WIP
This commit is contained in:
parent
f91fa2d27d
commit
633b366baf
@ -7,6 +7,7 @@ import com.isolaatti.auth.data.remote.AuthApi
|
|||||||
import com.isolaatti.auth.domain.AuthRepository
|
import com.isolaatti.auth.domain.AuthRepository
|
||||||
import com.isolaatti.connectivity.RetrofitClient
|
import com.isolaatti.connectivity.RetrofitClient
|
||||||
import com.isolaatti.database.AppDatabase
|
import com.isolaatti.database.AppDatabase
|
||||||
|
import com.isolaatti.settings.domain.UserIdSetting
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
@ -21,7 +22,7 @@ class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideAuthRepository(tokenStorage: TokenStorage, authApi: AuthApi, keyValueDao: KeyValueDao): AuthRepository {
|
fun provideAuthRepository(tokenStorage: TokenStorage, authApi: AuthApi, userIdSetting: UserIdSetting): AuthRepository {
|
||||||
return AuthRepositoryImpl(tokenStorage, authApi, keyValueDao)
|
return AuthRepositoryImpl(tokenStorage, authApi, userIdSetting)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ import com.isolaatti.auth.data.local.TokenStorage
|
|||||||
import com.isolaatti.auth.data.remote.AuthApi
|
import com.isolaatti.auth.data.remote.AuthApi
|
||||||
import com.isolaatti.auth.data.remote.Credential
|
import com.isolaatti.auth.data.remote.Credential
|
||||||
import com.isolaatti.auth.domain.AuthRepository
|
import com.isolaatti.auth.domain.AuthRepository
|
||||||
|
import com.isolaatti.settings.domain.UserIdSetting
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
@ -17,11 +18,8 @@ import javax.inject.Inject
|
|||||||
class AuthRepositoryImpl @Inject constructor(
|
class AuthRepositoryImpl @Inject constructor(
|
||||||
private val tokenStorage: TokenStorage,
|
private val tokenStorage: TokenStorage,
|
||||||
private val authApi: AuthApi,
|
private val authApi: AuthApi,
|
||||||
private val keyValueDao: KeyValueDao
|
private val userIdSetting: UserIdSetting
|
||||||
) : AuthRepository {
|
) : AuthRepository {
|
||||||
companion object {
|
|
||||||
val KEY_USERID = "user_id"
|
|
||||||
}
|
|
||||||
override fun authWithEmailAndPassword(
|
override fun authWithEmailAndPassword(
|
||||||
email: String,
|
email: String,
|
||||||
password: String
|
password: String
|
||||||
@ -37,7 +35,7 @@ class AuthRepositoryImpl @Inject constructor(
|
|||||||
return@flow
|
return@flow
|
||||||
}
|
}
|
||||||
tokenStorage.storeToken(dto)
|
tokenStorage.storeToken(dto)
|
||||||
keyValueDao.setValue(KeyValueEntity(KEY_USERID, dto.userId.toString()))
|
userIdSetting.setUserId(dto.userId)
|
||||||
emit(Resource.Success(true))
|
emit(Resource.Success(true))
|
||||||
return@flow
|
return@flow
|
||||||
}
|
}
|
||||||
@ -66,7 +64,7 @@ class AuthRepositoryImpl @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getUserId(): Flow<Int?> = flow {
|
override fun getUserId(): Flow<Int?> = flow {
|
||||||
emit(keyValueDao.getValue(KEY_USERID).toIntOrNull())
|
emit(userIdSetting.getUserId())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -25,6 +25,7 @@ import com.isolaatti.picture_viewer.ui.PictureViewerActivity
|
|||||||
import com.isolaatti.posting.PostViewerActivity
|
import com.isolaatti.posting.PostViewerActivity
|
||||||
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.domain.Ownable
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
|
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
|
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
|
||||||
@ -160,7 +161,7 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
.usePlugin(PicassoImagesPluginDef.picassoImagePlugin)
|
.usePlugin(PicassoImagesPluginDef.picassoImagePlugin)
|
||||||
.usePlugin(LinkifyPlugin.create())
|
.usePlugin(LinkifyPlugin.create())
|
||||||
.build()
|
.build()
|
||||||
adapter = PostsRecyclerViewAdapter(markwon, this, null)
|
adapter = PostsRecyclerViewAdapter(markwon, this)
|
||||||
viewBinding.feedRecyclerView.adapter = adapter
|
viewBinding.feedRecyclerView.adapter = adapter
|
||||||
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
|
|
||||||
@ -227,8 +228,8 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
|
|
||||||
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
||||||
|
|
||||||
override fun onOptions(postId: Long) {
|
override fun onOptions(post: Ownable) {
|
||||||
optionsViewModel.setOptions(Options.myPostOptions, CALLER_ID, postId)
|
optionsViewModel.setOptions(Options.POST_OPTIONS, CALLER_ID, post)
|
||||||
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
||||||
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package com.isolaatti.home.presentation
|
|||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
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.domain.PostsRepository
|
||||||
@ -31,12 +30,16 @@ class FeedViewModel @Inject constructor(
|
|||||||
if (refresh) {
|
if (refresh) {
|
||||||
posts.value = null
|
posts.value = null
|
||||||
}
|
}
|
||||||
postsRepository.getFeed(getLastId()).onEach { feedDtoResource ->
|
postsRepository.getFeed(getLastId()).onEach { listResource ->
|
||||||
when (feedDtoResource) {
|
when (listResource) {
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
loadingPosts.postValue(false)
|
loadingPosts.postValue(false)
|
||||||
posts.postValue(Pair(posts.value?.first?.concatFeed(feedDtoResource.data) ?: feedDtoResource.data, UpdateEvent(UpdateEvent.UpdateType.PAGE_ADDED, null)))
|
posts.postValue(Pair(postsList?.apply {
|
||||||
noMoreContent.postValue(feedDtoResource.data?.moreContent == false)
|
addAll(listResource.data ?: listOf())
|
||||||
|
} ?: listResource.data,
|
||||||
|
UpdateEvent(UpdateEvent.UpdateType.PAGE_ADDED, null)))
|
||||||
|
|
||||||
|
noMoreContent.postValue(listResource.data?.size == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Loading -> {
|
is Resource.Loading -> {
|
||||||
@ -45,7 +48,7 @@ class FeedViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Error -> {
|
is Resource.Error -> {
|
||||||
errorLoading.postValue(feedDtoResource.errorType)
|
//errorLoading.postValue(feedDtoResource.errorType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isLoadingFromScrolling = false
|
isLoadingFromScrolling = false
|
||||||
|
|||||||
@ -3,8 +3,8 @@ package com.isolaatti.posting.comments.data.repository
|
|||||||
import com.isolaatti.posting.comments.data.remote.CommentDto
|
import com.isolaatti.posting.comments.data.remote.CommentDto
|
||||||
import com.isolaatti.posting.comments.data.remote.CommentToPostDto
|
import com.isolaatti.posting.comments.data.remote.CommentToPostDto
|
||||||
import com.isolaatti.posting.comments.data.remote.CommentsApi
|
import com.isolaatti.posting.comments.data.remote.CommentsApi
|
||||||
import com.isolaatti.posting.comments.data.remote.FeedCommentsDto
|
|
||||||
import com.isolaatti.posting.comments.domain.CommentsRepository
|
import com.isolaatti.posting.comments.domain.CommentsRepository
|
||||||
|
import com.isolaatti.posting.comments.domain.model.Comment
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import retrofit2.awaitResponse
|
import retrofit2.awaitResponse
|
||||||
@ -12,10 +12,10 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class CommentsRepositoryImpl @Inject constructor(private val commentsApi: CommentsApi) :
|
class CommentsRepositoryImpl @Inject constructor(private val commentsApi: CommentsApi) :
|
||||||
CommentsRepository {
|
CommentsRepository {
|
||||||
override fun getComments(postId: Long, lastId: Long): Flow<FeedCommentsDto> = flow {
|
override fun getComments(postId: Long, lastId: Long): Flow<MutableList<Comment>> = flow {
|
||||||
val response = commentsApi.getCommentsOfPosts(postId, lastId, 15).awaitResponse()
|
val response = commentsApi.getCommentsOfPosts(postId, lastId, 15).awaitResponse()
|
||||||
if(response.isSuccessful){
|
if(response.isSuccessful){
|
||||||
response.body()?.let { emit(it) }
|
response.body()?.let { emit(Comment.fromCommentsDto(it).toMutableList()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,11 @@ package com.isolaatti.posting.comments.domain
|
|||||||
|
|
||||||
import com.isolaatti.posting.comments.data.remote.CommentDto
|
import com.isolaatti.posting.comments.data.remote.CommentDto
|
||||||
import com.isolaatti.posting.comments.data.remote.CommentToPostDto
|
import com.isolaatti.posting.comments.data.remote.CommentToPostDto
|
||||||
import com.isolaatti.posting.comments.data.remote.FeedCommentsDto
|
import com.isolaatti.posting.comments.domain.model.Comment
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface CommentsRepository {
|
interface CommentsRepository {
|
||||||
fun getComments(postId: Long, lastId: Long): Flow<FeedCommentsDto>
|
fun getComments(postId: Long, lastId: Long): Flow<MutableList<Comment>>
|
||||||
fun getComment(commentId: Long): Flow<CommentDto>
|
fun getComment(commentId: Long): Flow<CommentDto>
|
||||||
fun postComment(commentToPostDto: CommentToPostDto, postId: Long): Flow<Boolean>
|
fun postComment(commentToPostDto: CommentToPostDto, postId: Long): Flow<Boolean>
|
||||||
}
|
}
|
||||||
@ -1,12 +1,30 @@
|
|||||||
package com.isolaatti.posting.comments.domain.model
|
package com.isolaatti.posting.comments.domain.model
|
||||||
|
|
||||||
|
import com.isolaatti.posting.comments.data.remote.CommentDto
|
||||||
|
import com.isolaatti.posting.comments.data.remote.FeedCommentsDto
|
||||||
|
import com.isolaatti.posting.common.domain.Ownable
|
||||||
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
|
|
||||||
data class Comment(
|
data class Comment(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val textContent: String,
|
val textContent: String,
|
||||||
val userId: Int,
|
override val userId: Int,
|
||||||
val postId: Long,
|
val postId: Long,
|
||||||
val date: String,
|
val date: String,
|
||||||
val responseForCommentId: Long?,
|
val username: String
|
||||||
val linkedDiscussionId: Long?,
|
) : Ownable {
|
||||||
val linkedCommentId: Long?
|
companion object {
|
||||||
|
fun fromCommentsDto(dtoList: FeedCommentsDto): List<Comment> {
|
||||||
|
return dtoList.data.map {
|
||||||
|
Comment(
|
||||||
|
id = it.comment.id,
|
||||||
|
textContent = it.comment.textContent,
|
||||||
|
userId = it.comment.userId,
|
||||||
|
postId = it.comment.postId,
|
||||||
|
date = it.comment.date,
|
||||||
|
username = it.username
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
package com.isolaatti.posting.comments.domain.use_case
|
package com.isolaatti.posting.comments.domain.use_case
|
||||||
|
|
||||||
import com.isolaatti.posting.comments.data.remote.CommentDto
|
|
||||||
import com.isolaatti.posting.comments.data.remote.FeedCommentsDto
|
|
||||||
import com.isolaatti.posting.comments.domain.CommentsRepository
|
import com.isolaatti.posting.comments.domain.CommentsRepository
|
||||||
|
import com.isolaatti.posting.comments.domain.model.Comment
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class GetComments @Inject constructor(private val commentsRepository: CommentsRepository) {
|
class GetComments @Inject constructor(private val commentsRepository: CommentsRepository) {
|
||||||
operator fun invoke(postId: Long, lastId: Long? = null): Flow<FeedCommentsDto> =
|
operator fun invoke(postId: Long, lastId: Long? = null): Flow<MutableList<Comment>> =
|
||||||
commentsRepository.getComments(postId, lastId ?: 0)
|
commentsRepository.getComments(postId, lastId ?: 0)
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
|
|||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.isolaatti.databinding.BottomSheetPostCommentsBinding
|
import com.isolaatti.databinding.BottomSheetPostCommentsBinding
|
||||||
import com.isolaatti.posting.common.domain.OnUserInteractedCallback
|
import com.isolaatti.posting.common.domain.OnUserInteractedCallback
|
||||||
|
import com.isolaatti.posting.common.domain.Ownable
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
|
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
|
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
|
||||||
@ -115,8 +116,8 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onOptions(postId: Long) {
|
override fun onOptions(comment: Ownable) {
|
||||||
optionsViewModel.setOptions(Options.myCommentOptions, CALLER_ID)
|
optionsViewModel.setOptions(Options.POST_OPTIONS, CALLER_ID, comment)
|
||||||
val fragment = BottomSheetPostOptionsFragment()
|
val fragment = BottomSheetPostOptionsFragment()
|
||||||
fragment.show(parentFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
fragment.show(parentFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,12 +5,13 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.isolaatti.databinding.CommentLayoutBinding
|
import com.isolaatti.databinding.CommentLayoutBinding
|
||||||
import com.isolaatti.posting.comments.data.remote.CommentDto
|
import com.isolaatti.posting.comments.data.remote.CommentDto
|
||||||
|
import com.isolaatti.posting.comments.domain.model.Comment
|
||||||
import com.isolaatti.posting.common.domain.OnUserInteractedCallback
|
import com.isolaatti.posting.common.domain.OnUserInteractedCallback
|
||||||
import com.isolaatti.utils.UrlGen
|
import com.isolaatti.utils.UrlGen
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
|
|
||||||
class CommentsRecyclerViewAdapter(private var list: List<CommentDto>, private val markwon: Markwon, private val callback: OnUserInteractedCallback) : RecyclerView.Adapter<CommentsRecyclerViewAdapter.CommentViewHolder>() {
|
class CommentsRecyclerViewAdapter(private var list: List<Comment>, private val markwon: Markwon, private val callback: OnUserInteractedCallback) : RecyclerView.Adapter<CommentsRecyclerViewAdapter.CommentViewHolder>() {
|
||||||
|
|
||||||
inner class CommentViewHolder(val viewBinding: CommentLayoutBinding) : RecyclerView.ViewHolder(viewBinding.root)
|
inner class CommentViewHolder(val viewBinding: CommentLayoutBinding) : RecyclerView.ViewHolder(viewBinding.root)
|
||||||
|
|
||||||
@ -23,21 +24,21 @@ class CommentsRecyclerViewAdapter(private var list: List<CommentDto>, private va
|
|||||||
override fun onBindViewHolder(holder: CommentViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: CommentViewHolder, position: Int) {
|
||||||
val comment = list[position]
|
val comment = list[position]
|
||||||
|
|
||||||
holder.viewBinding.textViewDate.text = comment.comment.date
|
holder.viewBinding.textViewDate.text = comment.date
|
||||||
markwon.setMarkdown(holder.viewBinding.postContent, comment.comment.textContent)
|
markwon.setMarkdown(holder.viewBinding.postContent, comment.textContent)
|
||||||
holder.viewBinding.textViewUsername.text = comment.username
|
holder.viewBinding.textViewUsername.text = comment.username
|
||||||
holder.viewBinding.textViewUsername.setOnClickListener {
|
holder.viewBinding.textViewUsername.setOnClickListener {
|
||||||
callback.onProfileClick(comment.comment.userId)
|
callback.onProfileClick(comment.userId)
|
||||||
}
|
}
|
||||||
holder.viewBinding.moreButton.setOnClickListener {
|
holder.viewBinding.moreButton.setOnClickListener {
|
||||||
callback.onOptions(comment.comment.id)
|
callback.onOptions(comment)
|
||||||
}
|
}
|
||||||
Picasso.get()
|
Picasso.get()
|
||||||
.load(UrlGen.userProfileImage(comment.comment.userId))
|
.load(UrlGen.userProfileImage(comment.userId))
|
||||||
.into(holder.viewBinding.avatarPicture)
|
.into(holder.viewBinding.avatarPicture)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun submitList(commentDtoList: List<CommentDto>) {
|
fun submitList(commentDtoList: List<Comment>) {
|
||||||
val lastIndex = if(list.count() - 1 < 1) 0 else list.count() - 1
|
val lastIndex = if(list.count() - 1 < 1) 0 else list.count() - 1
|
||||||
list = commentDtoList
|
list = commentDtoList
|
||||||
notifyItemRangeChanged(lastIndex, commentDtoList.count())
|
notifyItemRangeChanged(lastIndex, commentDtoList.count())
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.isolaatti.posting.comments.data.remote.CommentDto
|
import com.isolaatti.posting.comments.data.remote.CommentDto
|
||||||
|
import com.isolaatti.posting.comments.domain.model.Comment
|
||||||
import com.isolaatti.posting.comments.domain.use_case.GetComments
|
import com.isolaatti.posting.comments.domain.use_case.GetComments
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -16,9 +17,9 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class CommentsViewModel @Inject constructor(private val getComments: GetComments) : ViewModel() {
|
class CommentsViewModel @Inject constructor(private val getComments: GetComments) : ViewModel() {
|
||||||
private val _comments: MutableLiveData<List<CommentDto>> = MutableLiveData()
|
private val _comments: MutableLiveData<List<Comment>> = MutableLiveData()
|
||||||
|
|
||||||
val comments: LiveData<List<CommentDto>> get() = _comments
|
val comments: LiveData<List<Comment>> get() = _comments
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* postId to query comments for. First page will be fetched when set.
|
* postId to query comments for. First page will be fetched when set.
|
||||||
@ -36,10 +37,10 @@ class CommentsViewModel @Inject constructor(private val getComments: GetComments
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
getComments(postId, lastId).onEach {
|
getComments(postId, lastId).onEach {
|
||||||
val newList = _comments.value?.toMutableList() ?: mutableListOf()
|
val newList = _comments.value?.toMutableList() ?: mutableListOf()
|
||||||
newList.addAll(it.data)
|
newList.addAll(it)
|
||||||
_comments.postValue(newList)
|
_comments.postValue(newList)
|
||||||
if(it.data.isNotEmpty()){
|
if(it.isNotEmpty()){
|
||||||
lastId = it.data.last().comment.id
|
lastId = it.last().id
|
||||||
}
|
}
|
||||||
|
|
||||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
@ -49,8 +50,8 @@ class CommentsViewModel @Inject constructor(private val getComments: GetComments
|
|||||||
/**
|
/**
|
||||||
* Use when new comment has been posted
|
* Use when new comment has been posted
|
||||||
*/
|
*/
|
||||||
fun putCommentAtTheBeginning(commentDto: CommentDto) {
|
fun putCommentAtTheBeginning(commentDto: Comment) {
|
||||||
val newList: MutableList<CommentDto> = mutableListOf(commentDto)
|
val newList: MutableList<Comment> = mutableListOf(commentDto)
|
||||||
newList.addAll(_comments.value ?: mutableListOf())
|
newList.addAll(_comments.value ?: mutableListOf())
|
||||||
_comments.postValue(newList)
|
_comments.postValue(newList)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.isolaatti.posting.common.domain
|
package com.isolaatti.posting.common.domain
|
||||||
|
|
||||||
interface OnUserInteractedCallback {
|
interface OnUserInteractedCallback {
|
||||||
fun onOptions(postId: Long)
|
fun onOptions(postId: Ownable)
|
||||||
fun onProfileClick(userId: Int)
|
fun onProfileClick(userId: Int)
|
||||||
fun onLoadMore()
|
fun onLoadMore()
|
||||||
}
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.isolaatti.posting.common.domain
|
||||||
|
|
||||||
|
interface Ownable {
|
||||||
|
val userId: Int
|
||||||
|
}
|
||||||
@ -21,6 +21,8 @@ data class Options(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val POST_OPTIONS = 1
|
||||||
|
|
||||||
val noOptions = Options(0, listOf())
|
val noOptions = Options(0, listOf())
|
||||||
val myPostOptions = Options(R.string.post_options_title, listOf(
|
val myPostOptions = Options(R.string.post_options_title, listOf(
|
||||||
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
|
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
|
||||||
|
|||||||
@ -3,10 +3,21 @@ package com.isolaatti.posting.common.options_bottom_sheet.presentation
|
|||||||
import androidx.lifecycle.LiveData
|
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 com.isolaatti.posting.common.domain.Ownable
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
|
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
|
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
|
||||||
|
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options.Companion.POST_OPTIONS
|
||||||
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
|
import com.isolaatti.settings.domain.UserIdSetting
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class BottomSheetPostOptionsViewModel : ViewModel() {
|
@HiltViewModel
|
||||||
|
class BottomSheetPostOptionsViewModel @Inject constructor(private val userIdSetting: UserIdSetting) : ViewModel() {
|
||||||
private val _options: MutableLiveData<Options> = MutableLiveData()
|
private val _options: MutableLiveData<Options> = MutableLiveData()
|
||||||
val options: LiveData<Options> get() = _options
|
val options: LiveData<Options> get() = _options
|
||||||
|
|
||||||
@ -21,10 +32,28 @@ class BottomSheetPostOptionsViewModel : ViewModel() {
|
|||||||
_optionClicked.postValue(null)
|
_optionClicked.postValue(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOptions(options: Options, callerId: Int, payload: Any? = null) {
|
fun setOptions(options: Int, callerId: Int, payload: Ownable? = null) {
|
||||||
_options.postValue(options)
|
viewModelScope.launch {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
when(options) {
|
||||||
|
POST_OPTIONS -> {
|
||||||
|
userIdSetting.getUserId()?.let { userId ->
|
||||||
|
if(userId == payload?.userId) {
|
||||||
|
_options.postValue(Options.myPostOptions)
|
||||||
|
} else {
|
||||||
|
_options.postValue(Options.postOptions)
|
||||||
|
}
|
||||||
_callerId = callerId
|
_callerId = callerId
|
||||||
_payload = payload
|
_payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,18 +10,19 @@ import com.isolaatti.posting.posts.data.remote.FeedsApi
|
|||||||
import com.isolaatti.posting.posts.data.remote.PostApi
|
import com.isolaatti.posting.posts.data.remote.PostApi
|
||||||
import com.isolaatti.posting.posts.data.remote.PostDeletedDto
|
import com.isolaatti.posting.posts.data.remote.PostDeletedDto
|
||||||
import com.isolaatti.posting.posts.domain.PostsRepository
|
import com.isolaatti.posting.posts.domain.PostsRepository
|
||||||
|
import com.isolaatti.posting.posts.domain.entity.Post
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
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<MutableList<Post>>> = flow {
|
||||||
emit(Resource.Loading())
|
emit(Resource.Loading())
|
||||||
try {
|
try {
|
||||||
val result = feedsApi.getChronology(lastId, 20).execute()
|
val result = feedsApi.getChronology(lastId, 20).execute()
|
||||||
if(result.isSuccessful) {
|
if(result.isSuccessful) {
|
||||||
emit(Resource.Success(result.body()))
|
emit(Resource.Success(result.body()?.let { Post.fromFeedDto(it) }))
|
||||||
return@flow
|
return@flow
|
||||||
}
|
}
|
||||||
when(result.code()) {
|
when(result.code()) {
|
||||||
@ -35,13 +36,13 @@ 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<MutableList<Post>>> = flow {
|
||||||
emit(Resource.Loading())
|
emit(Resource.Loading())
|
||||||
try {
|
try {
|
||||||
val gson = Gson()
|
val gson = Gson()
|
||||||
val result = feedsApi.postsOfUser(userId, 20, lastId, olderFirst, gson.toJson(filter)).execute()
|
val result = feedsApi.postsOfUser(userId, 20, lastId, olderFirst, gson.toJson(filter)).execute()
|
||||||
if(result.isSuccessful) {
|
if(result.isSuccessful) {
|
||||||
emit(Resource.Success(result.body()))
|
emit(Resource.Success(result.body()?.let { Post.fromFeedDto(it) }))
|
||||||
return@flow
|
return@flow
|
||||||
}
|
}
|
||||||
when(result.code()) {
|
when(result.code()) {
|
||||||
|
|||||||
@ -5,14 +5,15 @@ import com.isolaatti.posting.posts.data.remote.EditPostDto
|
|||||||
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.data.remote.PostDeletedDto
|
import com.isolaatti.posting.posts.data.remote.PostDeletedDto
|
||||||
|
import com.isolaatti.posting.posts.domain.entity.Post
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface PostsRepository {
|
interface PostsRepository {
|
||||||
|
|
||||||
fun getFeed(lastId: Long): Flow<Resource<FeedDto>>
|
fun getFeed(lastId: Long): Flow<Resource<MutableList<Post>>>
|
||||||
|
|
||||||
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<MutableList<Post>>>
|
||||||
|
|
||||||
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,40 @@
|
|||||||
|
package com.isolaatti.posting.posts.domain.entity
|
||||||
|
|
||||||
|
import com.isolaatti.posting.common.domain.Ownable
|
||||||
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
|
|
||||||
|
data class Post(
|
||||||
|
val id: Long,
|
||||||
|
var textContent: String,
|
||||||
|
override val userId: Int,
|
||||||
|
val privacy: Int,
|
||||||
|
val date: String,
|
||||||
|
var audioId: String?,
|
||||||
|
val squadId: String?,
|
||||||
|
var numberOfLikes: Int,
|
||||||
|
var numberOfComments: Int,
|
||||||
|
val userName: String,
|
||||||
|
val squadName: String?,
|
||||||
|
var liked: Boolean
|
||||||
|
) : Ownable {
|
||||||
|
companion object {
|
||||||
|
fun fromFeedDto(feedDto: FeedDto): MutableList<Post> {
|
||||||
|
return feedDto.data.map {
|
||||||
|
Post(
|
||||||
|
id = it.post.id,
|
||||||
|
userId = it.post.userId,
|
||||||
|
textContent = it.post.textContent,
|
||||||
|
privacy = it.post.privacy,
|
||||||
|
date = it.post.date,
|
||||||
|
audioId = it.post.audioId,
|
||||||
|
squadId = it.post.squadId,
|
||||||
|
numberOfComments = it.numberOfComments,
|
||||||
|
numberOfLikes = it.numberOfLikes,
|
||||||
|
userName = it.userName,
|
||||||
|
squadName = it.squadName,
|
||||||
|
liked = it.liked
|
||||||
|
)
|
||||||
|
}.toMutableList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package com.isolaatti.posting.posts.presentation
|
package com.isolaatti.posting.posts.presentation
|
||||||
|
|
||||||
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
||||||
|
import com.isolaatti.posting.common.domain.Ownable
|
||||||
|
|
||||||
abstract class PostListingRecyclerViewAdapterWiring(private val postsViewModelBase: PostListingViewModelBase) : OnUserInteractedWithPostCallback {
|
abstract class PostListingRecyclerViewAdapterWiring(private val postsViewModelBase: PostListingViewModelBase) : OnUserInteractedWithPostCallback {
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ abstract class PostListingRecyclerViewAdapterWiring(private val postsViewModelBa
|
|||||||
|
|
||||||
abstract override fun onOpenPost(postId: Long)
|
abstract override fun onOpenPost(postId: Long)
|
||||||
|
|
||||||
abstract override fun onOptions(postId: Long)
|
abstract override fun onOptions(post: Ownable)
|
||||||
|
|
||||||
abstract override fun onProfileClick(userId: Int)
|
abstract override fun onProfileClick(userId: Int)
|
||||||
}
|
}
|
||||||
@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.isolaatti.posting.likes.domain.repository.LikesRepository
|
import com.isolaatti.posting.likes.domain.repository.LikesRepository
|
||||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
|
import com.isolaatti.posting.posts.domain.entity.Post
|
||||||
import com.isolaatti.posting.posts.domain.use_case.DeletePost
|
import com.isolaatti.posting.posts.domain.use_case.DeletePost
|
||||||
import com.isolaatti.profile.domain.use_case.GetProfilePosts
|
import com.isolaatti.profile.domain.use_case.GetProfilePosts
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
@ -24,8 +25,9 @@ abstract class PostListingViewModelBase : ViewModel() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var deletePostUseCase: DeletePost
|
lateinit var deletePostUseCase: DeletePost
|
||||||
|
|
||||||
val posts: MutableLiveData<Pair<FeedDto?, UpdateEvent>?> = MutableLiveData()
|
val posts: MutableLiveData<Pair<MutableList<Post>?, UpdateEvent>?> = MutableLiveData()
|
||||||
|
|
||||||
|
val postsList get() = posts.value?.first
|
||||||
|
|
||||||
val loadingPosts = MutableLiveData(false)
|
val loadingPosts = MutableLiveData(false)
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ abstract class PostListingViewModelBase : ViewModel() {
|
|||||||
val errorLoading: MutableLiveData<Resource.Error.ErrorType?> = MutableLiveData()
|
val errorLoading: MutableLiveData<Resource.Error.ErrorType?> = MutableLiveData()
|
||||||
var isLoadingFromScrolling = false
|
var isLoadingFromScrolling = false
|
||||||
|
|
||||||
fun getLastId(): Long = try { posts.value?.first?.data?.last()?.post?.id ?: 0 } catch (e: NoSuchElementException) { 0 }
|
fun getLastId(): Long = try { posts.value?.first?.last()?.id ?: 0 } catch (e: NoSuchElementException) { 0 }
|
||||||
|
|
||||||
|
|
||||||
abstract fun getFeed(refresh: Boolean)
|
abstract fun getFeed(refresh: Boolean)
|
||||||
@ -42,12 +44,12 @@ abstract class PostListingViewModelBase : ViewModel() {
|
|||||||
fun likePost(postId: Long) {
|
fun likePost(postId: Long) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
likesRepository.likePost(postId).onEach {likeDto ->
|
likesRepository.likePost(postId).onEach {likeDto ->
|
||||||
val likedPost = posts.value?.first?.data?.find { post -> post.post.id == likeDto.postId }
|
val likedPost = posts.value?.first?.find { post -> post.id == likeDto.postId }
|
||||||
val index = posts.value?.first?.data?.indexOf(likedPost)
|
val index = posts.value?.first?.indexOf(likedPost)
|
||||||
if(index != null){
|
if(index != null){
|
||||||
val temp = posts.value?.first
|
val temp = posts.value?.first?.toMutableList()
|
||||||
Log.d("***", temp.toString())
|
Log.d("***", temp.toString())
|
||||||
temp?.data?.set(index, likedPost!!.apply {
|
temp?.set(index, likedPost!!.apply {
|
||||||
liked = true
|
liked = true
|
||||||
numberOfLikes = likeDto.likesCount
|
numberOfLikes = likeDto.likesCount
|
||||||
|
|
||||||
@ -61,10 +63,11 @@ abstract class PostListingViewModelBase : ViewModel() {
|
|||||||
fun unLikePost(postId: Long) {
|
fun unLikePost(postId: Long) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
likesRepository.unLikePost(postId).onEach {likeDto ->
|
likesRepository.unLikePost(postId).onEach {likeDto ->
|
||||||
val likedPost = posts.value?.first?.data?.find { post -> post.post.id == likeDto.postId }
|
val likedPost = posts.value?.first?.find { post -> post.id == likeDto.postId }
|
||||||
val index = posts.value?.first?.data?.indexOf(likedPost)
|
val index = posts.value?.first?.indexOf(likedPost)
|
||||||
if(index != null){
|
if(index != null){
|
||||||
posts.value?.first?.data?.set(index, likedPost!!.apply {
|
val temp = posts.value?.first?.toMutableList()
|
||||||
|
temp?.set(index, likedPost!!.apply {
|
||||||
liked = false
|
liked = false
|
||||||
numberOfLikes = likeDto.likesCount
|
numberOfLikes = likeDto.likesCount
|
||||||
})
|
})
|
||||||
@ -79,11 +82,11 @@ abstract class PostListingViewModelBase : ViewModel() {
|
|||||||
deletePostUseCase(postId).onEach { res ->
|
deletePostUseCase(postId).onEach { res ->
|
||||||
when(res) {
|
when(res) {
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
val postDeleted = posts.value?.first?.data?.find { postDto -> postDto.post.id == postId }
|
val postDeleted = posts.value?.first?.find { post -> post.id == postId }
|
||||||
?: return@onEach
|
?: return@onEach
|
||||||
val index = posts.value?.first?.data?.indexOf(postDeleted)
|
val index = posts.value?.first?.indexOf(postDeleted)
|
||||||
|
|
||||||
posts.value?.first?.data?.removeAt(index!!)
|
posts.value?.first?.removeAt(index!!)
|
||||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_REMOVED, index)))
|
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_REMOVED, index)))
|
||||||
}
|
}
|
||||||
is Resource.Loading -> {}
|
is Resource.Loading -> {}
|
||||||
|
|||||||
@ -12,15 +12,16 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
|||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
|
||||||
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
||||||
|
import com.isolaatti.posting.posts.domain.entity.Post
|
||||||
import com.isolaatti.utils.UrlGen.userProfileImage
|
import com.isolaatti.utils.UrlGen.userProfileImage
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
|
|
||||||
class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callback: OnUserInteractedWithPostCallback, private var feedDto: FeedDto?) : RecyclerView.Adapter<PostsRecyclerViewAdapter.FeedViewHolder>(){
|
class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callback: OnUserInteractedWithPostCallback) : RecyclerView.Adapter<PostsRecyclerViewAdapter.FeedViewHolder>(){
|
||||||
|
private var postList: List<Post>? = null
|
||||||
inner class FeedViewHolder(itemView: View) : ViewHolder(itemView) {
|
inner class FeedViewHolder(itemView: View) : ViewHolder(itemView) {
|
||||||
fun bindView(postDto: FeedDto.PostDto, payloads: List<Any>) {
|
fun bindView(postDto: Post, payloads: List<Any>) {
|
||||||
|
|
||||||
Log.d("payloads", payloads.count().toString())
|
Log.d("payloads", payloads.count().toString())
|
||||||
val likeButton: MaterialButton = itemView.findViewById(R.id.like_button)
|
val likeButton: MaterialButton = itemView.findViewById(R.id.like_button)
|
||||||
@ -59,17 +60,17 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
|
|||||||
val username: TextView = itemView.findViewById(R.id.text_view_username)
|
val username: TextView = itemView.findViewById(R.id.text_view_username)
|
||||||
username.text = postDto.userName
|
username.text = postDto.userName
|
||||||
username.setOnClickListener {
|
username.setOnClickListener {
|
||||||
callback.onProfileClick(postDto.post.userId)
|
callback.onProfileClick(postDto.userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
val profileImageView: ImageView = itemView.findViewById(R.id.avatar_picture)
|
val profileImageView: ImageView = itemView.findViewById(R.id.avatar_picture)
|
||||||
Picasso.get().load(userProfileImage(postDto.post.userId)).into(profileImageView)
|
Picasso.get().load(userProfileImage(postDto.userId)).into(profileImageView)
|
||||||
|
|
||||||
val dateTextView: TextView = itemView.findViewById(R.id.text_view_date)
|
val dateTextView: TextView = itemView.findViewById(R.id.text_view_date)
|
||||||
dateTextView.text = postDto.post.date
|
dateTextView.text = postDto.date
|
||||||
|
|
||||||
val content: TextView = itemView.findViewById(R.id.post_content)
|
val content: TextView = itemView.findViewById(R.id.post_content)
|
||||||
markwon.setMarkdown(content, postDto.post.textContent)
|
markwon.setMarkdown(content, postDto.textContent)
|
||||||
|
|
||||||
likeButton.isEnabled = true
|
likeButton.isEnabled = true
|
||||||
|
|
||||||
@ -87,23 +88,23 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
|
|||||||
|
|
||||||
val moreButton: MaterialButton = itemView.findViewById(R.id.more_button)
|
val moreButton: MaterialButton = itemView.findViewById(R.id.more_button)
|
||||||
moreButton.setOnClickListener {
|
moreButton.setOnClickListener {
|
||||||
callback.onOptions(postDto.post.id)
|
callback.onOptions(postDto)
|
||||||
}
|
}
|
||||||
|
|
||||||
likeButton.setOnClickListener {
|
likeButton.setOnClickListener {
|
||||||
likeButton.isEnabled = false
|
likeButton.isEnabled = false
|
||||||
if(postDto.liked){
|
if(postDto.liked){
|
||||||
callback.onUnLiked(postDto.post.id)
|
callback.onUnLiked(postDto.id)
|
||||||
} else {
|
} else {
|
||||||
callback.onLiked(postDto.post.id)
|
callback.onLiked(postDto.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commentsButton.setOnClickListener {
|
commentsButton.setOnClickListener {
|
||||||
callback.onComment(postDto.post.id)
|
callback.onComment(postDto.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
itemView.findViewById<MaterialCardView>(R.id.card).setOnClickListener {
|
itemView.findViewById<MaterialCardView>(R.id.card).setOnClickListener {
|
||||||
callback.onOpenPost(postDto.post.id)
|
callback.onOpenPost(postDto.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -122,25 +123,25 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
|
|||||||
}
|
}
|
||||||
|
|
||||||
var previousSize = 0
|
var previousSize = 0
|
||||||
override fun getItemCount(): Int = feedDto?.data?.size ?: 0
|
override fun getItemCount(): Int = postList?.size ?: 0
|
||||||
|
|
||||||
|
|
||||||
override fun setHasStableIds(hasStableIds: Boolean) {
|
override fun setHasStableIds(hasStableIds: Boolean) {
|
||||||
super.setHasStableIds(true)
|
super.setHasStableIds(true)
|
||||||
}
|
}
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
fun updateList(updatedFeed: FeedDto, updateEvent: UpdateEvent? = null) {
|
fun updateList(updatedFeed: List<Post>, updateEvent: UpdateEvent? = null) {
|
||||||
if(updateEvent == null) {
|
if(updateEvent == null) {
|
||||||
feedDto = updatedFeed
|
postList = updatedFeed
|
||||||
|
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val postUpdated = updateEvent.affectedPosition?.let { feedDto?.data?.get(it) }
|
val postUpdated = updateEvent.affectedPosition?.let { postList?.get(it) }
|
||||||
val position = updateEvent.affectedPosition
|
val position = updateEvent.affectedPosition
|
||||||
|
|
||||||
previousSize = itemCount
|
previousSize = itemCount
|
||||||
feedDto = updatedFeed
|
postList = updatedFeed
|
||||||
|
|
||||||
when(updateEvent.updateType) {
|
when(updateEvent.updateType) {
|
||||||
UpdateEvent.UpdateType.POST_LIKED -> {
|
UpdateEvent.UpdateType.POST_LIKED -> {
|
||||||
@ -179,8 +180,8 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
|
|||||||
requestedNewContent = false
|
requestedNewContent = false
|
||||||
}
|
}
|
||||||
override fun onBindViewHolder(holder: FeedViewHolder, position: Int, payloads: List<Any>) {
|
override fun onBindViewHolder(holder: FeedViewHolder, position: Int, payloads: List<Any>) {
|
||||||
holder.bindView(feedDto?.data?.get(position) ?: return, payloads)
|
holder.bindView(postList?.get(position) ?: return, payloads)
|
||||||
val totalItems = feedDto?.data?.size
|
val totalItems = postList?.size
|
||||||
if(totalItems != null && totalItems > 0 && !requestedNewContent) {
|
if(totalItems != null && totalItems > 0 && !requestedNewContent) {
|
||||||
if(position == totalItems - 1) {
|
if(position == totalItems - 1) {
|
||||||
requestedNewContent = true
|
requestedNewContent = true
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
package com.isolaatti.profile.domain.use_case
|
package com.isolaatti.profile.domain.use_case
|
||||||
|
|
||||||
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.domain.PostsRepository
|
import com.isolaatti.posting.posts.domain.PostsRepository
|
||||||
|
import com.isolaatti.posting.posts.domain.entity.Post
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
import kotlinx.coroutines.flow.Flow
|
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<MutableList<Post>>> =
|
||||||
postsRepository.getProfilePosts(userId, lastId, olderFirst, filter)
|
postsRepository.getProfilePosts(userId, lastId, olderFirst, filter)
|
||||||
}
|
}
|
||||||
@ -65,8 +65,8 @@ class ProfileViewModel @Inject constructor(private val getProfileUseCase: GetPro
|
|||||||
when (feedDtoResource) {
|
when (feedDtoResource) {
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
loadingPosts.postValue(false)
|
loadingPosts.postValue(false)
|
||||||
posts.postValue(Pair(posts.value?.first?.concatFeed(feedDtoResource.data) ?: feedDtoResource.data, UpdateEvent(if(refresh) UpdateEvent.UpdateType.REFRESH else UpdateEvent.UpdateType.PAGE_ADDED, null)))
|
posts.postValue(Pair(posts.value?.first?.apply { addAll(feedDtoResource.data ?: listOf()) } ?: feedDtoResource.data, UpdateEvent(if(refresh) UpdateEvent.UpdateType.REFRESH else UpdateEvent.UpdateType.PAGE_ADDED, null)))
|
||||||
noMoreContent.postValue(feedDtoResource.data?.moreContent == false)
|
noMoreContent.postValue(feedDtoResource.data?.size == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Loading -> {
|
is Resource.Loading -> {
|
||||||
|
|||||||
@ -18,10 +18,12 @@ import com.isolaatti.followers.domain.FollowingState
|
|||||||
import com.isolaatti.home.FeedFragment
|
import com.isolaatti.home.FeedFragment
|
||||||
import com.isolaatti.posting.PostViewerActivity
|
import com.isolaatti.posting.PostViewerActivity
|
||||||
import com.isolaatti.posting.comments.presentation.BottomSheetPostComments
|
import com.isolaatti.posting.comments.presentation.BottomSheetPostComments
|
||||||
|
import com.isolaatti.posting.common.domain.Ownable
|
||||||
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
|
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.data.remote.FeedDto
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
|
import com.isolaatti.posting.posts.domain.entity.Post
|
||||||
import com.isolaatti.posting.posts.presentation.PostListingRecyclerViewAdapterWiring
|
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.posting.posts.presentation.UpdateEvent
|
||||||
@ -67,7 +69,7 @@ class ProfileMainFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val postsObserver: Observer<Pair<FeedDto?, UpdateEvent>?> = Observer {
|
private val postsObserver: Observer<Pair<List<Post>?, UpdateEvent>?> = Observer {
|
||||||
if(it?.first != null) {
|
if(it?.first != null) {
|
||||||
postsAdapter.updateList(it.first!!, it.second)
|
postsAdapter.updateList(it.first!!, it.second)
|
||||||
postsAdapter.newContentRequestFinished()
|
postsAdapter.newContentRequestFinished()
|
||||||
@ -188,7 +190,7 @@ class ProfileMainFragment : Fragment() {
|
|||||||
.usePlugin(LinkifyPlugin.create())
|
.usePlugin(LinkifyPlugin.create())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
postsAdapter = PostsRecyclerViewAdapter(markwon,postListingRecyclerViewAdapterWiring, null )
|
postsAdapter = PostsRecyclerViewAdapter(markwon,postListingRecyclerViewAdapterWiring )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,8 +212,8 @@ class ProfileMainFragment : Fragment() {
|
|||||||
PostViewerActivity.startActivity(requireContext(), postId)
|
PostViewerActivity.startActivity(requireContext(), postId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptions(postId: Long) {
|
override fun onOptions(post: Ownable) {
|
||||||
optionsViewModel.setOptions(Options.myPostOptions, FeedFragment.CALLER_ID, postId)
|
optionsViewModel.setOptions(Options.POST_OPTIONS, FeedFragment.CALLER_ID, post)
|
||||||
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
||||||
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package com.isolaatti.settings
|
|||||||
|
|
||||||
import com.isolaatti.database.AppDatabase
|
import com.isolaatti.database.AppDatabase
|
||||||
import com.isolaatti.settings.data.KeyValueDao
|
import com.isolaatti.settings.data.KeyValueDao
|
||||||
|
import com.isolaatti.settings.data.SettingsRepositoryImpl
|
||||||
|
import com.isolaatti.settings.domain.SettingsRepository
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
@ -14,4 +16,9 @@ class Module {
|
|||||||
fun provideKeyValueDao(database: AppDatabase): KeyValueDao {
|
fun provideKeyValueDao(database: AppDatabase): KeyValueDao {
|
||||||
return database.keyValueDao()
|
return database.keyValueDao()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun provideSettingsRepository(keyValueDao: KeyValueDao): SettingsRepository {
|
||||||
|
return SettingsRepositoryImpl(keyValueDao)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -8,8 +8,8 @@ import androidx.room.Query
|
|||||||
@Dao
|
@Dao
|
||||||
interface KeyValueDao {
|
interface KeyValueDao {
|
||||||
@Query("SELECT value FROM key_values WHERE id = :key")
|
@Query("SELECT value FROM key_values WHERE id = :key")
|
||||||
fun getValue(key: String): String
|
suspend fun getValue(key: String): String
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
fun setValue(entity: KeyValueEntity)
|
suspend fun setValue(entity: KeyValueEntity)
|
||||||
}
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.isolaatti.settings.data
|
||||||
|
|
||||||
|
import com.isolaatti.settings.domain.SettingsRepository
|
||||||
|
|
||||||
|
class SettingsRepositoryImpl(private val keyValueDao: KeyValueDao) : SettingsRepository {
|
||||||
|
override suspend fun setKeyValue(key: String, value: String) {
|
||||||
|
keyValueDao.setValue(KeyValueEntity(key, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getKeyValue(key: String): String? {
|
||||||
|
return keyValueDao.getValue(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
package com.isolaatti.settings.domain
|
||||||
|
|
||||||
|
interface SettingsRepository {
|
||||||
|
suspend fun setKeyValue(key: String, value: String)
|
||||||
|
suspend fun getKeyValue(key: String): String?
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.isolaatti.settings.domain
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class UserIdSetting @Inject constructor(private val settingsRepository: SettingsRepository) {
|
||||||
|
suspend fun getUserId(): Int? {
|
||||||
|
return settingsRepository.getKeyValue(KEY_USER_ID)?.toIntOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun setUserId(userId: Int) {
|
||||||
|
settingsRepository.setKeyValue(KEY_USER_ID, userId.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val KEY_USER_ID = "userId"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user