Skip to content

Instantly share code, notes, and snippets.

@dleonett
Last active October 22, 2020 22:38
Show Gist options
  • Save dleonett/de93a014af777963bcf64e4aac8c0340 to your computer and use it in GitHub Desktop.
Save dleonett/de93a014af777963bcf64e4aac8c0340 to your computer and use it in GitHub Desktop.
Single View State LiveData example
package com.leonett.photofeed.ui.feature.account
import android.content.Context
import android.content.Intent
import android.view.View
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.leonett.photofeed.App
import com.leonett.photofeed.R
import com.leonett.photofeed.ui.base.BaseFragment
import com.leonett.photofeed.ui.feature.login.LoginActivity
import kotlinx.android.synthetic.main.fragment_account.*
import javax.inject.Inject
class AccountFragment : BaseFragment() {
@Inject
lateinit var accountViewModelFactory: AccountViewModelFactory
private lateinit var accountViewModel: AccountViewModel
override val layoutId: Int
get() = R.layout.fragment_account
override fun onAttach(context: Context) {
super.onAttach(context)
(requireContext().applicationContext as App).appComponent.accountComponent().create()
.inject(this)
}
override fun initVars() {
accountViewModel = ViewModelProvider(this, accountViewModelFactory)
.get(AccountViewModel::class.java)
}
override fun initViews(view: View) {
btnOpenAbout.setOnClickListener { navigateToAbout() }
btnSignOut.setOnClickListener { logoutUser() }
}
override fun observeViewModels() {
observeSingleStateLiveData()
observeMultipleLiveData()
}
private fun observeSingleStateLiveData() {
// Screen state
accountViewModel.screenStateLiveData.observe(viewLifecycleOwner, Observer {
when (it) {
// Loading state
is AccountScreenState.Loading -> {
showProgressDialog("Loading...")
}
// Success state
is AccountScreenState.Success -> {
hideProgressDialog()
Glide.with(requireContext())
.load(it.userInfo.avatarUrl)
.apply(RequestOptions().circleCrop())
.apply(RequestOptions().placeholder(R.drawable.placeholder_image_circle))
.into(imgAvatar)
txtName.text = it.userInfo.name
txtCity.text = it.userInfo.city
btnFriends.text = String.format("Friends (%d)", it.friendsInfo.count)
btnFriends.visibility = View.VISIBLE
btnPhotos.text = String.format("Photos (%d)", it.photosInfo.count)
btnPhotos.visibility = View.VISIBLE
}
// Error state
is AccountScreenState.Error -> {
hideProgressDialog()
showPersistentSnackbar(txtName, it.message, "Dismiss") {
// Just dismiss snack bar
}
}
}
})
}
private fun observeMultipleLiveData() {
// Loader
accountViewModel.loaderLiveData.observe(viewLifecycleOwner, Observer {
if (it) {
showProgressDialog("Loading...")
} else {
hideProgressDialog()
}
})
// User info
accountViewModel.userInfoLiveData.observe(viewLifecycleOwner, Observer {
Glide.with(requireContext())
.load(it.avatarUrl)
.apply(RequestOptions().circleCrop())
.apply(RequestOptions().placeholder(R.drawable.placeholder_image_circle))
.into(imgAvatar)
txtName.text = it.name
txtCity.text = it.city
})
// Friends info
accountViewModel.friendsInfoLiveData.observe(viewLifecycleOwner, Observer {
btnFriends.text = String.format("Friends (%d)", it.count)
btnFriends.visibility = View.VISIBLE
})
// Photos info
accountViewModel.photosInfoLiveData.observe(viewLifecycleOwner, Observer {
btnPhotos.text = String.format("Photos (%d)", it.count)
btnPhotos.visibility = View.VISIBLE
})
// Error banner
accountViewModel.errorLiveData.observe(viewLifecycleOwner, Observer {
showPersistentSnackbar(txtName, it, "Dismiss") {
// Just dismiss snack bar
}
})
}
private fun navigateToAbout() {
findNavController().navigate(R.id.actionAbout)
}
private fun logoutUser() {
accountViewModel.logoutUser()
navigateToLogin()
}
private fun navigateToLogin() {
val intent = Intent(requireActivity(), LoginActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
}
}
package com.leonett.photofeed.ui.feature.account
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.leonett.photofeed.data.UserRepository
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
class AccountViewModel @Inject constructor(private val userRepository: UserRepository) :
ViewModel() {
private var _userInfoLiveData: MutableLiveData<UserInfo> = MutableLiveData()
val userInfoLiveData: LiveData<UserInfo>
get() = _userInfoLiveData
private var _friendsInfoLiveData: MutableLiveData<FriendsInfo> = MutableLiveData()
val friendsInfoLiveData: LiveData<FriendsInfo>
get() = _friendsInfoLiveData
private var _photosInfoLiveData: MutableLiveData<PhotosInfo> = MutableLiveData()
val photosInfoLiveData: LiveData<PhotosInfo>
get() = _photosInfoLiveData
private var _errorLiveData: MutableLiveData<String> = MutableLiveData()
val errorLiveData: LiveData<String>
get() = _errorLiveData
private var _loaderLiveData: MutableLiveData<Boolean> = MutableLiveData()
val loaderLiveData: LiveData<Boolean>
get() = _loaderLiveData
private var _screenStateLiveData: MutableLiveData<AccountScreenState> = MutableLiveData()
val screenStateLiveData: LiveData<AccountScreenState>
get() = _screenStateLiveData
init {
viewModelScope.launch {
//successMultipleLiveData()
//errorMultipleLiveData()
successSingleViewState()
//errorSingleViewState()
}
}
private suspend fun successSingleViewState() {
_screenStateLiveData.value = AccountScreenState.Loading
delay(2000)
_screenStateLiveData.value = AccountScreenState.Success(
UserInfo(
"John Smith",
"New York",
"https://cactusthemes.com/blog/wp-content/uploads/2018/01/tt_avatar_small.jpg"
),
FriendsInfo(200),
PhotosInfo(90)
)
}
private suspend fun errorSingleViewState() {
_screenStateLiveData.value = AccountScreenState.Loading
delay(2000)
_screenStateLiveData.value = AccountScreenState.Error("User does not exist")
}
private suspend fun successMultipleLiveData() {
_loaderLiveData.value = true
delay(2000)
_loaderLiveData.value = false
_userInfoLiveData.value =
UserInfo(
"John Smith",
"New York",
"https://cactusthemes.com/blog/wp-content/uploads/2018/01/tt_avatar_small.jpg"
)
_friendsInfoLiveData.value = FriendsInfo(200)
_photosInfoLiveData.value = PhotosInfo(90)
}
private suspend fun errorMultipleLiveData() {
_loaderLiveData.value = true
delay(2000)
_loaderLiveData.value = false
_errorLiveData.value = "User does not exist"
}
fun logoutUser() {
userRepository.clearLocalUser()
}
}
data class UserInfo(val name: String, val city: String, val avatarUrl: String)
data class PhotosInfo(val count: Int)
data class FriendsInfo(val count: Int)
sealed class AccountScreenState {
object Loading : AccountScreenState()
data class Success(
val userInfo: UserInfo,
val friendsInfo: FriendsInfo,
val photosInfo: PhotosInfo
) : AccountScreenState()
data class Error(val message: String) : AccountScreenState()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment