lista de seguidores y seguidos
This commit is contained in:
parent
36c25a37d6
commit
75b93da044
@ -1,6 +1,42 @@
|
||||
package com.isolaatti.common
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
enum class ListUpdateEvent {
|
||||
ItemUpdated,
|
||||
ItemsAdded
|
||||
ItemsAdded,
|
||||
Refresh
|
||||
}
|
||||
|
||||
/**
|
||||
* @param listUpdateEvent indicate what type of update was made to the list
|
||||
* @param items list of positions. For ItemUpdated these positions indicate the changed positions.
|
||||
* For ItemsAdded indicate the range where the item was inserted, first element the beginning, second element the end.
|
||||
* If list contains only one element, only that position will be inserted
|
||||
*/
|
||||
class UpdateEvent(private val listUpdateEvent: ListUpdateEvent, private val items: Array<Int>) {
|
||||
fun notify(adapter: RecyclerView.Adapter<*>) {
|
||||
when(listUpdateEvent) {
|
||||
ListUpdateEvent.ItemUpdated -> {
|
||||
items.forEach { position ->
|
||||
adapter.notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
ListUpdateEvent.ItemsAdded -> {
|
||||
if(items.isEmpty()) {
|
||||
return
|
||||
}
|
||||
if(items.count() == 1) {
|
||||
adapter.notifyItemInserted(items[0])
|
||||
} else {
|
||||
adapter.notifyItemRangeInserted(items[0], items[1])
|
||||
}
|
||||
}
|
||||
|
||||
ListUpdateEvent.Refresh -> {
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,8 @@ import android.view.ViewGroup
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.Adapter
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import coil.load
|
||||
import com.isolaatti.R
|
||||
@ -13,18 +15,30 @@ import com.isolaatti.databinding.ItemUserListBinding
|
||||
import com.isolaatti.profile.domain.entity.ProfileListItem
|
||||
import com.isolaatti.utils.UrlGen
|
||||
|
||||
class UserListRecyclerViewAdapter(private val callback: UserItemCallback) : ListAdapter<ProfileListItem, UserListRecyclerViewAdapter.UserListViewHolder>(diffCallback) {
|
||||
class UserListRecyclerViewAdapter(private val callback: UserItemCallback) : Adapter<UserListRecyclerViewAdapter.UserListViewHolder>() {
|
||||
|
||||
private var data: List<ProfileListItem> = listOf()
|
||||
|
||||
inner class UserListViewHolder(val item: ItemUserListBinding) : ViewHolder(item.root)
|
||||
|
||||
fun updateData(newData: List<ProfileListItem>, updateEvent: UpdateEvent) {
|
||||
data = newData
|
||||
updateEvent.notify(this)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserListViewHolder {
|
||||
return UserListViewHolder(ItemUserListBinding.inflate(LayoutInflater.from(parent.context)))
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return data.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: UserListViewHolder, position: Int) {
|
||||
val context = holder.itemView.context
|
||||
holder.itemView.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
getItem(position).let { user ->
|
||||
holder.item.followButton.isEnabled = true
|
||||
data[position].let { user ->
|
||||
holder.item.root.setOnClickListener {
|
||||
callback.itemClick(user.id)
|
||||
}
|
||||
@ -34,34 +48,17 @@ class UserListRecyclerViewAdapter(private val callback: UserItemCallback) : List
|
||||
holder.item.followButton.text = context.getText(R.string.unfollow)
|
||||
holder.item.followButton.setTextColor(ResourcesCompat.getColor(context.resources, R.color.danger, null))
|
||||
holder.item.followButton.setOnClickListener {
|
||||
it.isEnabled = false
|
||||
callback.followButtonClick(user, UserItemCallback.FollowButtonAction.Unfollow)
|
||||
}
|
||||
} else {
|
||||
holder.item.followButton.text = context.getText(R.string.follow)
|
||||
holder.item.followButton.setTextColor(ResourcesCompat.getColor(context.resources, R.color.purple_lighter, null))
|
||||
holder.item.followButton.setOnClickListener {
|
||||
it.isEnabled = false
|
||||
callback.followButtonClick(user, UserItemCallback.FollowButtonAction.Follow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val diffCallback: DiffUtil.ItemCallback<ProfileListItem> = object: DiffUtil.ItemCallback<ProfileListItem>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: ProfileListItem,
|
||||
newItem: ProfileListItem
|
||||
): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: ProfileListItem,
|
||||
newItem: ProfileListItem
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,6 +4,8 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.isolaatti.common.ListUpdateEvent
|
||||
import com.isolaatti.common.UpdateEvent
|
||||
import com.isolaatti.followers.domain.FollowersRepository
|
||||
import com.isolaatti.profile.domain.entity.ProfileListItem
|
||||
import com.isolaatti.utils.Resource
|
||||
@ -19,15 +21,15 @@ import javax.inject.Inject
|
||||
class FollowersViewModel @Inject constructor(private val followersRepository: FollowersRepository) : ViewModel() {
|
||||
var userId: Int = 0
|
||||
|
||||
private val followersList: MutableList<ProfileListItem> = mutableListOf()
|
||||
private val followingsList: MutableList<ProfileListItem> = mutableListOf()
|
||||
private var followersList: List<ProfileListItem> = listOf()
|
||||
private var followingsList: List<ProfileListItem> = listOf()
|
||||
|
||||
|
||||
private val _followers: MutableLiveData<List<ProfileListItem>> = MutableLiveData()
|
||||
private val _followings: MutableLiveData<List<ProfileListItem>> = MutableLiveData()
|
||||
private val _followers: MutableLiveData<Pair<List<ProfileListItem>, UpdateEvent>> = MutableLiveData()
|
||||
private val _followings: MutableLiveData<Pair<List<ProfileListItem>, UpdateEvent>> = MutableLiveData()
|
||||
|
||||
val followers: LiveData<List<ProfileListItem>> get() = _followers
|
||||
val followings: LiveData<List<ProfileListItem>> get() = _followings
|
||||
val followers: LiveData<Pair<List<ProfileListItem>, UpdateEvent>> get() = _followers
|
||||
val followings: LiveData<Pair<List<ProfileListItem>, UpdateEvent>> get() = _followings
|
||||
|
||||
private val toRetry: MutableList<Runnable> = mutableListOf()
|
||||
|
||||
@ -59,20 +61,26 @@ class FollowersViewModel @Inject constructor(private val followersRepository: Fo
|
||||
return followingsList.last().id
|
||||
}
|
||||
|
||||
fun fetchFollowers() {
|
||||
fun fetchFollowers(refresh: Boolean = false) {
|
||||
if(userId <= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if(refresh) {
|
||||
followersList = mutableListOf()
|
||||
}
|
||||
|
||||
val updateListEvent = if(refresh) ListUpdateEvent.Refresh else ListUpdateEvent.ItemsAdded
|
||||
|
||||
viewModelScope.launch {
|
||||
followersRepository.getFollowersOfUser(userId, getFollowersLastId()).onEach {
|
||||
when(it) {
|
||||
is Resource.Success -> {
|
||||
if(it.data != null) {
|
||||
followersList.addAll(it.data)
|
||||
val prevCount = followersList.count()
|
||||
followersList += it.data
|
||||
_followers.postValue(Pair(followersList, UpdateEvent(updateListEvent, arrayOf(prevCount))))
|
||||
}
|
||||
|
||||
_followers.postValue(followersList)
|
||||
}
|
||||
is Resource.Error -> {
|
||||
toRetry.add {
|
||||
@ -85,11 +93,17 @@ class FollowersViewModel @Inject constructor(private val followersRepository: Fo
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchFollowings() {
|
||||
fun fetchFollowings(refresh: Boolean = false) {
|
||||
if(userId <= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if(refresh) {
|
||||
followingsList = mutableListOf()
|
||||
}
|
||||
|
||||
val updateListEvent = if(refresh) ListUpdateEvent.Refresh else ListUpdateEvent.ItemsAdded
|
||||
|
||||
viewModelScope.launch {
|
||||
followersRepository.getFollowingsOfUser(userId, getFollowingsLastId()).onEach {
|
||||
when(it) {
|
||||
@ -101,8 +115,9 @@ class FollowersViewModel @Inject constructor(private val followersRepository: Fo
|
||||
is Resource.Loading -> {}
|
||||
is Resource.Success -> {
|
||||
if(it.data != null) {
|
||||
followingsList.addAll(it.data)
|
||||
_followings.postValue(followingsList)
|
||||
val prevCount = followersList.count()
|
||||
followingsList += it.data
|
||||
_followings.postValue(Pair(followingsList, UpdateEvent(updateListEvent, arrayOf(prevCount))))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,15 +130,19 @@ class FollowersViewModel @Inject constructor(private val followersRepository: Fo
|
||||
val followingsIndex = followingsList.indexOf(user)
|
||||
|
||||
if(followersIndex >= 0) {
|
||||
followersList[followersIndex] = user
|
||||
followersList = followersList.toMutableList().apply {
|
||||
set(followersIndex, user)
|
||||
}
|
||||
|
||||
_followers.postValue(followersList)
|
||||
_followers.postValue(Pair(followersList, UpdateEvent(ListUpdateEvent.ItemUpdated, arrayOf(followersIndex))))
|
||||
}
|
||||
|
||||
if(followingsIndex >= 0) {
|
||||
followingsList[followingsIndex] = user
|
||||
followingsList = followingsList.toMutableList().apply {
|
||||
set(followingsIndex, user)
|
||||
}
|
||||
|
||||
_followings.postValue(followingsList)
|
||||
_followings.postValue(Pair(followingsList, UpdateEvent(ListUpdateEvent.ItemUpdated, arrayOf(followingsIndex))))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.isolaatti.followers.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -12,6 +13,7 @@ import com.isolaatti.common.UserListRecyclerViewAdapter
|
||||
import com.isolaatti.databinding.FragmentFollowersBinding
|
||||
import com.isolaatti.followers.presentation.FollowersViewModel
|
||||
import com.isolaatti.profile.domain.entity.ProfileListItem
|
||||
import com.isolaatti.profile.ui.ProfileActivity
|
||||
|
||||
class FollowersFragment : Fragment(), UserItemCallback {
|
||||
private lateinit var binding: FragmentFollowersBinding
|
||||
@ -28,8 +30,9 @@ class FollowersFragment : Fragment(), UserItemCallback {
|
||||
}
|
||||
|
||||
private fun setObservers() {
|
||||
viewModel.followers.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
viewModel.followers.observe(viewLifecycleOwner) { (list, updateEvent) ->
|
||||
adapter.updateData(list, updateEvent)
|
||||
binding.swipeToRefresh.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +40,10 @@ class FollowersFragment : Fragment(), UserItemCallback {
|
||||
adapter = UserListRecyclerViewAdapter(this)
|
||||
binding.recyclerUsers.adapter = adapter
|
||||
binding.recyclerUsers.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||
|
||||
binding.swipeToRefresh.setOnRefreshListener {
|
||||
viewModel.fetchFollowers(refresh = true)
|
||||
}
|
||||
}
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@ -48,7 +55,7 @@ class FollowersFragment : Fragment(), UserItemCallback {
|
||||
}
|
||||
|
||||
override fun itemClick(userId: Int) {
|
||||
|
||||
ProfileActivity.startActivity(requireContext(), userId)
|
||||
}
|
||||
|
||||
override fun followButtonClick(user: ProfileListItem, action: UserItemCallback.FollowButtonAction) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.isolaatti.followers.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -19,6 +20,8 @@ class FollowingFragment : Fragment(), UserItemCallback {
|
||||
private val viewModel: FollowersViewModel by viewModels({ requireParentFragment() })
|
||||
private lateinit var adapter: UserListRecyclerViewAdapter
|
||||
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@ -29,8 +32,9 @@ class FollowingFragment : Fragment(), UserItemCallback {
|
||||
}
|
||||
|
||||
private fun setObservers() {
|
||||
viewModel.followings.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
viewModel.followings.observe(viewLifecycleOwner) { (list, updateEvent) ->
|
||||
adapter.updateData(list, updateEvent)
|
||||
binding.swipeToRefresh.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +42,10 @@ class FollowingFragment : Fragment(), UserItemCallback {
|
||||
adapter = UserListRecyclerViewAdapter(this)
|
||||
binding.recyclerUsers.adapter = adapter
|
||||
binding.recyclerUsers.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||
|
||||
binding.swipeToRefresh.setOnRefreshListener {
|
||||
viewModel.fetchFollowings(refresh = true)
|
||||
}
|
||||
}
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
@ -26,9 +26,7 @@ class ProfileListItem(
|
||||
if (id != other.id) return false
|
||||
if (name != other.name) return false
|
||||
if (profileImageId != other.profileImageId) return false
|
||||
if (following != other.following) return false
|
||||
|
||||
return true
|
||||
return following == other.following
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user