I have a quick question to the `WearNavScaffold` o...
# compose-wear
y
I have a quick question to the
WearNavScaffold
of horologist. I used a
scalingLazyColumnComposable
to show a menu and default time text. Wenn I swipe back to the menu screen, the time text is gone. Is it desired behaviour? My navi graph code
๐Ÿ‘€ 1
j
So two things. Firstly that looks like a bug to me. @yschimke FYI. Secondly Wear UX guidance is to scroll away the time text when you scroll up the screen - horologist supports this so worth looking at whether you want to configure that into your app.
y
WearNavScaffold should do that for you. I'll look into the bug. But the samples do exactly what you are both asking for.
Nothing obvious from the code. Are the WearNavScaffold classes exactly the same? I noticed you copied them into you project instead of using as a library.
y
@yschimke thanks for your feedback. the WearNavScaffold class is the same imported from the horologist v0.0.24. I have followed the Nav example (https://github.com/google/horologist/blob/main/sample/src/main/java/com/google/android/horologist/navsample/NavWearApp.kt) and left out the time text, snackbar and state slots to use the defaults. And the focusRequester for the NavMenuScreen, i used a default one instead of getting it from a viewModel. I see also the navExample functions as expected. Maybe the focusRequester is causing the problem, but I thought it is fine to hoist state in composable instead of hoisting focusrequester state in viewModel? I try to make the navExample as simple as possible for me to get a gist of it. And tried to use as much default param from WearNavScaffold of horologist. I might do something wrong.
y
Thanks for flagging this, it seems like a regression after the wear compose 1.0.0-rc01 update. Can reproduce in the sample in Horologist, but not on 1.0.0-beta03.
๐Ÿ™Œ 1
I may not get a fix out today, so if it's important then try with beta03, https://github.com/google/horologist/issues/243
y
Thanks. No problem. I will back down to beta03. Indeed, i used wear compose 1.0.0-rc01 and didnโ€™t thought that might be the route cause.
y
It would be great if you can confirm that.
And also any feedback on the WearNavScaffold, very welcome (good or bad). It's the best time to change the API if it isn't quite right.
y
This is interesting. I just test the difference between wear compose rc01 and beta03. With either following combination, a default time text is shown and will disappear.
Copy code
compose_compiler_version = '1.2.0-rc01'
wear_compose_version = '1.0.0-beta03'

or

compose_compiler_version = '1.2.0-beta03'
wear_compose_version = '1.0.0-rc01'
With beta03
Copy code
compose_compiler_version = '1.2.0-beta03'
wear_compose_version = '1.0.0-beta03'
the default time text doesnโ€™t shown on the
scalingLazyColumnComposable
, I will probably need to customize the time text slot.
y
I'm treating it as a bug, so hopefully I get a fix in and it does the right thing by just upgrading the horologist version. At the moment, I'm mainly focusing on why it's not showing with wear-compose rc01, and compose rc01.
y
Regarding the WearNavScaffold API, I think the structure is great. we use a default menu to launch all the routes and it can be defined in the NavGraphBuilder, which is quite intuitive. I am just confused by the different
states need to remember
, there are the swipeDismissState and the navState, and also the ScalingLazyListState for the
scalingLazyColumnComposable
. The learning curve for states are quite high at the beginning. Maybe we need
some more doc
and probably a codelab to explain die effect of states and how to customise the states with WearNavScaffold API. I will also welcome some more docs to know what the
snackbar slot
does ๐Ÿ™‚ I havenโ€™t figure it out yet. And I would also like to know what the focusRequest is generally used for. I am very new to compose in general. I really like compose and wear compose, for my limited knowledge and working with horologist, I am able to refactor one view activity and reduce the code from 1000+ lines to 180 lines.
y
Regarding snackbar, there is a demo in Horologist.
Basically you probably want to avoid Toast.
But unlike mobile, Wear Compose doesn't have a Snackbar implementation built in.
It's also important that you can control how it shows up, maybe just as a temporary Chip (a styleable toast), or a dialog with some transparency. And from where.
The snackbar model separates out the thing producing the error/warning/notice (maybe in a viewmodel?), from the thing displaying it, in this case the top level of the app, coordinating the display so you don't have multiple at once.
There are docs for the mobile snackbar, it's sort of assumed you are familiar with those first.
But docs would help here.
y
Thanks. I am just wondering why the snackbar slot is in WearNavScaffold? Is that i can override it for all the route to use horologist snackbar? I will dig more deeper into the snackbar example.
y
I believe basically you should only have one place in a Single Activity Architecture app that is showing these. Not per screen.
If I'm wrong about that then the design should change.
y
I see. I think you are right. In the view system, snackbar is also attached to a root view. I got it now ๐Ÿ™‚
y
Thanks, that's reassuring.
The way you display these is still up to you, we don't have UX guidance, but the sample shows a dialog, you can start with.
๐Ÿ™Œ 1
On the various states, you shouldn't have to remember all of these. They should have sensible defaults that do the right thing.
The reason the sample has them all, is because the swipe to dismiss state is needed for the PagerScreen. If this is common, we could probably have a wearPagerScreen() that hides this also.
๐Ÿ‘ 1
@Yingding Wang Could you try this fix to Modifier.fadeAwayScalingLazyList?
Copy code
@ExperimentalHorologistComposeLayoutApi
public fun Modifier.fadeAwayScalingLazyList(
    initialIndex: Int = 1,
    initialOffset: Int = 0,
    scrollStateFn: () -> ScalingLazyListState,
): Modifier =
    composed {
        val scrollState = remember { scrollStateFn() }

        val isInitial by derivedStateOf { scrollState.centerItemIndex == initialIndex }
        val centerItemScrollOffset by derivedStateOf { scrollState.centerItemScrollOffset }

        if (isInitial && centerItemScrollOffset > initialOffset) {
            val y = centerItemScrollOffset / LocalDensity.current.density
y
@yschimke Do you mean i shall override the horologist Modifier extension function?
Copy code
@ExperimentalHorologistComposeLayoutApi
fun Modifier.fadeAwayScalingLazyList(
    initialIndex: Int = 1,
    initialOffset: Int = 0,
    scrollStateFn: () -> ScalingLazyListState,
): Modifier =
    composed {
        val scrollState = remember { scrollStateFn() }

        val isInitial by derivedStateOf { scrollState.centerItemIndex == initialIndex }
        val centerItemScrollOffset by derivedStateOf { scrollState.centerItemScrollOffset }

        if (isInitial && centerItemScrollOffset > initialOffset) {
            val y = centerItemScrollOffset / LocalDensity.current.density
            fadeEffect(y, fade = true)
        } else if (scrollState.centerItemIndex > initialIndex) {
            alpha(0.0f)
        } else {
            this
        }
    }
I canโ€™t compile since
fadeEffect: it is private in file
y
I wasn't sure how much you copied into your project. In that case I'll put a PR up and try to do a release today.
y
๐Ÿ™‚ Let me see if i can try this out in the horologist source code, give 20 minutes. And I will let you know if the patch works.
y
I've tried the patch there already,.
So this is more whether it fixes it in your app.
y
I can add my app there too ๐Ÿ™‚ so that i can import the horologist source code instead of using the maven lib.
If you want to have some more certainty, but i am sure it should work, if you say so ๐Ÿ™‚
y
Up to you. Thanks for flagging this.
y
@yschimke quick question to the horologist repo structure, I compiled my app there, but it is still beta03. Where can i change the libs.wearcompose dependency version to rc01?
y
gradle/libs.versions.toml
But it's already updated
Copy code
wearcompose = "1.0.0-rc01"
y
I pull it quite a while ago, it was still
1.0.0-beta03
on my end ๐Ÿ™‚
It is kind of strange. You can see from 10s to the end, as i started app. the time text is shown and then it is gone as the menu appears. Wenn i swipe back and it is there for a sec and disappears again.
I used this patch:
Copy code
@ExperimentalHorologistComposeLayoutApi
fun Modifier.fadeAwayScalingLazyList(
    initialIndex: Int = 1,
    initialOffset: Int = 0,
    scrollStateFn: () -> ScalingLazyListState,
): Modifier =
    composed {
        val scrollState = remember { scrollStateFn() }

        val isInitial by derivedStateOf { scrollState.centerItemIndex == initialIndex }
        val centerItemScrollOffset by derivedStateOf { scrollState.centerItemScrollOffset }

        if (isInitial && centerItemScrollOffset > initialOffset) {
            val y = centerItemScrollOffset / LocalDensity.current.density
            fadeEffect(y, fade = true)
        } else if (scrollState.centerItemIndex > initialIndex) {
            alpha(0.0f)
        } else {
            this
        }
    }
y
Can you share a branch of that? I'm happy to dig in.
y
Sure, here is my branch https://github.com/yingding/horologist/tree/timetext/, I modified patch in
layout/fadeAway.kt
and added my example to the
sample/simplenav
folder, you can start my app with a config using specific activity of SimpleNavActivity
๐Ÿ‘๐Ÿป 1
I will be away for 2 hours, should something not working or I do did something wrong in patch please let me know. Will respond in 2 hours.
๐Ÿ‘๐Ÿป 1
y
Thanks for the branch, I've worked out why it's happening on the menu screen. I'm not sure of a clean fix. It's sort of a limitation around how the time text scrolling works.
The mechnical problem here is that time text needs a starting position. From that it measures relative to that in terms of the center item and offset. In your code you initial state is index = 0
Copy code
scrollStateBuilder = { ScalingLazyListState(initialCenterItemIndex = 0) }
But that isn't possible because of your auto centering params.
Copy code
autoCentering = AutoCenteringParams(itemIndex = 1, itemOffset = 30),
If you change it to
Copy code
AutoCenteringParams(itemIndex = 0)
It shows up
I'll raise a bug, because it confusing and I don't think it's handling all the logic correctly. I'm just not sure if I can fix it cleanly.
y
I see, thanks for the feedback.
y
I'll say the same, this is useful feedback for em.
103 Views