ZupIT/beagle

Feature Request: action onPullRefresh for ListView

Closed this issue · 7 comments

In many cases, listview have different data after pull refresh action. But at the moment, list view doesn't support any action for pull refresh. Could you support this action in the next version ? Thank you

We don't have enough time to implement this for the next version (1.8), but it is an interesting request and we've discussed it a little bit today. We'll further discuss it next monday and we'll probably add this to our backlog, releasing it for 1.9.

In any case, the "onPullToRefresh" event will probably be attached to the ScreenComponent, and not the ListView.

It sounds great, big thanks for your support

Hello @minmon98 , we have created a custom component on Android that could help you.

Follow the steps below to implement it:

This implementation must use the native android SwipeRefreshComponent view. You must download the library below to import it.

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

Here follows the code for a native component that set the rules for your refresh component

import android.content.Context
import android.view.View
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout

class SwipeRefreshComponent(
    context: Context
) : SwipeRefreshLayout(context) {

    var refreshListener: RefreshListener? = null

    init {
        refreshListener()
    }

    fun setChildComponent(child: View) {
        this.addView(child)
    }

    fun refresh(isRefreshing: Boolean) {
        this.isRefreshing = isRefreshing
    }

    private fun refreshListener() {
        this.setOnRefreshListener {
            refreshListener?.onRefresh()
        }
    }

}

interface RefreshListener {
    fun onRefresh()
}

Defines our beagle component, in this case a SwipeRefreshWidget:

import android.view.View
import br.com.zup.beagle.android.action.Action
import br.com.zup.beagle.android.context.Bind
import br.com.zup.beagle.android.utils.handleEvent
import br.com.zup.beagle.android.utils.observeBindChanges
import br.com.zup.beagle.android.view.custom.BeagleFlexView
import br.com.zup.beagle.android.widget.RootView
import br.com.zup.beagle.android.widget.WidgetView
import br.com.zup.beagle.annotation.RegisterWidget
import br.com.zup.beagle.core.ServerDrivenComponent
import br.com.zup.beagle.sample.components.RefreshListener
import br.com.zup.beagle.sample.components.SwipeRefreshComponent

@RegisterWidget
class SwipeRefreshWidget(
    val child: ServerDrivenComponent,
    val refresh: Bind<Boolean>,
    val onPullRefresh: List<Action>
) : WidgetView() {
    override fun buildView(rootView: RootView): View {

        val beagleFlexView = BeagleFlexView(rootView)

        return SwipeRefreshComponent(rootView.getContext()).apply {

            beagleFlexView.addView(this@SwipeRefreshWidget.child, false)

            setChildComponent(beagleFlexView)

            refreshListener = object : RefreshListener {
                override fun onRefresh() {
                    this@SwipeRefreshWidget.handleEvent(
                        rootView = rootView,
                        origin = this@apply,
                        actions = onPullRefresh
                    )
                }
            }

            observeBindChanges(rootView = rootView, view = this, bind = this@SwipeRefreshWidget.refresh) { isRefreshing ->
                isRefreshing?.let { refresh(it) }
            }
        }
    }
}

Finally we can use the component:

data class Content(
    val refresh: Boolean,
    val contentList: Any
)

object ListViewScreenBuilder : ScreenBuilder {
    override fun build() = Screen(
        context = ContextData(
            id = "content",
            value = Content(
                refresh = false,
                contentList = listOf("0", "1", "2", "3", "4", "5",
                    "6", "7", "8", "9", "10",
                    "11", "12", "13", "14", "15",
                    "16", "17", "18", "19", "20")
            )
        ),
        navigationBar = NavigationBar(title = "List With SwipeRefresh"),
        child = SwipeRefreshWidget(
            child = buildListView(),
            refresh = expressionOf("@{content.refresh}"),
            onPullRefresh = listOf(
                SetContext(
                    contextId = "content",
                    value = Content(
                        refresh = false,
                        contentList = listOf("0 OUTSIDE", "1 OUTSIDE", "2 OUTSIDE", "3 OUTSIDE", "4 OUTSIDE", "5 OUTSIDE",
                            "6 OUTSIDE", "7 OUTSIDE", "8 OUTSIDE", "9 OUTSIDE", "10 OUTSIDE",
                            "11 OUTSIDE", "12 OUTSIDE", "13 OUTSIDE", "14 OUTSIDE", "15 OUTSIDE",
                            "16 OUTSIDE", "17 OUTSIDE", "18 OUTSIDE", "19 OUTSIDE", "20 OUTSIDE")
                    )
                )
            )
        )
    )

