ZupIT/beagle

ListView Fails to update when the context has been updated

bradleysmaskell opened this issue · 5 comments

Please provide all the information requested. Issues that do not follow this format are likely to stall.

Description

Android ListViews fail to rerender when the ContextData is updated either from a PullToRefresh or a button that updates the list views context.

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Create a PullToRefresh Component
  2. Create a ListView Component and add it as a child of the PullToRefresh Component
  3. Create a ContextData object which stores the list of model objects that populate the ListView's templates. Assign this context value initially with an empty list.
  4. On the ListView's onInit action call SendRequest to the list views model objects
  5. On SendRequest's onSuccess action set the list views context to the data retrieved.
  6. Repeat the same flow with PullToRefresh's onPull action or even with a Button's onPress action to fetch new model objects and set the Context.

Using this flow:

  • iOS: works as expected. Each time a pull to refresh event occurs, the list view is updated and a new render occurs client-side.
  • Android: does not work as expected. The console in Android studio logs the send request, and I can see the new data there to render but no new render occurs on the ListView

Expected Results

Android should update in parity with iOS.

Code example, screenshot, or link to a repository:

class WorldSegmentScreenBuilder(
    private val world: Int
) : ScreenBuilder {

    private val segmentContext = ContextData(
        id = "segments",
        value = listOf<Segment>()
    )

    private val pullToRefreshContext = ContextData(
        id = "isRefreshing",
        value = false
    )

    override fun build() = Screen(
        navigationBar = NavigationBar(
            title = "SEGMENTS",
            styleId = DesignSystem.NavigationBarStyle.darkNavigationBarStyle
        ),
        child = Container(
            children = listOf(
                headerImageView(),
                pullToRefreshView(view = segmentListView()),
                Button(
                    text = "Reset Context",
                    onPress = loadSegmentActions()
                )
            )
        ).setStyle {
            this.backgroundColor = DesignSystem.Color.darkerGray
        }
    )

    private fun headerImageView() = Image(
        path = ImagePath.Local.both(
            webUrl = Bind.constant("/segment_image.png"),
            mobileId = Bind.constant("segment_image")
        ),
        mode = ImageContentMode.FIT_XY
    ).setStyle {
        size = Size(
            width = UnitValue.percent(100),
            height = UnitValue.percent(30),
        )
    }

    private fun pullToRefreshView(view: ServerDrivenComponent) = PullToRefresh(
        context = pullToRefreshContext,
        onPull = loadSegmentActions(),
        isRefreshing = expressionOf("@{isRefreshing}"),
        color = DesignSystem.Color.lightGray,
        child = view
    )

    private fun segmentListView() = ListView(
        context = segmentContext,
        onInit = loadSegmentActions(),
        dataSource = expressionOf(expression = "@{segments}"),
        templates = listOf(
            SegmentRowTemplate().build()
        )
    )

    private fun loadSegmentActions(
        shuffled: Boolean = true
    ) = listOf<Action>(
        SetContext(
            contextId = "isRefreshing",
            value = true
        ),
        SendRequest(
            url = "<Your_URL>",
            onSuccess = listOf(
                SetContext(
                    contextId = "segments",
                    value = "@{onSuccess.data}"
                ),
                SetContext(
                    contextId = "isRefreshing",
                    value = false
                )
            ),
            onError = listOf(
                SetContext(
                    contextId = "isRefreshing",
                    value = false
                )
            )
        )
    )
}

Hello @bradleysmaskell, thanks for reporting the bug.

This seems to be a problem with the ListView not updating its size when inside a PullToRefresh. As a workaround, can you set the height of the listView to "100%" and see if it works?

Here's an example (JSON): https://playground.usebeagle.io/#/cloud/S3-40b0081f-cebf-49db-b905-af6e154a4e36/main.json?platform=android

In the example above, if I remove "height: 100%" from the ListView, I get the behavior you described. But by setting it I have it working on both Android and iOS.

I hope this workaround works for now. If not, please let me know. We'll fix the bug as soon as we can, but it might take a while, since our dedicated Android developer is currently on vacations.

In any case, if your team finds where the bug is, we'd be happy to accept a Pull Request.

Hey thanks @Tiagoperes! After applying your suggestion I'm still not seeing the ListViews data get updated when pulling to refresh.

How the list view is defined:

    private fun segmentListView() = ListView(
        context = segmentContext,
        onInit = loadSegmentActions(),
        dataSource = expressionOf(expression = "@{segments}"),
        templates = listOf(
            SegmentRowTemplate().build()
        )
    ).setStyle {
        backgroundColor = DesignSystem.Color.white
        size = Size(
            height = UnitValue.percent(100) // setting the height to 100% per your suggestion
        )
    }

How pull to refresh is defined:

    private fun pullToRefreshView(listView: ListView) = PullToRefresh(
        context = pullToRefreshContext,
        onPull = loadSegmentActions(),
        isRefreshing = expressionOf("@{isRefreshing}"),
        color = DesignSystem.Color.zwiftLightGray,
        child = listView
    )

When pulling to refresh I can see the SendRequest go through in the logs with the data shuffled to observe the change but the list view isn't re-rendered on Android like it is on iOS.

Hello @bradleysmaskell, please check the fix for this bug on https://github.com/ZupIT/beagle-android/releases/tag/2.0.5
Feel free to reopen an issue if this does not work for your scenario.

@hernandazevedozup @Tiagoperes I'd love to test this out but it appears the release isn't available via Gradle.

Failed to resolve: br.com.zup.beagle:android:2.0.5
Show in Project Structure dialog
Affected Modules: app

Hi @bradleysmaskell. Thank you for the help.

please try again, it seems available now on this link

https://repo1.maven.org/maven2/br/com/zup/beagle/android/2.0.5/