diff --git a/app/src/main/java/com/isolaatti/profile/domain/entity/ProfileListItem.kt b/app/src/main/java/com/isolaatti/profile/domain/entity/ProfileListItem.kt index 9cbb4e8..5c19cd5 100644 --- a/app/src/main/java/com/isolaatti/profile/domain/entity/ProfileListItem.kt +++ b/app/src/main/java/com/isolaatti/profile/domain/entity/ProfileListItem.kt @@ -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 { diff --git a/app/src/main/java/com/isolaatti/profile/profile_listing/presentation/ProfileListingViewModel.kt b/app/src/main/java/com/isolaatti/profile/profile_listing/presentation/ProfileListingViewModel.kt index cc22d14..dab91d9 100644 --- a/app/src/main/java/com/isolaatti/profile/profile_listing/presentation/ProfileListingViewModel.kt +++ b/app/src/main/java/com/isolaatti/profile/profile_listing/presentation/ProfileListingViewModel.kt @@ -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) diff --git a/app/src/main/java/com/isolaatti/profile/profile_listing/ui/ProfileListingFragment.kt b/app/src/main/java/com/isolaatti/profile/profile_listing/ui/ProfileListingFragment.kt index 3fa5d5e..a053105 100644 --- a/app/src/main/java/com/isolaatti/profile/profile_listing/ui/ProfileListingFragment.kt +++ b/app/src/main/java/com/isolaatti/profile/profile_listing/ui/ProfileListingFragment.kt @@ -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 diff --git a/app/src/main/java/com/isolaatti/profile/ui/BrowseProfilesFragment.kt b/app/src/main/java/com/isolaatti/profile/ui/BrowseProfilesFragment.kt index 44524e3..17c7b9a 100644 --- a/app/src/main/java/com/isolaatti/profile/ui/BrowseProfilesFragment.kt +++ b/app/src/main/java/com/isolaatti/profile/ui/BrowseProfilesFragment.kt @@ -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) }) + + } } \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/search/data/SearchRepositoryImpl.kt b/app/src/main/java/com/isolaatti/search/data/SearchRepositoryImpl.kt index 54bd9fe..4277d70 100644 --- a/app/src/main/java/com/isolaatti/search/data/SearchRepositoryImpl.kt +++ b/app/src/main/java/com/isolaatti/search/data/SearchRepositoryImpl.kt @@ -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> = flow { + override fun getNewestUsers(after: Int?): Flow>> = 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 { diff --git a/app/src/main/java/com/isolaatti/search/domain/SearchRepository.kt b/app/src/main/java/com/isolaatti/search/domain/SearchRepository.kt index 9e80e38..197f50d 100644 --- a/app/src/main/java/com/isolaatti/search/domain/SearchRepository.kt +++ b/app/src/main/java/com/isolaatti/search/domain/SearchRepository.kt @@ -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> fun getTrendingHashtags(): Flow> - fun getNewestUsers(): Flow> + fun getNewestUsers(after: Int?): Flow>> } \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/search/presentation/SearchViewModel.kt b/app/src/main/java/com/isolaatti/search/presentation/SearchViewModel.kt index 198ec5c..a9eea00 100644 --- a/app/src/main/java/com/isolaatti/search/presentation/SearchViewModel.kt +++ b/app/src/main/java/com/isolaatti/search/presentation/SearchViewModel.kt @@ -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> = MutableLiveData() val searchResults: MutableLiveData = MutableLiveData() val trendingHashtags: MutableLiveData = MutableLiveData() - val newestUsers: MutableLiveData = MutableLiveData() + val newestUsers: MutableLiveData> = 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 -> {} diff --git a/app/src/main/java/com/isolaatti/search/presentation/UserCarouselAdapter.kt b/app/src/main/java/com/isolaatti/search/presentation/UserCarouselAdapter.kt index a8a21ca..84459cc 100644 --- a/app/src/main/java/com/isolaatti/search/presentation/UserCarouselAdapter.kt +++ b/app/src/main/java/com/isolaatti/search/presentation/UserCarouselAdapter.kt @@ -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(itemCallback) { +) : ListAdapter(itemCallback) { companion object { - val itemCallback = object: DiffUtil.ItemCallback() { + val itemCallback = object: DiffUtil.ItemCallback() { 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) } diff --git a/app/src/main/java/com/isolaatti/search/ui/SearchFragment.kt b/app/src/main/java/com/isolaatti/search/ui/SearchFragment.kt index 29b393e..b93c407 100644 --- a/app/src/main/java/com/isolaatti/search/ui/SearchFragment.kt +++ b/app/src/main/java/com/isolaatti/search/ui/SearchFragment.kt @@ -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 = Observer { - newestUsersAdapter?.submitList(it.result) + private val newestUsersObserver: Observer> = Observer { + newestUsersAdapter?.submitList(it) } override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/res/layout/fragment_browse_profile.xml b/app/src/main/res/layout/fragment_browse_profile.xml new file mode 100644 index 0000000..01c9f68 --- /dev/null +++ b/app/src/main/res/layout/fragment_browse_profile.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/profile_listing_navigation.xml b/app/src/main/res/navigation/profile_listing_navigation.xml new file mode 100644 index 0000000..d7b92bc --- /dev/null +++ b/app/src/main/res/navigation/profile_listing_navigation.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file