ViewStateStore

Additional

Language
Kotlin
Version
1.3-alpha-1 (May 22, 2019)
Created
Feb 20, 2019
Updated
May 22, 2019
Owner
Davide Giuseppe Farella (4face-studi0)
Contributor
Davide Giuseppe Farella (4face-studi0)
1
Activity
Badge
Generate
Download
Source code

Show card

This library is created on an idea of Fabio Collini ( https://proandroiddev.com/unidirectional-data-flow-using-coroutines-f5a792bf34e5 ).

ViewStateStore

ViewStateStore wraps a LiveData for deliver ViewStates to the UI.

Supported ViewState types are;

  • Success holds the real data
  • Error holds and error ( which could be a custom class ) with its Throwable and an optiona customMessageRes.
  • Loading
  • None ( default initial value )

Installation

ViewStateStore

implementation( "studio.forface.viewstatestore:viewstatestore:last_version" )

Paging extension

implementation( "studio.forface.viewstatestore:viewstatestore-paging:last_version" )

Minimal usage

class CarsViewModel( val getCars: GetCars ): ViewModel() {
    val cars = ViewStateStore<List<Car>>()

    init {
        cars.setLoading()
        viewModelScope.launch {
            runCatching { withContext( IO ) { getCars() } }
                .onSuccess( cars::setData )
                .onFailure { cars.setError( it ) }
        }
    }
}

class CarsFragment: Fragment(), ViewStateFragment {
    override fun onActivityCreated( savedInstanceState: Bundle? ) {
        carsViewModel.cars.observe {
            doOnLoading { isLoading -> progressBar.isVisible = isLoading }
            doOnError( ::showError )
            doOnData( ::updateCars )
        }
    }
}

Or you can set an ErrorResolution

// CarsViewModel
    init {
        loadCars()
    }

    private fun loadCars() {
        cars.setLoading()
        viewModelScope.launch {
            runCatching { withContext( IO ) { getCars() } }
                .onSuccess( cars::setData )
                .onFailure { cars.setError( it, ::loadCars ) }
        }
    }
}

// CarsFragment
    override fun onActivityCreated( savedInstanceState: Bundle? ) {
        carsViewModel.cars.observe {
            ...
            doOnError( ::showError )
        }
    }

    fun showError( error: ViewState.Error ) {
        Snackbar.make(
            coordinatorLayout,
            error.getMessage( requireContext() ),
            Snackbar.LENGTH_SHORT
        ).apply {
            if ( error.hasResolution() )
                setAction( "Retry" ) { error.resolve() } }
            show()
        }
    }
}

It's also possible to lock the ViewStateStore for make it be mutable only from a ViewStateStoreScope

class CarsViewModel( val getCars: GetCars ): ViewModel(), ViewStateStoreScope {
    val cars = ViewStateStore<List<Car>>().lock // Locking the ViewStateStore
}

class CarsFragment: Fragment(), ViewStateFragment {
    override fun onActivityCreated( savedInstanceState: Bundle? ) {
        carsViewModel.cars.postLoading() // Does NOT compile, LockedViewStateStore.postLoading not resolved
    }
}

From external source

A ViewStateStore can also be created from a LiveData or a DataSource.Factory ( see paging artifact for last one ).

val carsLiveData: LiveData<Car> = roomDatabase.getCars()
val cars = ViewStateStore.from( carsLiveData )
val carsDataSource: DataSource.Factory<Int, Car> = roomDatabase.getCars()
val cars = ViewStateStore.from( carsDataSource )

Wiki

Full Wiki here

ViewStateStore Doc here

Paging Doc here