WIP perfil
This commit is contained in:
parent
0ab027b635
commit
4a8d05c87b
@ -24,7 +24,6 @@ import com.isolaatti.databinding.FragmentFeedBinding
|
|||||||
import com.isolaatti.drafts.ui.DraftsActivity
|
import com.isolaatti.drafts.ui.DraftsActivity
|
||||||
import com.isolaatti.home.presentation.FeedViewModel
|
import com.isolaatti.home.presentation.FeedViewModel
|
||||||
import com.isolaatti.posting.PostViewerActivity
|
import com.isolaatti.posting.PostViewerActivity
|
||||||
import com.isolaatti.posting.posts.presentation.PostsViewModel
|
|
||||||
import com.isolaatti.posting.comments.presentation.BottomSheetPostComments
|
import com.isolaatti.posting.comments.presentation.BottomSheetPostComments
|
||||||
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
|
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
|
||||||
@ -32,6 +31,7 @@ import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
|
|||||||
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
|
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
|
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
|
||||||
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
|
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
|
||||||
|
import com.isolaatti.posting.posts.presentation.UpdateEvent
|
||||||
import com.isolaatti.posting.posts.ui.CreatePostActivity
|
import com.isolaatti.posting.posts.ui.CreatePostActivity
|
||||||
import com.isolaatti.profile.ui.ProfileActivity
|
import com.isolaatti.profile.ui.ProfileActivity
|
||||||
import com.isolaatti.settings.ui.SettingsActivity
|
import com.isolaatti.settings.ui.SettingsActivity
|
||||||
@ -53,9 +53,8 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
const val CALLER_ID = 20
|
const val CALLER_ID = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
private val viewModel: PostsViewModel by activityViewModels()
|
|
||||||
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
||||||
private val screenViewModel: FeedViewModel by viewModels()
|
private val viewModel: FeedViewModel by activityViewModels()
|
||||||
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
|
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
|
||||||
|
|
||||||
private lateinit var viewBinding: FragmentFeedBinding
|
private lateinit var viewBinding: FragmentFeedBinding
|
||||||
@ -158,7 +157,7 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
screenViewModel.userProfile.observe(viewLifecycleOwner) {
|
viewModel.userProfile.observe(viewLifecycleOwner) {
|
||||||
val header = viewBinding.homeDrawer.getHeaderView(0) as? ConstraintLayout
|
val header = viewBinding.homeDrawer.getHeaderView(0) as? ConstraintLayout
|
||||||
|
|
||||||
val image: ImageView? = header?.findViewById(R.id.profileImageView)
|
val image: ImageView? = header?.findViewById(R.id.profileImageView)
|
||||||
@ -175,34 +174,23 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
|
|
||||||
|
|
||||||
viewModel.posts.observe(viewLifecycleOwner){
|
viewModel.posts.observe(viewLifecycleOwner){
|
||||||
if (it != null) {
|
if (it.first != null) {
|
||||||
adapter.updateList(it,null)
|
adapter.updateList(it.first!!, it.second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// viewModel.loadingPosts.observe(viewLifecycleOwner) {
|
viewModel.loadingPosts.observe(viewLifecycleOwner) {
|
||||||
// viewBinding.progressBarLoading.visibility = if(it) View.VISIBLE else View.GONE
|
viewBinding.swipeToRefresh.isRefreshing = it
|
||||||
// viewBinding.loadMoreButton.visibility = if(it) View.GONE else View.VISIBLE
|
}
|
||||||
// }
|
|
||||||
//
|
|
||||||
// viewModel.noMoreContent.observe(viewLifecycleOwner) {
|
// viewModel.noMoreContent.observe(viewLifecycleOwner) {
|
||||||
// val visibility = if(it) View.VISIBLE else View.GONE
|
//
|
||||||
// viewBinding.noMoreContentToShowTextView.visibility = visibility
|
|
||||||
// viewBinding.refreshButton.visibility = visibility
|
|
||||||
// viewBinding.loadMoreButton.visibility = if(it) View.GONE else View.VISIBLE
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
viewModel.errorLoading.observe(viewLifecycleOwner) {
|
viewModel.errorLoading.observe(viewLifecycleOwner) {
|
||||||
errorViewModel.error.postValue(it)
|
errorViewModel.error.postValue(it)
|
||||||
}
|
}
|
||||||
viewModel.postLiked.observe(viewLifecycleOwner) {
|
viewModel.getProfile()
|
||||||
viewModel.posts.value?.let { feed ->
|
|
||||||
adapter.updateList(
|
|
||||||
feed, PostsRecyclerViewAdapter.UpdateEvent(
|
|
||||||
PostsRecyclerViewAdapter.UpdateEvent.UpdateType.POST_LIKED, it.postId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
screenViewModel.getProfile()
|
|
||||||
|
|
||||||
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
|
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
|
||||||
}
|
}
|
||||||
@ -210,8 +198,6 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
fun onNewMenuItemClicked(v: View) {
|
fun onNewMenuItemClicked(v: View) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onLiked(postId: Long) = viewModel.likePost(postId)
|
override fun onLiked(postId: Long) = viewModel.likePost(postId)
|
||||||
|
|
||||||
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
||||||
@ -234,5 +220,4 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
override fun onProfileClick(userId: Int) {
|
override fun onProfileClick(userId: Int) {
|
||||||
ProfileActivity.startActivity(requireContext(), userId)
|
ProfileActivity.startActivity(requireContext(), userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -8,16 +8,13 @@ import androidx.lifecycle.Observer
|
|||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.common.ErrorMessageViewModel
|
|
||||||
import com.isolaatti.common.IsolaattiBaseActivity
|
import com.isolaatti.common.IsolaattiBaseActivity
|
||||||
import com.isolaatti.databinding.ActivityHomeBinding
|
import com.isolaatti.databinding.ActivityHomeBinding
|
||||||
import com.isolaatti.posting.posts.presentation.PostsViewModel
|
import com.isolaatti.home.presentation.FeedViewModel
|
||||||
import com.isolaatti.utils.Resource
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
class HomeActivity : IsolaattiBaseActivity() {
|
class HomeActivity : IsolaattiBaseActivity() {
|
||||||
private lateinit var viewBinding: ActivityHomeBinding
|
private lateinit var viewBinding: ActivityHomeBinding
|
||||||
private val postsViewModel: PostsViewModel by viewModels()
|
private val feedViewModel: FeedViewModel by viewModels()
|
||||||
override fun onRetry() {
|
override fun onRetry() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -32,7 +29,7 @@ class HomeActivity : IsolaattiBaseActivity() {
|
|||||||
viewBinding.navigationRail?.setupWithNavController(navHostFragment.navController)
|
viewBinding.navigationRail?.setupWithNavController(navHostFragment.navController)
|
||||||
|
|
||||||
if(savedInstanceState == null) {
|
if(savedInstanceState == null) {
|
||||||
postsViewModel.getFeed(false)
|
feedViewModel.getFeed(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,9 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.isolaatti.auth.domain.AuthRepository
|
import com.isolaatti.auth.domain.AuthRepository
|
||||||
|
import com.isolaatti.posting.posts.domain.PostsRepository
|
||||||
|
import com.isolaatti.posting.posts.presentation.PostListingViewModelBase
|
||||||
|
import com.isolaatti.posting.posts.presentation.UpdateEvent
|
||||||
import com.isolaatti.profile.data.remote.UserProfileDto
|
import com.isolaatti.profile.data.remote.UserProfileDto
|
||||||
import com.isolaatti.profile.domain.use_case.GetProfile
|
import com.isolaatti.profile.domain.use_case.GetProfile
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
@ -17,7 +20,36 @@ import kotlinx.coroutines.launch
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class FeedViewModel @Inject constructor(private val getProfileUseCase: GetProfile, private val authRepository: AuthRepository) : ViewModel() {
|
class FeedViewModel @Inject constructor(
|
||||||
|
private val getProfileUseCase: GetProfile,
|
||||||
|
private val authRepository: AuthRepository,
|
||||||
|
private val postsRepository: PostsRepository
|
||||||
|
) : PostListingViewModelBase() {
|
||||||
|
|
||||||
|
override fun getFeed(refresh: Boolean) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
if (refresh) {
|
||||||
|
posts.value = null
|
||||||
|
}
|
||||||
|
postsRepository.getFeed(getLastId()).onEach { feedDtoResource ->
|
||||||
|
when (feedDtoResource) {
|
||||||
|
is Resource.Success -> {
|
||||||
|
loadingPosts.postValue(false)
|
||||||
|
posts.postValue(Pair(posts.value?.first?.concatFeed(feedDtoResource.data) ?: feedDtoResource.data, UpdateEvent(UpdateEvent.UpdateType.PAGE_ADDED, null)))
|
||||||
|
noMoreContent.postValue(feedDtoResource.data?.moreContent == false)
|
||||||
|
}
|
||||||
|
|
||||||
|
is Resource.Loading -> {
|
||||||
|
loadingPosts.postValue(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
is Resource.Error -> {
|
||||||
|
errorLoading.postValue(feedDtoResource.errorType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// User profile
|
// User profile
|
||||||
private val _userProfile: MutableLiveData<UserProfileDto> = MutableLiveData()
|
private val _userProfile: MutableLiveData<UserProfileDto> = MutableLiveData()
|
||||||
@ -25,10 +57,10 @@ class FeedViewModel @Inject constructor(private val getProfileUseCase: GetProfil
|
|||||||
|
|
||||||
fun getProfile() {
|
fun getProfile() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
authRepository.getUserId().onEach {userId ->
|
authRepository.getUserId().onEach { userId ->
|
||||||
userId?.let {
|
userId?.let {
|
||||||
getProfileUseCase(userId).onEach {profile ->
|
getProfileUseCase(userId).onEach { profile ->
|
||||||
if(profile is Resource.Success) {
|
if (profile is Resource.Success) {
|
||||||
profile.data?.let { _userProfile.postValue(it) }
|
profile.data?.let { _userProfile.postValue(it) }
|
||||||
}
|
}
|
||||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
|
|||||||
@ -10,14 +10,8 @@ import com.isolaatti.posting.posts.data.remote.PostApi
|
|||||||
import com.isolaatti.posting.posts.domain.PostsRepository
|
import com.isolaatti.posting.posts.domain.PostsRepository
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import retrofit2.await
|
|
||||||
import java.io.IOException
|
|
||||||
import java.lang.RuntimeException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.coroutines.resume
|
|
||||||
import kotlin.coroutines.suspendCoroutine
|
|
||||||
|
|
||||||
class PostsRepositoryImpl @Inject constructor(private val feedsApi: FeedsApi, private val postApi: PostApi) : PostsRepository {
|
class PostsRepositoryImpl @Inject constructor(private val feedsApi: FeedsApi, private val postApi: PostApi) : PostsRepository {
|
||||||
override fun getFeed(lastId: Long): Flow<Resource<FeedDto>> = flow {
|
override fun getFeed(lastId: Long): Flow<Resource<FeedDto>> = flow {
|
||||||
@ -39,7 +33,7 @@ class PostsRepositoryImpl @Inject constructor(private val feedsApi: FeedsApi, pr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getProfilePosts(userId: Int, lastId: Long, olderFirst: Boolean, filter: FeedFilterDto): Flow<Resource<FeedDto>> = flow {
|
override fun getProfilePosts(userId: Int, lastId: Long, olderFirst: Boolean, filter: FeedFilterDto?): Flow<Resource<FeedDto>> = flow {
|
||||||
emit(Resource.Loading())
|
emit(Resource.Loading())
|
||||||
try {
|
try {
|
||||||
val gson = Gson()
|
val gson = Gson()
|
||||||
|
|||||||
@ -11,7 +11,7 @@ interface PostsRepository {
|
|||||||
|
|
||||||
fun getFeed(lastId: Long): Flow<Resource<FeedDto>>
|
fun getFeed(lastId: Long): Flow<Resource<FeedDto>>
|
||||||
|
|
||||||
fun getProfilePosts(userId: Int, lastId: Long, olderFirst: Boolean, filter: FeedFilterDto): Flow<Resource<FeedDto>>
|
fun getProfilePosts(userId: Int, lastId: Long, olderFirst: Boolean, filter: FeedFilterDto?): Flow<Resource<FeedDto>>
|
||||||
|
|
||||||
fun makePost(createPostDto: CreatePostDto): Flow<Resource<FeedDto.PostDto>>
|
fun makePost(createPostDto: CreatePostDto): Flow<Resource<FeedDto.PostDto>>
|
||||||
fun editPost(editPostDto: EditPostDto): Flow<Resource<FeedDto.PostDto>>
|
fun editPost(editPostDto: EditPostDto): Flow<Resource<FeedDto.PostDto>>
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.isolaatti.posting.posts.presentation
|
||||||
|
|
||||||
|
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
||||||
|
|
||||||
|
abstract class PostListingRecyclerViewAdapterWiring(private val postsViewModelBase: PostListingViewModelBase) : OnUserInteractedWithPostCallback {
|
||||||
|
|
||||||
|
override fun onLiked(postId: Long) {
|
||||||
|
postsViewModelBase.likePost(postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnLiked(postId: Long) {
|
||||||
|
postsViewModelBase.unLikePost(postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract override fun onComment(postId: Long)
|
||||||
|
|
||||||
|
abstract override fun onOpenPost(postId: Long)
|
||||||
|
|
||||||
|
abstract override fun onOptions(postId: Long)
|
||||||
|
|
||||||
|
abstract override fun onProfileClick(userId: Int)
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
package com.isolaatti.posting.posts.presentation
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.isolaatti.posting.likes.data.remote.LikeDto
|
||||||
|
import com.isolaatti.posting.likes.domain.repository.LikesRepository
|
||||||
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
|
import com.isolaatti.profile.domain.use_case.GetProfilePosts
|
||||||
|
import com.isolaatti.utils.Resource
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
abstract class PostListingViewModelBase : ViewModel() {
|
||||||
|
@Inject
|
||||||
|
lateinit var likesRepository: LikesRepository
|
||||||
|
@Inject
|
||||||
|
lateinit var getProfilePosts: GetProfilePosts
|
||||||
|
|
||||||
|
val posts: MutableLiveData<Pair<FeedDto?, UpdateEvent>> = MutableLiveData()
|
||||||
|
|
||||||
|
val loadingPosts = MutableLiveData(false)
|
||||||
|
|
||||||
|
val noMoreContent = MutableLiveData(false)
|
||||||
|
|
||||||
|
val errorLoading: MutableLiveData<Resource.Error.ErrorType?> = MutableLiveData()
|
||||||
|
|
||||||
|
fun getLastId(): Long = try { posts.value?.first?.data?.last()?.post?.id ?: 0 } catch (e: NoSuchElementException) { 0 }
|
||||||
|
|
||||||
|
|
||||||
|
abstract fun getFeed(refresh: Boolean)
|
||||||
|
|
||||||
|
fun likePost(postId: Long) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
likesRepository.likePost(postId).onEach {likeDto ->
|
||||||
|
val likedPost = posts.value?.first?.data?.find { post -> post.post.id == likeDto.postId }
|
||||||
|
val index = posts.value?.first?.data?.indexOf(likedPost)
|
||||||
|
if(index != null){
|
||||||
|
val temp = posts.value?.first
|
||||||
|
Log.d("***", temp.toString())
|
||||||
|
temp?.data?.set(index, likedPost!!.apply {
|
||||||
|
liked = true
|
||||||
|
numberOfLikes = likeDto.likesCount
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, likedPost?.post?.id)))
|
||||||
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unLikePost(postId: Long) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
likesRepository.unLikePost(postId).onEach {likeDto ->
|
||||||
|
val likedPost = posts.value?.first?.data?.find { post -> post.post.id == likeDto.postId }
|
||||||
|
val index = posts.value?.first?.data?.indexOf(likedPost)
|
||||||
|
if(index != null){
|
||||||
|
posts.value?.first?.data?.set(index, likedPost!!.apply {
|
||||||
|
liked = false
|
||||||
|
numberOfLikes = likeDto.likesCount
|
||||||
|
})
|
||||||
|
}
|
||||||
|
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, likedPost?.post?.id)))
|
||||||
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -114,15 +114,6 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
|
|||||||
data class LikeCountUpdatePayload(val likeCount: Int)
|
data class LikeCountUpdatePayload(val likeCount: Int)
|
||||||
data class CommentsCountUpdatePayload(val commentsCount: Int)
|
data class CommentsCountUpdatePayload(val commentsCount: Int)
|
||||||
|
|
||||||
data class UpdateEvent(val updateType: UpdateType, val affectedId: Long) {
|
|
||||||
enum class UpdateType {
|
|
||||||
POST_LIKED,
|
|
||||||
POST_COMMENTED,
|
|
||||||
POST_REMOVED,
|
|
||||||
POST_ADDED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedViewHolder {
|
||||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.post_layout, parent, false)
|
val view = LayoutInflater.from(parent.context).inflate(R.layout.post_layout, parent, false)
|
||||||
@ -143,24 +134,34 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
|
|||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val postUpdated = feedDto?.data?.find { p -> p.post.id == updateEvent.affectedId } ?: return
|
val postUpdated = feedDto?.data?.find { p -> p.post.id == updateEvent.affectedId }
|
||||||
val position = feedDto?.data?.indexOf(postUpdated) ?: return
|
val position = feedDto?.data?.indexOf(postUpdated)
|
||||||
|
|
||||||
feedDto = updatedFeed
|
feedDto = updatedFeed
|
||||||
|
|
||||||
when(updateEvent.updateType) {
|
when(updateEvent.updateType) {
|
||||||
UpdateEvent.UpdateType.POST_LIKED -> {
|
UpdateEvent.UpdateType.POST_LIKED -> {
|
||||||
notifyItemChanged(position, LikeCountUpdatePayload(postUpdated.numberOfLikes))
|
if(postUpdated != null && position != null)
|
||||||
|
notifyItemChanged(position, LikeCountUpdatePayload(postUpdated.numberOfLikes))
|
||||||
}
|
}
|
||||||
UpdateEvent.UpdateType.POST_COMMENTED -> {
|
UpdateEvent.UpdateType.POST_COMMENTED -> {
|
||||||
notifyItemChanged(position, CommentsCountUpdatePayload(postUpdated.numberOfComments))
|
if(postUpdated != null && position != null)
|
||||||
|
notifyItemChanged(position, CommentsCountUpdatePayload(postUpdated.numberOfComments))
|
||||||
}
|
}
|
||||||
UpdateEvent.UpdateType.POST_REMOVED -> {
|
UpdateEvent.UpdateType.POST_REMOVED -> {
|
||||||
notifyItemRemoved(position)
|
if(postUpdated != null && position != null)
|
||||||
|
notifyItemRemoved(position)
|
||||||
}
|
}
|
||||||
UpdateEvent.UpdateType.POST_ADDED -> {
|
UpdateEvent.UpdateType.POST_ADDED -> {
|
||||||
notifyItemInserted(0)
|
notifyItemInserted(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateEvent.UpdateType.PAGE_ADDED -> {
|
||||||
|
notifyItemInserted(itemCount - 1)
|
||||||
|
}
|
||||||
|
UpdateEvent.UpdateType.REFRESH -> {
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,105 +0,0 @@
|
|||||||
package com.isolaatti.posting.posts.presentation
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.isolaatti.posting.comments.data.remote.FeedCommentsDto
|
|
||||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
|
||||||
import com.isolaatti.posting.likes.data.remote.LikeDto
|
|
||||||
import com.isolaatti.posting.likes.domain.repository.LikesRepository
|
|
||||||
import com.isolaatti.posting.posts.data.repository.PostsRepositoryImpl
|
|
||||||
import com.isolaatti.posting.posts.domain.PostsRepository
|
|
||||||
import com.isolaatti.utils.Resource
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.flowOn
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@HiltViewModel
|
|
||||||
class PostsViewModel @Inject constructor(private val postsRepository: PostsRepository, private val likesRepository: LikesRepository) : ViewModel() {
|
|
||||||
|
|
||||||
private val _posts: MutableLiveData<FeedDto?> = MutableLiveData()
|
|
||||||
val posts: LiveData<FeedDto?> get() = _posts
|
|
||||||
|
|
||||||
private val _loadingPosts = MutableLiveData(false)
|
|
||||||
val loadingPosts: LiveData<Boolean> get() = _loadingPosts
|
|
||||||
|
|
||||||
private val _noMoreContent = MutableLiveData(false)
|
|
||||||
val noMoreContent: LiveData<Boolean> get() = _noMoreContent
|
|
||||||
|
|
||||||
private val _errorLoading: MutableLiveData<Resource.Error.ErrorType?> = MutableLiveData()
|
|
||||||
val errorLoading: LiveData<Resource.Error.ErrorType?> get() = _errorLoading
|
|
||||||
|
|
||||||
private val _comments: MutableLiveData<FeedCommentsDto> = MutableLiveData()
|
|
||||||
val comments: LiveData<FeedCommentsDto> get() = _comments
|
|
||||||
|
|
||||||
private fun getLastId(): Long = try {_posts.value?.data?.last()?.post?.id ?: 0} catch (e: NoSuchElementException) { 0 }
|
|
||||||
|
|
||||||
private val _postLiked: MutableLiveData<LikeDto> = MutableLiveData()
|
|
||||||
val postLiked: LiveData<LikeDto> get() = _postLiked
|
|
||||||
|
|
||||||
fun getFeed(refresh: Boolean) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
if(refresh) {
|
|
||||||
_posts.value = null
|
|
||||||
}
|
|
||||||
postsRepository.getFeed(getLastId()).onEach {
|
|
||||||
when(it) {
|
|
||||||
is Resource.Success -> {
|
|
||||||
_loadingPosts.postValue(false)
|
|
||||||
_posts.postValue(posts.value?.concatFeed(it.data) ?: it.data)
|
|
||||||
_noMoreContent.postValue(it.data?.moreContent == false)
|
|
||||||
}
|
|
||||||
is Resource.Loading -> {
|
|
||||||
_loadingPosts.postValue(true)
|
|
||||||
}
|
|
||||||
is Resource.Error -> {
|
|
||||||
_errorLoading.postValue(it.errorType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun likePost(postId: Long) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
likesRepository.likePost(postId).onEach {likeDto ->
|
|
||||||
val likedPost = _posts.value?.data?.find { post -> post.post.id == likeDto.postId }
|
|
||||||
val index = _posts.value?.data?.indexOf(likedPost)
|
|
||||||
Log.d("***", index.toString())
|
|
||||||
if(index != null){
|
|
||||||
val temp = _posts.value
|
|
||||||
Log.d("***", temp.toString())
|
|
||||||
temp?.data?.set(index, likedPost!!.apply {
|
|
||||||
liked = true
|
|
||||||
numberOfLikes = likeDto.likesCount
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_postLiked.postValue(likeDto)
|
|
||||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unLikePost(postId: Long) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
likesRepository.unLikePost(postId).onEach {likeDto ->
|
|
||||||
val likedPost = _posts.value?.data?.find { post -> post.post.id == likeDto.postId }
|
|
||||||
val index = _posts.value?.data?.indexOf(likedPost)
|
|
||||||
if(index != null){
|
|
||||||
_posts.value?.data?.set(index, likedPost!!.apply {
|
|
||||||
liked = false
|
|
||||||
numberOfLikes = likeDto.likesCount
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_postLiked.postValue(likeDto)
|
|
||||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.isolaatti.posting.posts.presentation
|
||||||
|
|
||||||
|
data class UpdateEvent(val updateType: UpdateType, val affectedId: Long?) {
|
||||||
|
enum class UpdateType {
|
||||||
|
POST_LIKED,
|
||||||
|
POST_COMMENTED,
|
||||||
|
POST_REMOVED,
|
||||||
|
POST_ADDED,
|
||||||
|
PAGE_ADDED,
|
||||||
|
REFRESH
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class GetProfilePosts @Inject constructor(private val postsRepository: PostsRepository) {
|
class GetProfilePosts @Inject constructor(private val postsRepository: PostsRepository) {
|
||||||
operator fun invoke(userId: Int, lastId: Long, olderFirst: Boolean, filter: FeedFilterDto): Flow<Resource<FeedDto>> =
|
operator fun invoke(userId: Int, lastId: Long, olderFirst: Boolean, filter: FeedFilterDto?): Flow<Resource<FeedDto>> =
|
||||||
postsRepository.getProfilePosts(userId, lastId, olderFirst, filter)
|
postsRepository.getProfilePosts(userId, lastId, olderFirst, filter)
|
||||||
}
|
}
|
||||||
@ -6,6 +6,8 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
import com.isolaatti.posting.posts.data.remote.FeedFilterDto
|
import com.isolaatti.posting.posts.data.remote.FeedFilterDto
|
||||||
|
import com.isolaatti.posting.posts.presentation.PostListingViewModelBase
|
||||||
|
import com.isolaatti.posting.posts.presentation.UpdateEvent
|
||||||
import com.isolaatti.profile.data.remote.UserProfileDto
|
import com.isolaatti.profile.data.remote.UserProfileDto
|
||||||
import com.isolaatti.profile.domain.ProfileRepository
|
import com.isolaatti.profile.domain.ProfileRepository
|
||||||
import com.isolaatti.profile.domain.use_case.GetProfile
|
import com.isolaatti.profile.domain.use_case.GetProfile
|
||||||
@ -24,14 +26,13 @@ import java.time.Month
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class ProfileViewModel @Inject constructor(private val getProfileUseCase: GetProfile, private val getProfilePosts: GetProfilePosts) : ViewModel() {
|
class ProfileViewModel @Inject constructor(private val getProfileUseCase: GetProfile, private val getProfilePostsUseCase: GetProfilePosts) : PostListingViewModelBase() {
|
||||||
private val _profile = MutableLiveData<UserProfileDto>()
|
private val _profile = MutableLiveData<UserProfileDto>()
|
||||||
val profile: LiveData<UserProfileDto> get() = _profile
|
val profile: LiveData<UserProfileDto> get() = _profile
|
||||||
|
|
||||||
private val _posts = MutableLiveData<FeedDto>()
|
var profileId: Int = 0
|
||||||
val posts: LiveData<FeedDto> get() = _posts
|
|
||||||
|
|
||||||
fun getProfile(profileId: Int) {
|
fun getProfile() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
getProfileUseCase(profileId).onEach {
|
getProfileUseCase(profileId).onEach {
|
||||||
if(it is Resource.Success) {
|
if(it is Resource.Success) {
|
||||||
@ -41,24 +42,23 @@ class ProfileViewModel @Inject constructor(private val getProfileUseCase: GetPro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPosts(profileId: Int, refresh: Boolean) {
|
override fun getFeed(refresh: Boolean) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
getProfilePosts(
|
getProfilePostsUseCase(profileId, getLastId(), false, null).onEach { feedDtoResource ->
|
||||||
profileId,
|
when (feedDtoResource) {
|
||||||
-1,
|
is Resource.Success -> {
|
||||||
false,
|
loadingPosts.postValue(false)
|
||||||
FeedFilterDto(
|
posts.postValue(Pair(posts.value?.first?.concatFeed(feedDtoResource.data) ?: feedDtoResource.data, UpdateEvent(UpdateEvent.UpdateType.PAGE_ADDED, null)))
|
||||||
"both",
|
noMoreContent.postValue(feedDtoResource.data?.moreContent == false)
|
||||||
"both",
|
}
|
||||||
FeedFilterDto.DataRange(
|
|
||||||
false,
|
is Resource.Loading -> {
|
||||||
LocalDate.of(2020, 1, 1),
|
loadingPosts.postValue(true)
|
||||||
LocalDate.now()
|
}
|
||||||
)
|
|
||||||
)
|
is Resource.Error -> {
|
||||||
).onEach {
|
errorLoading.postValue(feedDtoResource.errorType)
|
||||||
if(it is Resource.Success) {
|
}
|
||||||
_posts.postValue(it.data!!)
|
|
||||||
}
|
}
|
||||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,29 +1,36 @@
|
|||||||
package com.isolaatti.profile.ui
|
package com.isolaatti.profile.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.activity.viewModels
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
|
||||||
import com.isolaatti.BuildConfig
|
import com.isolaatti.BuildConfig
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.databinding.FragmentDiscussionsBinding
|
import com.isolaatti.databinding.FragmentDiscussionsBinding
|
||||||
|
import com.isolaatti.home.FeedFragment
|
||||||
|
import com.isolaatti.posting.PostViewerActivity
|
||||||
|
import com.isolaatti.posting.comments.presentation.BottomSheetPostComments
|
||||||
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
||||||
|
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
|
||||||
|
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
|
||||||
|
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
|
||||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
|
import com.isolaatti.posting.posts.presentation.PostListingRecyclerViewAdapterWiring
|
||||||
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
|
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
|
||||||
|
import com.isolaatti.posting.posts.presentation.UpdateEvent
|
||||||
import com.isolaatti.profile.data.remote.UserProfileDto
|
import com.isolaatti.profile.data.remote.UserProfileDto
|
||||||
import com.isolaatti.profile.presentation.ProfileViewModel
|
import com.isolaatti.profile.presentation.ProfileViewModel
|
||||||
import com.isolaatti.utils.PicassoImagesPluginDef
|
import com.isolaatti.utils.PicassoImagesPluginDef
|
||||||
import com.isolaatti.utils.UrlGen
|
import com.isolaatti.utils.UrlGen
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
||||||
import io.noties.markwon.AbstractMarkwonPlugin
|
import io.noties.markwon.AbstractMarkwonPlugin
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import io.noties.markwon.MarkwonConfiguration
|
import io.noties.markwon.MarkwonConfiguration
|
||||||
@ -31,14 +38,19 @@ import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAb
|
|||||||
import io.noties.markwon.linkify.LinkifyPlugin
|
import io.noties.markwon.linkify.LinkifyPlugin
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class DiscussionsFragment : Fragment(), OnUserInteractedWithPostCallback {
|
class DiscussionsFragment : Fragment() {
|
||||||
lateinit var viewBinding: FragmentDiscussionsBinding
|
lateinit var viewBinding: FragmentDiscussionsBinding
|
||||||
|
|
||||||
private val viewModel: ProfileViewModel by viewModels()
|
private val viewModel: ProfileViewModel by viewModels()
|
||||||
|
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
|
||||||
private var userId: Int? = null
|
private var userId: Int? = null
|
||||||
|
|
||||||
|
lateinit var postsAdapter: PostsRecyclerViewAdapter
|
||||||
|
|
||||||
|
// collapsing bar
|
||||||
private var title = ""
|
private var title = ""
|
||||||
lateinit var feedAdapter: PostsRecyclerViewAdapter
|
private var scrollRange = -1
|
||||||
|
private var isShow = false
|
||||||
|
|
||||||
|
|
||||||
private val profileObserver = Observer<UserProfileDto> { profile ->
|
private val profileObserver = Observer<UserProfileDto> { profile ->
|
||||||
Picasso.get()
|
Picasso.get()
|
||||||
@ -50,30 +62,18 @@ class DiscussionsFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
viewBinding.textViewDescription.text = profile.descriptionText
|
viewBinding.textViewDescription.text = profile.descriptionText
|
||||||
}
|
}
|
||||||
|
|
||||||
private val postsObserver: Observer<FeedDto> = Observer {
|
private val postsObserver: Observer<Pair<FeedDto?, UpdateEvent>> = Observer {
|
||||||
feedAdapter.updateList(it, null)
|
if(it.first != null) {
|
||||||
|
postsAdapter.updateList(it.first!!, it.second)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
private lateinit var postListingRecyclerViewAdapterWiring: PostListingRecyclerViewAdapterWiring
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
userId = (requireActivity()).intent.extras?.getInt(ProfileActivity.EXTRA_USER_ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
private fun setupCollapsingBar() {
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
viewBinding = FragmentDiscussionsBinding.inflate(inflater)
|
|
||||||
|
|
||||||
return viewBinding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
var scrollRange = -1
|
|
||||||
var isShow = false
|
|
||||||
viewBinding.topAppBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
|
viewBinding.topAppBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
|
||||||
if (scrollRange == -1) scrollRange = appBarLayout.totalScrollRange
|
if (scrollRange == -1) scrollRange = appBarLayout.totalScrollRange
|
||||||
if (scrollRange + verticalOffset == 0) {
|
if (scrollRange + verticalOffset == 0) {
|
||||||
@ -83,38 +83,16 @@ class DiscussionsFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
viewBinding.collapsingToolbarLayout.title = " "
|
viewBinding.collapsingToolbarLayout.title = " "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bind() {
|
||||||
|
|
||||||
|
|
||||||
viewBinding.topAppBar.setNavigationOnClickListener {
|
viewBinding.topAppBar.setNavigationOnClickListener {
|
||||||
findNavController().popBackStack()
|
findNavController().popBackStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
viewModel.profile.observe(viewLifecycleOwner, profileObserver)
|
|
||||||
viewModel.posts.observe(viewLifecycleOwner, postsObserver)
|
|
||||||
|
|
||||||
userId?.let {
|
|
||||||
viewModel.getProfile(it)
|
|
||||||
viewModel.getPosts(it, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
val markwon = Markwon.builder(requireContext())
|
|
||||||
.usePlugin(object: AbstractMarkwonPlugin() {
|
|
||||||
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
|
||||||
builder
|
|
||||||
.imageDestinationProcessor(
|
|
||||||
ImageDestinationProcessorRelativeToAbsolute
|
|
||||||
.create(BuildConfig.backend))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.usePlugin(PicassoImagesPluginDef.picassoImagePlugin)
|
|
||||||
.usePlugin(LinkifyPlugin.create())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
feedAdapter = PostsRecyclerViewAdapter(markwon, this, null)
|
|
||||||
|
|
||||||
viewBinding.feedRecyclerView.adapter = feedAdapter
|
|
||||||
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
|
||||||
|
|
||||||
viewBinding.bottomAppBar.setOnMenuItemClickListener {
|
viewBinding.bottomAppBar.setOnMenuItemClickListener {
|
||||||
when(it.itemId) {
|
when(it.itemId) {
|
||||||
R.id.audios_menu_item -> {
|
R.id.audios_menu_item -> {
|
||||||
@ -129,29 +107,88 @@ class DiscussionsFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewBinding.feedRecyclerView.adapter = postsAdapter
|
||||||
|
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLiked(postId: Long) {
|
private fun setObservers() {
|
||||||
TODO("Not yet implemented")
|
viewModel.profile.observe(viewLifecycleOwner, profileObserver)
|
||||||
|
viewModel.posts.observe(viewLifecycleOwner, postsObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUnLiked(postId: Long) {
|
private fun getData() {
|
||||||
TODO("Not yet implemented")
|
|
||||||
|
userId?.let { profileId ->
|
||||||
|
viewModel.profileId = profileId
|
||||||
|
viewModel.getProfile()
|
||||||
|
viewModel.getFeed(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onComment(postId: Long) {
|
private fun setupPostsAdapter() {
|
||||||
TODO("Not yet implemented")
|
val markwon = Markwon.builder(requireContext())
|
||||||
|
.usePlugin(object: AbstractMarkwonPlugin() {
|
||||||
|
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
||||||
|
builder
|
||||||
|
.imageDestinationProcessor(
|
||||||
|
ImageDestinationProcessorRelativeToAbsolute
|
||||||
|
.create(BuildConfig.backend))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.usePlugin(PicassoImagesPluginDef.picassoImagePlugin)
|
||||||
|
.usePlugin(LinkifyPlugin.create())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
postsAdapter = PostsRecyclerViewAdapter(markwon,postListingRecyclerViewAdapterWiring, null )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenPost(postId: Long) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
TODO("Not yet implemented")
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
userId = (requireActivity()).intent.extras?.getInt(ProfileActivity.EXTRA_USER_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptions(postId: Long) {
|
override fun onAttach(context: Context) {
|
||||||
TODO("Not yet implemented")
|
super.onAttach(context)
|
||||||
|
postListingRecyclerViewAdapterWiring = object: PostListingRecyclerViewAdapterWiring(viewModel) {
|
||||||
|
override fun onComment(postId: Long) {
|
||||||
|
val modalBottomSheet = BottomSheetPostComments.getInstance(postId)
|
||||||
|
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostComments.TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOpenPost(postId: Long) {
|
||||||
|
PostViewerActivity.startActivity(requireContext(), postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptions(postId: Long) {
|
||||||
|
optionsViewModel.setOptions(Options.postOptions, FeedFragment.CALLER_ID)
|
||||||
|
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
||||||
|
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProfileClick(userId: Int) {
|
||||||
|
//ProfileActivity.startActivity(requireContext(), userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onProfileClick(userId: Int) {
|
override fun onCreateView(
|
||||||
TODO("Not yet implemented")
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
viewBinding = FragmentDiscussionsBinding.inflate(inflater)
|
||||||
|
|
||||||
|
return viewBinding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
setupCollapsingBar()
|
||||||
|
setupPostsAdapter()
|
||||||
|
bind()
|
||||||
|
setObservers()
|
||||||
|
getData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,6 +10,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.core.content.ContentProviderCompat.requireContext
|
import androidx.core.content.ContentProviderCompat.requireContext
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
@ -45,7 +46,6 @@ class ProfileActivity : FragmentActivity() {
|
|||||||
|
|
||||||
lateinit var viewBinding: ActivityProfileBinding
|
lateinit var viewBinding: ActivityProfileBinding
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
viewBinding = ActivityProfileBinding.inflate(layoutInflater)
|
viewBinding = ActivityProfileBinding.inflate(layoutInflater)
|
||||||
|
|||||||
@ -1,8 +1,24 @@
|
|||||||
package com.isolaatti.profile.ui
|
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.fragment.app.Fragment
|
||||||
|
import com.isolaatti.databinding.FragmentUserlinkBinding
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class UserLinkFragment : Fragment() {
|
class UserLinkFragment : Fragment() {
|
||||||
|
lateinit var binding: FragmentUserlinkBinding
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
binding = FragmentUserlinkBinding.inflate(inflater)
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,17 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<TextView
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/textView2"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:layout_height="wrap_content"
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:text="@string/audios"
|
android:id="@+id/topAppBar"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_width="match_parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:title="@string/audios"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:navigationIcon="@drawable/baseline_arrow_back_24"
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
app:navigationIconTint="@color/on_surface"
|
||||||
|
app:titleCentered="true"/>
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@ -44,9 +44,10 @@
|
|||||||
android:id="@+id/feed_recycler_view"
|
android:id="@+id/feed_recycler_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<com.google.android.material.navigation.NavigationView
|
<com.google.android.material.navigation.NavigationView
|
||||||
|
|||||||
@ -1,22 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<ScrollView
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="wrap_content">
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
<TextView
|
android:id="@+id/topAppBar"
|
||||||
android:id="@+id/textView3"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="2000dp"
|
app:title="@string/images"
|
||||||
android:text="@string/images"
|
app:navigationIcon="@drawable/baseline_arrow_back_24"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:navigationIconTint="@color/on_surface"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:titleCentered="true"/>
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
</ScrollView>
|
|
||||||
</FrameLayout>
|
|
||||||
6
app/src/main/res/layout/fragment_userlink.xml
Normal file
6
app/src/main/res/layout/fragment_userlink.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
Loading…
x
Reference in New Issue
Block a user