This commit is contained in:
Erik Cavazos 2023-09-12 22:31:52 -06:00
parent a763926c18
commit 0a8946167f
29 changed files with 240 additions and 150 deletions

View File

@ -1,4 +1,4 @@
package com.isolaatti.posting.common.domain
package com.isolaatti.common
interface OnUserInteractedCallback {
fun onOptions(postId: Ownable)

View File

@ -1,4 +1,4 @@
package com.isolaatti.posting.common.domain
package com.isolaatti.common
interface OnUserInteractedWithPostCallback : OnUserInteractedCallback {
fun onLiked(postId: Long)

View File

@ -0,0 +1,5 @@
package com.isolaatti.common
interface Ownable {
val userId: Int
}

View File

@ -0,0 +1,9 @@
package com.isolaatti.common.options_bottom_sheet.domain
/**
* @param optionsId Identify what dialog it is
* @param optionId Identify action
* @param callerId Identify who started dialog
* @param payload Data to identify on what item perform action
*/
data class OptionClicked(val optionsId: Int, val optionId: Int, val callerId: Int, val payload: Any? = null)

View File

@ -1,4 +1,4 @@
package com.isolaatti.posting.common.options_bottom_sheet.domain
package com.isolaatti.common.options_bottom_sheet.domain
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
@ -6,6 +6,7 @@ import com.isolaatti.R
data class Options(
@StringRes val title: Int,
val id: Int,
val items: List<Option>
) {
data class Option(
@ -19,14 +20,18 @@ data class Options(
const val OPTION_REPORT = 3
const val OPTION_SAVE = 4
const val OPTION_SNAPSHOT = 5
const val OPTION_PROFILE_PHOTO_VIEW_PHOTO = 6
const val OPTION_PROFILE_PHOTO_CHANGE_PHOTO = 7
const val OPTION_PROFILE_PHOTO_REMOVE_PHOTO = 8
}
}
companion object {
const val POST_OPTIONS = 1
const val COMMENT_OPTIONS = 2
const val PROFILE_PHOTO_OPTIONS = 3
val noOptions = Options(0, listOf())
val noOptions = Options(0, 0, listOf())
fun getPostsOptions(userOwned: Boolean, savable: Boolean, snapshotAble: Boolean): Options {
val list = mutableListOf(
@ -36,7 +41,8 @@ data class Options(
if(userOwned) {
list.addAll(listOf(
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT))
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT)
)
)
}
@ -48,7 +54,7 @@ data class Options(
list.add(Option(R.string.save_snapshot, R.drawable.baseline_download_24, Option.OPTION_SNAPSHOT))
}
return Options(R.string.post_options_title, list)
return Options(R.string.post_options_title, POST_OPTIONS, list)
}
fun getCommentOptions(userOwned: Boolean, savable: Boolean, snapshotAble: Boolean): Options {
@ -59,7 +65,8 @@ data class Options(
if(userOwned) {
list.addAll(listOf(
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT))
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT)
)
)
}
@ -71,7 +78,20 @@ data class Options(
list.add(Option(R.string.save_snapshot, R.drawable.baseline_download_24, Option.OPTION_SNAPSHOT))
}
return Options(R.string.comment_options, list)
return Options(R.string.comment_options, COMMENT_OPTIONS, list)
}
fun getProfilePhotoOptions(userOwned: Boolean): Options {
val list = mutableListOf(Option(R.string.view_photo, R.drawable.baseline_image_24, Option.OPTION_PROFILE_PHOTO_VIEW_PHOTO))
if(userOwned) {
list.addAll(listOf(
Option(R.string.change_profile_photo, R.drawable.baseline_edit_24, Option.OPTION_PROFILE_PHOTO_CHANGE_PHOTO),
Option(R.string.remove_photo, R.drawable.baseline_remove_circle_24, Option.OPTION_PROFILE_PHOTO_REMOVE_PHOTO)
))
}
return Options(R.string.profile_photo,PROFILE_PHOTO_OPTIONS, list)
}
}
}

View File

