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