270 lines
9.6 KiB
Kotlin
Raw Normal View History

2023-07-15 20:58:57 -06:00
package com.isolaatti.home
2023-02-06 13:44:27 -06:00
2023-02-11 23:41:23 -06:00
import android.content.Intent
2023-02-06 13:44:27 -06:00
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.constraintlayout.widget.ConstraintLayout
2023-02-11 23:41:23 -06:00
import androidx.fragment.app.activityViewModels
2023-09-10 13:17:50 -06:00
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
2023-09-10 13:17:50 -06:00
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
2023-02-11 23:41:23 -06:00
import androidx.recyclerview.widget.LinearLayoutManager
import coil.load
2023-07-17 00:08:36 -06:00
import com.isolaatti.BuildConfig
2023-02-06 13:44:27 -06:00
import com.isolaatti.R
2023-08-19 20:52:22 -06:00
import com.isolaatti.about.AboutActivity
import com.isolaatti.common.CoilImageLoader.imageLoader
2023-08-24 20:56:08 -06:00
import com.isolaatti.common.Dialogs
2023-07-15 20:58:57 -06:00
import com.isolaatti.common.ErrorMessageViewModel
2023-02-06 13:44:27 -06:00
import com.isolaatti.databinding.FragmentFeedBinding
2023-07-31 00:25:25 -06:00
import com.isolaatti.drafts.ui.DraftsActivity
import com.isolaatti.home.presentation.FeedViewModel
2023-09-10 20:35:22 -06:00
import com.isolaatti.images.picture_viewer.ui.PictureViewerActivity
2023-09-10 16:37:21 -06:00
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
2023-09-02 00:03:57 -06:00
import com.isolaatti.posting.comments.ui.BottomSheetPostComments
2023-09-12 22:31:52 -06:00
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
2023-08-27 23:03:40 -06:00
import com.isolaatti.posting.posts.domain.entity.Post
2023-08-25 00:18:32 -06:00
import com.isolaatti.posting.posts.presentation.CreatePostContract
import com.isolaatti.posting.posts.presentation.EditPostContract
2023-07-08 02:17:19 -06:00
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
2023-02-11 23:41:23 -06:00
import com.isolaatti.profile.ui.ProfileActivity
import com.isolaatti.settings.ui.SettingsActivity
import com.isolaatti.utils.UrlGen
2023-02-11 23:41:23 -06:00
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.coil.CoilImagesPlugin
2023-02-11 23:41:23 -06:00
import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute
import io.noties.markwon.linkify.LinkifyPlugin
2023-09-10 13:17:50 -06:00
import kotlinx.coroutines.launch
2023-02-06 13:44:27 -06:00
2023-02-11 23:41:23 -06:00
@AndroidEntryPoint
2023-07-08 02:17:19 -06:00
class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
2023-02-06 13:44:27 -06:00
companion object {
fun newInstance() = FeedFragment()
const val CALLER_ID = 20
2023-02-06 13:44:27 -06:00
}
2023-07-15 20:58:57 -06:00
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
2023-08-06 22:11:28 -06:00
private val viewModel: FeedViewModel by activityViewModels()
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
2023-08-06 23:22:53 -06:00
private var currentUserId = 0
2023-02-06 13:44:27 -06:00
private lateinit var viewBinding: FragmentFeedBinding
2023-07-08 02:17:19 -06:00
private lateinit var adapter: PostsRecyclerViewAdapter
2023-02-06 13:44:27 -06:00
2023-08-25 00:18:32 -06:00
// region launchers
private val createDiscussion = registerForActivityResult(CreatePostContract()) {
if(it != null) {
Toast.makeText(requireContext(), R.string.posted_successfully, Toast.LENGTH_SHORT).show()
}
}
2023-08-25 00:18:32 -06:00
private val editDiscussion = registerForActivityResult(EditPostContract()) {
if(it != null) {
viewModel.onPostUpdate(it)
}
}
// endregion
// region observers
2023-08-27 23:03:40 -06:00
private val optionsObserver: Observer<OptionClicked?> = Observer { optionClicked ->
2023-08-24 20:56:08 -06:00
if(optionClicked?.callerId == CALLER_ID) {
// post id should come as payload
2023-08-27 23:03:40 -06:00
val post = optionClicked.payload as? Post ?: return@Observer
2023-08-24 20:56:08 -06:00
when(optionClicked.optionId) {
Options.Option.OPTION_DELETE -> {
2023-08-24 20:56:08 -06:00
Dialogs.buildDeletePostDialog(requireContext()) { delete ->
optionsViewModel.handle()
if(delete) {
2023-08-27 23:03:40 -06:00
viewModel.deletePost(post.id)
2023-08-24 20:56:08 -06:00
}
}.show()
}
Options.Option.OPTION_EDIT -> {
2023-08-24 20:56:08 -06:00
optionsViewModel.handle()
2023-08-27 23:03:40 -06:00
editDiscussion.launch(post.id)
}
Options.Option.OPTION_REPORT -> {
2023-08-27 23:03:40 -06:00
optionsViewModel.handle()
}
}
}
}
2023-08-25 00:18:32 -06:00
// endregion
// region lifecycle
2023-02-06 13:44:27 -06:00
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewBinding = FragmentFeedBinding.inflate(inflater)
return viewBinding.root
}
2023-08-25 00:18:32 -06:00
// endregion
// region events
2023-02-11 23:41:23 -06:00
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.topAppBar.setNavigationOnClickListener {
2023-07-08 02:17:19 -06:00
viewBinding.drawerLayout?.openDrawer(viewBinding.homeDrawer)
2023-02-11 23:41:23 -06:00
}
2023-07-08 02:17:19 -06:00
2023-02-11 23:41:23 -06:00
viewBinding.homeDrawer.setNavigationItemSelectedListener {
when(it.itemId) {
R.id.my_profile_menu_item -> {
2023-08-06 23:22:53 -06:00
ProfileActivity.startActivity(requireContext(), currentUserId)
2023-02-11 23:41:23 -06:00
true
}
2023-07-31 00:25:25 -06:00
R.id.drafts_menu_item -> {
startActivity(Intent(requireActivity(), DraftsActivity::class.java))
true
}
2023-02-11 23:41:23 -06:00
R.id.settings_menu_item -> {
startActivity(Intent(requireActivity(), SettingsActivity::class.java))
true
}
2023-08-19 20:52:22 -06:00
R.id.about_menu_item -> {
startActivity(Intent(requireActivity(), AboutActivity::class.java))
true
}
2023-02-11 23:41:23 -06:00
else -> {true}
}
}
2023-07-15 20:58:57 -06:00
2023-02-11 23:41:23 -06:00
val markwon = Markwon.builder(requireContext())
.usePlugin(object: AbstractMarkwonPlugin() {
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
builder
.imageDestinationProcessor(ImageDestinationProcessorRelativeToAbsolute
2023-07-17 00:08:36 -06:00
.create(BuildConfig.backend))
2023-02-11 23:41:23 -06:00
}
})
.usePlugin(CoilImagesPlugin.create(requireContext(), imageLoader))
2023-02-11 23:41:23 -06:00
.usePlugin(LinkifyPlugin.create())
.build()
2023-08-27 20:00:43 -06:00
adapter = PostsRecyclerViewAdapter(markwon, this)
2023-02-11 23:41:23 -06:00
viewBinding.feedRecyclerView.adapter = adapter
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext())
2023-07-08 02:17:19 -06:00
2023-07-17 00:08:36 -06:00
viewBinding.swipeToRefresh.setOnRefreshListener {
viewModel.getFeed(refresh = true)
}
viewBinding.topAppBar.setOnMenuItemClickListener {
when(it.itemId) {
R.id.menu_item_new_discussion -> {
2023-08-25 00:18:32 -06:00
createDiscussion.launch(Unit)
true
}
else -> {
false
}
}
}
2023-08-06 22:11:28 -06:00
viewModel.userProfile.observe(viewLifecycleOwner) {
val header = viewBinding.homeDrawer.getHeaderView(0) as? ConstraintLayout
val image: ImageView? = header?.findViewById(R.id.profileImageView)
val textViewName: TextView? = header?.findViewById(R.id.textViewName)
val textViewEmail: TextView? = header?.findViewById(R.id.textViewEmail)
image?.load(UrlGen.userProfileImage(it.userId), imageLoader)
2023-08-20 16:11:07 -06:00
image?.setOnClickListener {_ ->
2023-11-20 22:53:14 -06:00
//PictureViewerActivity.startActivityWithImages(requireContext(), arrayOf(UrlGen.userProfileImageFullQuality(it.userId)))
2023-08-20 16:11:07 -06:00
}
textViewName?.text = it.name
textViewEmail?.text = it.email
2023-09-12 22:31:52 -06:00
currentUserId = it.userId
}
2023-07-08 02:17:19 -06:00
viewModel.posts.observe(viewLifecycleOwner){
2023-08-06 23:22:53 -06:00
if (it?.first != null) {
2023-08-06 22:11:28 -06:00
adapter.updateList(it.first!!, it.second)
2023-08-15 00:02:29 -06:00
adapter.newContentRequestFinished()
2023-07-17 00:08:36 -06:00
}
2023-07-15 20:58:57 -06:00
}
2023-07-17 00:08:36 -06:00
2023-08-06 22:11:28 -06:00
viewModel.loadingPosts.observe(viewLifecycleOwner) {
2023-08-15 00:02:29 -06:00
viewBinding.loadingIndicator.visibility = if(it) View.VISIBLE else View.GONE
2023-08-15 23:11:15 -06:00
if(!it) {
viewBinding.swipeToRefresh.isRefreshing = false
}
2023-08-06 22:11:28 -06:00
}
2023-07-17 00:08:36 -06:00
2023-07-15 20:58:57 -06:00
viewModel.errorLoading.observe(viewLifecycleOwner) {
errorViewModel.error.postValue(it)
2023-02-11 23:41:23 -06:00
}
2023-09-10 13:17:50 -06:00
2023-08-06 22:11:28 -06:00
viewModel.getProfile()
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
2023-09-10 13:17:50 -06:00
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
errorViewModel.retry.collect {
viewModel.retry()
errorViewModel.handleRetry()
}
}
}
2023-07-08 02:17:19 -06:00
}
override fun onLiked(postId: Long) = viewModel.likePost(postId)
2023-02-11 23:41:23 -06:00
2023-07-08 02:17:19 -06:00
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
2023-08-27 20:00:43 -06:00
override fun onOptions(post: Ownable) {
optionsViewModel.setOptions(Options.POST_OPTIONS, CALLER_ID, post)
2023-07-08 02:17:19 -06:00
val modalBottomSheet = BottomSheetPostOptionsFragment()
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
}
override fun onComment(postId: Long) {
val modalBottomSheet = BottomSheetPostComments.getInstance(postId)
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostComments.TAG)
2023-02-06 13:44:27 -06:00
}
2023-07-08 02:17:19 -06:00
override fun onOpenPost(postId: Long) {
PostViewerActivity.startActivity(requireContext(), postId)
}
2023-07-08 02:17:19 -06:00
override fun onProfileClick(userId: Int) {
ProfileActivity.startActivity(requireContext(), userId)
2023-07-08 02:17:19 -06:00
}
2023-08-15 00:02:29 -06:00
override fun onLoadMore() {
viewModel.getFeed(false)
}
2023-08-25 00:18:32 -06:00
// endregion
2023-02-06 13:44:27 -06:00
}