@ -1,15 +1,15 @@
package com.isolaatti.posting.common.options_bottom_sheet.presentation
package com.isolaatti.common.options_bottom_sheet.presentation
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
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.Options
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options.Companion.COMMENT_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.common.Ownable
import com.isolaatti.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.common.options_bottom_sheet.domain.Options
import com.isolaatti.common.options_bottom_sheet.domain.Options.Companion.COMMENT_OPTIONS
import com.isolaatti.common.options_bottom_sheet.domain.Options.Companion.POST_OPTIONS
import com.isolaatti.common.options_bottom_sheet.domain.Options.Companion.PROFILE_PHOTO_OPTIONS
import com.isolaatti.settings.domain.UserIdSetting
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineScope
@ -39,7 +39,8 @@ class BottomSheetPostOptionsViewModel @Inject constructor(private val userIdSett
when(options) {
POST_OPTIONS -> {
userIdSetting.getUserId()?.let { userId ->
_options.postValue(Options.getPostsOptions(
_options.postValue(
Options.getPostsOptions(
userOwned = userId == payload?.userId,
savable = false,
snapshotAble = false)
@ -50,7 +51,8 @@ class BottomSheetPostOptionsViewModel @Inject constructor(private val userIdSett
}
COMMENT_OPTIONS -> {
userIdSetting.getUserId()?.let { userId ->
_options.postValue(Options.getCommentOptions(
_options.postValue(
Options.getCommentOptions(
userOwned = userId == payload?.userId,
savable = false,
snapshotAble = false)
@ -59,13 +61,20 @@ class BottomSheetPostOptionsViewModel @Inject constructor(private val userIdSett
_payload = payload
}
}
PROFILE_PHOTO_OPTIONS -> {
userIdSetting.getUserId()?.let { userId ->
_options.postValue(Options.getProfilePhotoOptions(userOwned = userId == payload?.userId,))
_callerId = callerId
_payload = payload
}
}
}
}
}
}
fun optionClicked(optionId: Int) {
_optionClicked.postValue(OptionClicked(optionId, _callerId, _payload))
fun optionClicked(optionsId: Int, optionId: Int) {
_optionClicked.postValue(OptionClicked(optionsId, optionId, _callerId, _payload))
}
}

View File

@ -1,4 +1,4 @@
package com.isolaatti.posting.common.options_bottom_sheet.presentation
package com.isolaatti.common.options_bottom_sheet.presentation
import android.view.LayoutInflater
import android.view.ViewGroup
@ -6,14 +6,14 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import com.isolaatti.databinding.OptionItemBinding
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
import com.isolaatti.common.options_bottom_sheet.domain.Options
class OptionsRecyclerAdapter(val options: List<Options.Option>, private val optionCallback: OptionsCallback) : RecyclerView.Adapter<OptionsRecyclerAdapter.OptionViewHolder>() {
class OptionsRecyclerAdapter(val optionsId: Int, val options: List<Options.Option>, private val optionCallback: OptionsCallback) : RecyclerView.Adapter<OptionsRecyclerAdapter.OptionViewHolder>() {
inner class OptionViewHolder(val viewBinding: OptionItemBinding) : RecyclerView.ViewHolder(viewBinding.root)
fun interface OptionsCallback {
fun optionClicked(optionId: Int)
fun optionClicked(optionsId:Int, optionId: Int)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OptionViewHolder {
@ -34,7 +34,7 @@ class OptionsRecyclerAdapter(val options: List<Options.Option>, private val opti
text = context.getText(options[position].stringRes)
icon = AppCompatResources.getDrawable(context, options[position].icon)
setOnClickListener {
optionCallback.optionClicked(options[position].optionId)
optionCallback.optionClicked(optionsId, options[position].optionId)
}
}
}

View File

@ -1,4 +1,4 @@
package com.isolaatti.posting.common.options_bottom_sheet.ui
package com.isolaatti.common.options_bottom_sheet.ui
import android.os.Bundle
import android.util.Log
@ -15,9 +15,9 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton
import com.isolaatti.R
import com.isolaatti.databinding.BottomSheetPostOptionsBinding
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.OptionsRecyclerAdapter
import com.isolaatti.common.options_bottom_sheet.domain.Options
import com.isolaatti.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.common.options_bottom_sheet.presentation.OptionsRecyclerAdapter
class BottomSheetPostOptionsFragment : BottomSheetDialogFragment(), OptionsRecyclerAdapter.OptionsCallback {
private lateinit var viewBinding: BottomSheetPostOptionsBinding
@ -56,7 +56,7 @@ class BottomSheetPostOptionsFragment : BottomSheetDialogFragment(), OptionsRecyc
private fun renderOptions(options: Options) {
viewBinding.title.text = requireContext().getText(options.title)
viewBinding.recyclerOptions.adapter = OptionsRecyclerAdapter(options.items, this)
viewBinding.recyclerOptions.adapter = OptionsRecyclerAdapter(options.id, options.items, this)
viewBinding.recyclerOptions.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
}
@ -66,7 +66,7 @@ class BottomSheetPostOptionsFragment : BottomSheetDialogFragment(), OptionsRecyc
}
override fun optionClicked(optionId: Int) {
viewModel.optionClicked(optionId)
override fun optionClicked(optionsId:Int, optionId: Int) {
viewModel.optionClicked(optionsId, optionId)
}
}

View File

@ -27,12 +27,12 @@ import com.isolaatti.home.presentation.FeedViewModel
import com.isolaatti.images.picture_viewer.ui.PictureViewerActivity
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
import com.isolaatti.posting.comments.ui.BottomSheetPostComments
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.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.common.OnUserInteractedWithPostCallback
import com.isolaatti.common.Ownable
import com.isolaatti.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.common.options_bottom_sheet.domain.Options
import com.isolaatti.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.posting.posts.presentation.CreatePostContract
import com.isolaatti.posting.posts.presentation.EditPostContract
@ -194,14 +194,14 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
val textViewName: TextView? = header?.findViewById(R.id.textViewName)
val textViewEmail: TextView? = header?.findViewById(R.id.textViewEmail)
Picasso.get().load(UrlGen.userProfileImage(it.id)).into(image)
Picasso.get().load(UrlGen.userProfileImage(it.userId)).into(image)
image?.setOnClickListener {_ ->
PictureViewerActivity.startActivityWithUrls(requireContext(), arrayOf(UrlGen.userProfileImageFullQuality(it.id)))
PictureViewerActivity.startActivityWithUrls(requireContext(), arrayOf(UrlGen.userProfileImageFullQuality(it.userId)))
}
textViewName?.text = it.name
textViewEmail?.text = it.email
currentUserId = it.id
currentUserId = it.userId
}

View File

@ -8,6 +8,7 @@ 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.domain.entity.UserProfile
import com.isolaatti.profile.domain.use_case.GetProfile
import com.isolaatti.utils.Resource
import dagger.hilt.android.lifecycle.HiltViewModel
@ -75,8 +76,8 @@ class FeedViewModel @Inject constructor(
}
// User profile
private val _userProfile: MutableLiveData<UserProfileDto> = MutableLiveData()
val userProfile: LiveData<UserProfileDto> get() = _userProfile
private val _userProfile: MutableLiveData<UserProfile> = MutableLiveData()
val userProfile: LiveData<UserProfile> get() = _userProfile
fun getProfile() {
viewModelScope.launch {

View File

@ -2,8 +2,7 @@ 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
import com.isolaatti.common.Ownable
data class Comment(
val id: Long,

View File

@ -5,10 +5,8 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.isolaatti.databinding.CommentLayoutBinding
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.posts.presentation.PostsRecyclerViewAdapter
import com.isolaatti.common.OnUserInteractedCallback
import com.isolaatti.utils.UrlGen
import com.squareup.picasso.Picasso
import io.noties.markwon.Markwon

View File

@ -1,12 +1,10 @@
package com.isolaatti.posting.comments.ui
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.doOnLayout
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
@ -15,9 +13,7 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HALF_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.isolaatti.R
@ -28,12 +24,12 @@ import com.isolaatti.posting.comments.domain.model.Comment
import com.isolaatti.posting.comments.presentation.CommentsRecyclerViewAdapter
import com.isolaatti.posting.comments.presentation.CommentsViewModel
import com.isolaatti.posting.comments.presentation.UpdateEvent
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.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.common.OnUserInteractedCallback
import com.isolaatti.common.Ownable
import com.isolaatti.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.common.options_bottom_sheet.domain.Options
import com.isolaatti.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.profile.ui.ProfileActivity
import com.isolaatti.utils.PicassoImagesPluginDef
import dagger.hilt.android.AndroidEntryPoint
@ -42,7 +38,6 @@ import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonConfiguration
import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute
import io.noties.markwon.linkify.LinkifyPlugin
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@AndroidEntryPoint

View File

@ -1,5 +0,0 @@
package com.isolaatti.posting.common.domain
interface Ownable {
val userId: Int
}

View File

@ -1,8 +0,0 @@
package com.isolaatti.posting.common.options_bottom_sheet.domain
/**
* @param optionId Identify action
* @param callerId Identify who started dialog
* @param payload Data to identify on what item perform action
*/
data class OptionClicked(val optionId: Int, val callerId: Int, val payload: Any? = null)

View File

@ -1,6 +1,6 @@
package com.isolaatti.posting.posts.domain.entity
import com.isolaatti.posting.common.domain.Ownable
import com.isolaatti.common.Ownable
import com.isolaatti.posting.posts.data.remote.FeedDto
data class Post(

View File

@ -1,9 +1,10 @@
package com.isolaatti.posting.posts.presentation
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
import com.isolaatti.posting.common.domain.Ownable
import com.isolaatti.common.OnUserInteractedWithPostCallback
import com.isolaatti.common.Ownable
abstract class PostListingRecyclerViewAdapterWiring(private val postsViewModelBase: PostListingViewModelBase) : OnUserInteractedWithPostCallback {
abstract class PostListingRecyclerViewAdapterWiring(private val postsViewModelBase: PostListingViewModelBase) :
OnUserInteractedWithPostCallback {
override fun onLiked(postId: Long) {
postsViewModelBase.likePost(postId)

View File

@ -12,7 +12,7 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.isolaatti.R
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
import com.isolaatti.common.OnUserInteractedWithPostCallback
import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.utils.UrlGen.userProfileImage
import com.squareup.picasso.Picasso

View File

@ -102,6 +102,11 @@ class PostViewerActivity : IsolaattiBaseActivity() {
binding.commentsInfo.setOnClickListener {
openComments()
}
binding.toolbar.setNavigationOnClickListener {
finish()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@ -3,7 +3,7 @@ package com.isolaatti.profile.data.remote
data class UserProfileDto(
val id: Int,
val name: String,
val email: String,
val email: String?,
val numberOfFollowers: Int,
val numberOfFollowing: Int,
val numberOfLikes: Int,

View File

@ -1,8 +1,9 @@
package com.isolaatti.profile.data.repository
import android.util.Log
import com.isolaatti.profile.data.remote.ProfileApi
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.profile.domain.ProfileRepository
import com.isolaatti.profile.domain.entity.UserProfile
import com.isolaatti.utils.Resource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
@ -10,15 +11,20 @@ import retrofit2.awaitResponse
import javax.inject.Inject
class ProfileRepositoryImpl @Inject constructor(private val profileApi: ProfileApi) : ProfileRepository {
override fun getProfile(userId: Int): Flow<Resource<UserProfileDto>> = flow {
override fun getProfile(userId: Int): Flow<Resource<UserProfile>> = flow {
try {
val result = profileApi.userProfile(userId).awaitResponse()
if(result.isSuccessful) {
emit(Resource.Success(result.body()))
return@flow
val dto = result.body()
if(dto != null) {
emit(Resource.Success(UserProfile.fromDto(dto)))
}
} else {
emit(Resource.Error(Resource.Error.mapErrorCode(result.code())))
} catch(_: Exception) {
}
} catch(e: Exception) {
Log.e("ProfileRepositoryImpl", e.message.toString())
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
}
}

View File

@ -1,10 +1,9 @@
package com.isolaatti.profile.domain
import com.isolaatti.profile.data.remote.ProfileApi
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.profile.domain.entity.UserProfile
import com.isolaatti.utils.Resource
import kotlinx.coroutines.flow.Flow
interface ProfileRepository {
fun getProfile(userId: Int): Flow<Resource<UserProfileDto>>
fun getProfile(userId: Int): Flow<Resource<UserProfile>>
}

View File

@ -0,0 +1,44 @@
package com.isolaatti.profile.domain.entity
import com.isolaatti.common.Ownable
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.utils.UrlGen
data class UserProfile(
override val userId: Int,
val name: String,
val email: String?,
val numberOfFollowers: Int,
val numberOfFollowing: Int,
val numberOfLikes: Int,
val numberOfPosts: Int,
val isUserItself: Boolean,
val followingThisUser: Boolean,
val thisUserIsFollowingMe: Boolean,
val profileImageId: String?,
val descriptionText: String?,
val descriptionAudioId: String?
) : Ownable {
val profileAvatarPictureUrl: String get() = UrlGen.userProfileImage(userId)
val profilePictureUrl: String get() = UrlGen.userProfileImageFullQuality(userId)
companion object {
fun fromDto(userProfileDto: UserProfileDto): UserProfile {
return UserProfile(
userId = userProfileDto.id,
name = userProfileDto.name,
email = userProfileDto.email,
numberOfFollowers = userProfileDto.numberOfFollowers,
numberOfFollowing = userProfileDto.numberOfFollowing,
numberOfLikes = userProfileDto.numberOfLikes,
numberOfPosts = userProfileDto.numberOfPosts,
isUserItself = userProfileDto.isUserItself,
followingThisUser = userProfileDto.followingThisUser,
thisUserIsFollowingMe = userProfileDto.thisUserIsFollowingMe,
profileImageId = userProfileDto.profileImageId,
descriptionText = userProfileDto.descriptionText,
descriptionAudioId = userProfileDto.descriptionAudioId
)
}
}
}

View File

@ -2,10 +2,11 @@ package com.isolaatti.profile.domain.use_case
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.profile.domain.ProfileRepository
import com.isolaatti.profile.domain.entity.UserProfile
import com.isolaatti.utils.Resource
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class GetProfile @Inject constructor(private val profileRepository: ProfileRepository) {
operator fun invoke(userId: Int): Flow<Resource<UserProfileDto>> = profileRepository.getProfile(userId)
operator fun invoke(userId: Int): Flow<Resource<UserProfile>> = profileRepository.getProfile(userId)
}

View File

@ -11,6 +11,7 @@ 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.domain.ProfileRepository
import com.isolaatti.profile.domain.entity.UserProfile
import com.isolaatti.profile.domain.use_case.GetProfile
import com.isolaatti.profile.domain.use_case.GetProfilePosts
import com.isolaatti.utils.Resource
@ -28,8 +29,8 @@ import javax.inject.Inject
@HiltViewModel
class ProfileViewModel @Inject constructor(private val getProfileUseCase: GetProfile, private val getProfilePostsUseCase: GetProfilePosts) : PostListingViewModelBase() {
private val _profile = MutableLiveData<UserProfileDto>()
val profile: LiveData<UserProfileDto> get() = _profile
private val _profile = MutableLiveData<UserProfile>()
val profile: LiveData<UserProfile> get() = _profile
var profileId: Int = 0

View File

@ -3,44 +3,9 @@ package com.isolaatti.profile.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.adapter.FragmentViewHolder
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener
import com.google.android.material.tabs.TabLayoutMediator
import com.isolaatti.BuildConfig
import com.isolaatti.R
import com.isolaatti.common.IsolaattiBaseActivity
import com.isolaatti.databinding.ActivityProfileBinding
import com.isolaatti.posting.common.domain.OnUserInteractedCallback
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.profile.presentation.ProfileViewModel
import com.isolaatti.utils.PicassoImagesPluginDef
import com.isolaatti.utils.UrlGen
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonConfiguration
import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute
import io.noties.markwon.linkify.LinkifyPlugin
@AndroidEntryPoint
class ProfileActivity : IsolaattiBaseActivity() {

View File

@ -2,6 +2,7 @@ package com.isolaatti.profile.ui
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -24,11 +25,12 @@ import com.isolaatti.followers.domain.FollowingState
import com.isolaatti.home.FeedFragment
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
import com.isolaatti.posting.comments.ui.BottomSheetPostComments
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.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.common.Ownable
import com.isolaatti.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.common.options_bottom_sheet.domain.Options
import com.isolaatti.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.images.picture_viewer.ui.PictureViewerActivity
import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.posting.posts.presentation.CreatePostContract
import com.isolaatti.posting.posts.presentation.EditPostContract
@ -36,6 +38,7 @@ import com.isolaatti.posting.posts.presentation.PostListingRecyclerViewAdapterWi
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.domain.entity.UserProfile
import com.isolaatti.profile.presentation.ProfileViewModel
import com.isolaatti.utils.PicassoImagesPluginDef
import com.isolaatti.utils.UrlGen
@ -75,9 +78,9 @@ class ProfileMainFragment : Fragment() {
}
}
private val profileObserver = Observer<UserProfileDto> { profile ->
private val profileObserver = Observer<UserProfile> { profile ->
Picasso.get()
.load(UrlGen.userProfileImage(profile.id))
.load(UrlGen.userProfileImage(profile.userId))
.into(viewBinding.profileImageView)
title = profile.name
@ -94,6 +97,12 @@ class ProfileMainFragment : Fragment() {
)
viewBinding.profileImageView.setOnClickListener {
optionsViewModel.setOptions(Options.PROFILE_PHOTO_OPTIONS, CALLER_ID, profile)
val fragment = BottomSheetPostOptionsFragment()
fragment.show(parentFragmentManager, BottomSheetPostOptionsFragment.TAG)
}
setupUiForUserType(profile.isUserItself)
}
@ -131,7 +140,25 @@ class ProfileMainFragment : Fragment() {
}
private val optionsObserver: Observer<OptionClicked?> = Observer { optionClicked ->
if(optionClicked?.callerId == FeedFragment.CALLER_ID) {
if(optionClicked?.callerId == CALLER_ID) {
Log.d("ProfileMainFragment", optionClicked.toString())
when(optionClicked.optionsId) {
Options.PROFILE_PHOTO_OPTIONS -> {
val profile = optionClicked.payload as? UserProfile
when(optionClicked.optionId) {
Options.Option.OPTION_PROFILE_PHOTO_CHANGE_PHOTO -> {}
Options.Option.OPTION_PROFILE_PHOTO_REMOVE_PHOTO -> {}
Options.Option.OPTION_PROFILE_PHOTO_VIEW_PHOTO -> {
val profilePictureUrl = profile?.profilePictureUrl
if(profilePictureUrl != null) {
PictureViewerActivity.startActivityWithUrls(requireContext(), arrayOf(profilePictureUrl))
}
}
}
optionsViewModel.handle()
}
Options.POST_OPTIONS -> {
// post id should come as payload
val post = optionClicked.payload as? Post ?: return@Observer
when(optionClicked.optionId) {
@ -155,6 +182,10 @@ class ProfileMainFragment : Fragment() {
}
}
}
}
private lateinit var postListingRecyclerViewAdapterWiring: PostListingRecyclerViewAdapterWiring
@ -163,7 +194,7 @@ class ProfileMainFragment : Fragment() {
viewBinding.topAppBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
if (scrollRange == -1) scrollRange = appBarLayout.totalScrollRange
if (scrollRange + verticalOffset == 0) {
viewBinding.collapsingToolbarLayout.title = title
viewBinding.collapsingToolbarLayout.title = viewModel.profile.value?.name
isShow = true
} else if (isShow) {
viewBinding.collapsingToolbarLayout.title = " "
@ -278,7 +309,7 @@ class ProfileMainFragment : Fragment() {
}
override fun onOptions(post: Ownable) {
optionsViewModel.setOptions(Options.POST_OPTIONS, FeedFragment.CALLER_ID, post)
optionsViewModel.setOptions(Options.POST_OPTIONS, CALLER_ID, post)
val modalBottomSheet = BottomSheetPostOptionsFragment()
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
}
@ -305,11 +336,12 @@ class ProfileMainFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupCollapsingBar()
setupPostsAdapter()
bind()
setObservers()
getData()
setupCollapsingBar()
@ -322,4 +354,8 @@ class ProfileMainFragment : Fragment() {
}
}
}
companion object {
const val CALLER_ID = 30
}
}

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13L7,13v-2h10v2z"/>
</vector>

View File

@ -84,4 +84,8 @@
<string name="comments">Comments</string>
<string name="likes_info">Claps: %d</string>
<string name="comments_info">Comments: %d</string>
<string name="view_photo">View photo</string>
<string name="change_profile_photo">Change profile photo</string>
<string name="profile_photo">Profile photo</string>
<string name="remove_photo">Remove photo</string>
</resources>