se agrega pantalla "browse profiles" y se realiza refactorización

This commit is contained in:
erik-everardo 2024-04-28 01:09:50 -06:00
parent 50a70c6207
commit ab76e3827a
11 changed files with 131 additions and 21 deletions

View File

@ -1,6 +1,7 @@
package com.isolaatti.profile.domain.entity
import com.isolaatti.profile.data.remote.ProfileListItemDto
import com.isolaatti.search.data.ProfileSearchDto
class ProfileListItem(
val id: Int,
@ -15,6 +16,10 @@ class ProfileListItem(
fun fromDto(dto: ProfileListItemDto) = ProfileListItem(
dto.id,dto.name, dto.profileImageId, dto.following
)
fun fromDto(dto: ProfileSearchDto) = ProfileListItem(
dto.id, dto.name, dto.imageId, dto.following
)
}
override fun equals(other: Any?): Boolean {

View File

@ -9,6 +9,7 @@ import com.isolaatti.common.UpdateEvent
import com.isolaatti.followers.domain.FollowersRepository
import com.isolaatti.posting.posts.domain.PostsRepository
import com.isolaatti.profile.domain.entity.ProfileListItem
import com.isolaatti.search.domain.SearchRepository
import com.isolaatti.utils.Resource
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
@ -21,7 +22,8 @@ import javax.inject.Inject
@HiltViewModel
class ProfileListingViewModel @Inject constructor(
private val followersRepository: FollowersRepository,
private val postsRepository: PostsRepository
private val postsRepository: PostsRepository,
private val searchRepository: SearchRepository
): ViewModel() {
// one of these values must be set from fragment, depending on what action will be performed
var userId: Int = 0 // for followers and followings
@ -145,7 +147,7 @@ class ProfileListingViewModel @Inject constructor(
when(resource) {
is Resource.Error -> {
toRetry.add {
fetchFollowings()
fetchPostLikedBy(refresh)
}
}
is Resource.Loading -> {}
@ -161,6 +163,34 @@ class ProfileListingViewModel @Inject constructor(
}
}
fun fetchProfiles(refresh: Boolean = false) {
if(refresh) {
usersList = mutableListOf()
}
val updateListEvent = if(refresh) ListUpdateEvent.Refresh else ListUpdateEvent.ItemsAdded
viewModelScope.launch {
searchRepository.getNewestUsers(getUsersLastId()).onEach { resource ->
when(resource) {
is Resource.Error -> {
toRetry.add {
fetchProfiles(refresh)
}
}
is Resource.Loading -> {}
is Resource.Success -> {
if(resource.data != null) {
val prevCount = usersList.count()
usersList += resource.data
_users.postValue(Pair(usersList, UpdateEvent(updateListEvent, arrayOf(prevCount))))
}
}
}
}.flowOn(Dispatchers.IO).launchIn(this)
}
}
private fun replaceOnLists(user: ProfileListItem) {
val userIndex = usersList.indexOf(user)

View File

@ -49,7 +49,7 @@ class ProfileListingFragment : Fragment(), UserItemCallback {
FOLLOWING -> viewModel.fetchFollowings(refresh)
FOLLOWERS -> viewModel.fetchFollowers(refresh)
POST_LIKES -> viewModel.fetchPostLikedBy(refresh)
BROWSE_PROFILES -> {}
BROWSE_PROFILES -> viewModel.fetchProfiles(refresh)
}
}
@ -70,7 +70,7 @@ class ProfileListingFragment : Fragment(), UserItemCallback {
}
companion object {
private const val ARG_MODE = "mode"
const val ARG_MODE = "mode"
private const val ARG_USER_ID = "userId"
private const val ARG_POST_ID = "postId"
const val FOLLOWERS = 1

View File

@ -1,6 +1,39 @@
package com.isolaatti.profile.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController
import com.isolaatti.R
import com.isolaatti.databinding.FragmentBrowseProfileBinding
import com.isolaatti.posting.posts.ui.PostListingFragment
import com.isolaatti.profile.profile_listing.ui.ProfileListingFragment
class BrowseProfilesFragment : Fragment() {
private lateinit var binding: FragmentBrowseProfileBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentBrowseProfileBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.toolbar.setNavigationOnClickListener {
findNavController().popBackStack()
}
(childFragmentManager.findFragmentById(R.id.post_list_fragment_container) as NavHostFragment)
.navController.setGraph(R.navigation.profile_listing_navigation, Bundle().apply { putInt(
ProfileListingFragment.ARG_MODE, ProfileListingFragment.BROWSE_PROFILES) })
}
}

View File

@ -1,6 +1,7 @@
package com.isolaatti.search.data
import android.util.Log
import com.isolaatti.profile.domain.entity.ProfileListItem
import com.isolaatti.search.domain.SearchRepository
import com.isolaatti.utils.Resource
import kotlinx.coroutines.flow.Flow
@ -66,16 +67,16 @@ class SearchRepositoryImpl(private val searchApi: SearchApi, private val searchD
}
}
override fun getNewestUsers(): Flow<Resource<NewestUsersDto>> = flow {
override fun getNewestUsers(after: Int?): Flow<Resource<List<ProfileListItem>>> = flow {
emit(Resource.Loading())
try {
val result = searchApi.getNewestUsers(10, null).awaitResponse()
val result = searchApi.getNewestUsers(10, after).awaitResponse()
if(result.isSuccessful) {
val dto = result.body()
if(dto != null) {
emit(Resource.Success(dto))
emit(Resource.Success(dto.result.map { ProfileListItem.fromDto(it) }))
}
} else {

View File

@ -1,7 +1,7 @@
package com.isolaatti.search.domain
import com.isolaatti.profile.domain.entity.ProfileListItem
import com.isolaatti.search.data.HashtagsDto
import com.isolaatti.search.data.NewestUsersDto
import com.isolaatti.search.data.SearchDto
import com.isolaatti.search.data.SearchHistoryEntity
import com.isolaatti.utils.Resource
@ -15,5 +15,5 @@ interface SearchRepository {
fun removeSuggestion(query: String): Flow<Resource<Boolean>>
fun getTrendingHashtags(): Flow<Resource<HashtagsDto>>
fun getNewestUsers(): Flow<Resource<NewestUsersDto>>
fun getNewestUsers(after: Int?): Flow<Resource<List<ProfileListItem>>>
}

View File

@ -4,6 +4,7 @@ import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.isolaatti.profile.domain.entity.ProfileListItem
import com.isolaatti.search.data.HashtagsDto
import com.isolaatti.search.data.NewestUsersDto
import com.isolaatti.search.data.SearchDto
@ -27,7 +28,7 @@ class SearchViewModel @Inject constructor(private val searchRepository: SearchRe
val searchSuggestions: MutableLiveData<List<SearchHistoryEntity>> = MutableLiveData()
val searchResults: MutableLiveData<SearchDto> = MutableLiveData()
val trendingHashtags: MutableLiveData<HashtagsDto> = MutableLiveData()
val newestUsers: MutableLiveData<NewestUsersDto> = MutableLiveData()
val newestUsers: MutableLiveData<List<ProfileListItem>> = MutableLiveData()
var searchQuery = ""
@ -95,7 +96,7 @@ class SearchViewModel @Inject constructor(private val searchRepository: SearchRe
fun loadNewestUsers() {
viewModelScope.launch {
searchRepository.getNewestUsers().onEach { resource ->
searchRepository.getNewestUsers(null).onEach { resource ->
when(resource) {
is Resource.Error -> {}
is Resource.Loading -> {}

View File

@ -8,25 +8,26 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
import coil.load
import com.isolaatti.R
import com.isolaatti.databinding.UsersCarouselItemBinding
import com.isolaatti.profile.domain.entity.ProfileListItem
import com.isolaatti.search.data.ProfileSearchDto
import com.isolaatti.utils.UrlGen
class UserCarouselAdapter(
private val onProfileClick: (profileId: Int) -> Unit = {}
) : ListAdapter<ProfileSearchDto, UserCarouselAdapter.UserCarouselItemViewHolder>(itemCallback) {
) : ListAdapter<ProfileListItem, UserCarouselAdapter.UserCarouselItemViewHolder>(itemCallback) {
companion object {
val itemCallback = object: DiffUtil.ItemCallback<ProfileSearchDto>() {
val itemCallback = object: DiffUtil.ItemCallback<ProfileListItem>() {
override fun areItemsTheSame(
oldItem: ProfileSearchDto,
newItem: ProfileSearchDto
oldItem: ProfileListItem,
newItem: ProfileListItem
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: ProfileSearchDto,
newItem: ProfileSearchDto
oldItem: ProfileListItem,
newItem: ProfileListItem
): Boolean {
return oldItem == newItem
}
@ -44,8 +45,8 @@ class UserCarouselAdapter(
val user = getItem(position)
holder.usersCarouselItemBinding.userCarouselName.text = user.name
if(user.imageId != null) {
holder.usersCarouselItemBinding.userCarouselImageView.load(UrlGen.imageUrl(user.imageId))
if(user.profileImageId != null) {
holder.usersCarouselItemBinding.userCarouselImageView.load(UrlGen.imageUrl(user.profileImageId))
} else {
holder.usersCarouselItemBinding.userCarouselImageView.load(R.drawable.avatar)
}

View File

@ -19,6 +19,8 @@ import com.google.android.material.chip.Chip
import com.isolaatti.R
import com.isolaatti.databinding.FragmentSearchBinding
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
import com.isolaatti.profile.domain.entity.ProfileListItem
import com.isolaatti.profile.profile_listing.ui.ProfileListingFragment
import com.isolaatti.profile.ui.ProfileActivity
import com.isolaatti.search.data.HashtagsDto
import com.isolaatti.search.data.NewestUsersDto
@ -67,8 +69,8 @@ class SearchFragment : Fragment() {
}
}
private val newestUsersObserver: Observer<NewestUsersDto> = Observer {
newestUsersAdapter?.submitList(it.result)
private val newestUsersObserver: Observer<List<ProfileListItem>> = Observer {
newestUsersAdapter?.submitList(it)
}
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title="@string/browse_profiles"
app:navigationIcon="@drawable/baseline_close_24"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/post_list_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/profile_listing_navigation"
app:startDestination="@id/profileListingFragment">
<fragment
android:id="@+id/profileListingFragment"
android:name="com.isolaatti.profile.profile_listing.ui.ProfileListingFragment"
android:label="ProfileListingFragment" />
</navigation>