Skip to content

Instantly share code, notes, and snippets.

@peterpazmandi
Last active July 14, 2020 14:23
Show Gist options
  • Save peterpazmandi/b28e53b702e9bb83978d5e84b0d125a6 to your computer and use it in GitHub Desktop.
Save peterpazmandi/b28e53b702e9bb83978d5e84b0d125a6 to your computer and use it in GitHub Desktop.
fun observeSet(id: String) = resultLiveData(
databaseQuery = { dao.getLegoSet(id) },
networkCall = { legoSetRemoteDataSource.fetchSet(id) },
saveCallResult = { dao.insert(it) })
/**
* Creates a new [LiveData] object does not emit a value until the source `this` LiveData value
* has been changed. The value is considered changed if `equals()` yields `false`.
*/
.distinctUntilChanged()
data class Result<out T>(val status: Status, val data: T?, val message: String?)
{
enum class Status
{
SUCCESS,
ERROR,
LOADING
}
companion object
{
fun <T> success(data: T): Result<T>
{
return Result(Status.SUCCESS, data, null)
}
fun <T> error(message: String, data: T? = null): Result<T>
{
return Result(Status.ERROR, data, message)
}
fun <T> loading(data: T? = null): Result<T>
{
return Result(Status.LOADING, data, null)
}
}
}
import androidx.lifecycle.ViewModel
import com.elifox.legocatalog.legoset.data.LegoSetRepository
import javax.inject.Inject
/**
* The ViewModel used in [SetFragment].
*/
class LegoSetViewModel @Inject constructor(repository: LegoSetRepository) : ViewModel()
{
lateinit var id: String
val legoSet by lazy { repository.observeSet(id) }
}
import androidx.lifecycle.LiveData
import androidx.lifecycle.liveData
import androidx.lifecycle.map
import com.elifox.legocatalog.data.Result.Status.ERROR
import com.elifox.legocatalog.data.Result.Status.SUCCESS
import kotlinx.coroutines.Dispatchers
/**
* The database serves as the single source of truth.
* Therefore UI can receive data updates from database only.
* Function notify UI about:
* [Result.Status.SUCCESS] - with data from database
* [Result.Status.ERROR] - if error has occurred from any source
* [Result.Status.LOADING]
*/
fun <T, A> resultLiveData(databaseQuery: () -> LiveData<T>,
networkCall: suspend () -> Result<A>,
saveCallResult: suspend (A) -> Unit): LiveData<Result<T>> =
liveData(Dispatchers.IO) {
emit(Result.loading<T>())
val source = databaseQuery.invoke().map { Result.success(it) }
emitSource(source)
val responseStatus = networkCall.invoke()
if (responseStatus.status == SUCCESS)
{
saveCallResult(responseStatus.data!!)
}
else if (responseStatus.status == ERROR)
{
emit(Result.error<T>(responseStatus.message!!))
emitSource(source)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment