se agrega pantalla "browse profiles" y se realiza refactorización
This commit is contained in:
parent
50a70c6207
commit
ab76e3827a
@ -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 {
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) })
|
||||
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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>>>
|
||||
}
|
||||
@ -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 -> {}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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?) {
|
||||
|
||||
26
app/src/main/res/layout/fragment_browse_profile.xml
Normal file
26
app/src/main/res/layout/fragment_browse_profile.xml
Normal 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>
|
||||
11
app/src/main/res/navigation/profile_listing_navigation.xml
Normal file
11
app/src/main/res/navigation/profile_listing_navigation.xml
Normal 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>
|
||||
Loading…
x
Reference in New Issue
Block a user