    private fun buildListView() = ListView(
        direction = ListDirection.VERTICAL,
        dataSource = expressionOf("@{content.contentList}"),
        template = Container(
            children = listOf(
                Text(text = "@{item}", alignment = TextAlignment.CENTER).applyStyle(
                    Style(
                        margin = EdgeValue(all = 5.unitReal())
                    )
                )
            )
        ).applyStyle(
            Style(
                size = Size(height = 100.unitReal())
            )
        )
    )
}

Here is the above sample in json:

   {
   "_beagleComponent_":"beagle:screenComponent",
   "navigationBar":{
      "title":"List With SwipeRefresh",
      "showBackButton":true
   },
   "child":{
      "_beagleComponent_":"custom:swipeRefreshWidget",
      "child":{
         "_beagleComponent_":"beagle:listView",
         "direction":"VERTICAL",
         "dataSource":"@{content.contentList}",
         "template":{
            "_beagleComponent_":"beagle:container",
            "children":[
               {
                  "_beagleComponent_":"beagle:text",
                  "text":"@{item}",
                  "alignment":"CENTER",
                  "style":{
                     "cornerRadius":{
                        
                     },
                     "size":{
                        
                     },
                     "margin":{
                        "all":{
                           "value":5,
                           "type":"REAL"
                        }
                     },
                     "flex":{
                        
                     }
                  }
               }
            ],
            "style":{
               "cornerRadius":{
                  
               },
               "size":{
                  "height":{
                     "value":100,
                     "type":"REAL"
                  }
               },
               "flex":{
                  
               }
            }
         },
         "iteratorName":"item",
         "isScrollIndicatorVisible":false
      },
      "refresh":"@{content.refresh}",
      "onPullRefresh":[
         {
            "_beagleAction_":"beagle:setContext",
            "contextId":"content",
            "value":{
               "refresh":false,
               "contentList":[
                  "0 OUTSIDE",
                  "1 OUTSIDE",
                  "2 OUTSIDE",
                  "3 OUTSIDE",
                  "4 OUTSIDE",
                  "5 OUTSIDE",
                  "6 OUTSIDE",
                  "7 OUTSIDE",
                  "8 OUTSIDE",
                  "9 OUTSIDE",
                  "10 OUTSIDE",
                  "11 OUTSIDE",
                  "12 OUTSIDE",
                  "13 OUTSIDE",
                  "14 OUTSIDE",
                  "15 OUTSIDE",
                  "16 OUTSIDE",
                  "17 OUTSIDE",
                  "18 OUTSIDE",
                  "19 OUTSIDE",
                  "20 OUTSIDE"
               ]
            }
         }
      ]
   },
   "context":{
      "id":"content",
      "value":{
         "refresh":false,
         "contentList":[
            "0",
            "1",
            "2",
            "3",
            "4",
            "5",
            "6",
            "7",
            "8",
            "9",
            "10",
            "11",
            "12",
            "13",
            "14",
            "15",
            "16",
            "17",
            "18",
            "19",
            "20"
         ]
      }
   }
}

Just to clarify, we are still probably going to implement the onPullToRefresh event. @luisoliveirazup answer tells you how you could implement this yourself in the current version (1.7).

@Tiagoperes @luisoliveirazup thank you all guys, I'm waiting for the next version now

the pull to refresh component will be in the next version we are expecting to launch it on Friday to follow up on this issue: #1626 I will close this as there is no more need to be open

@Tiagoperes @uziasferreirazup I have just checked this version. PullToRefresh and GridView with direction property are exactly what I'm waiting for. Thanks you a lot