WIP posts en compose
This commit is contained in:
parent
5775145a69
commit
37837653cc
@ -101,8 +101,11 @@ dependencies {
|
|||||||
// Customtabs
|
// Customtabs
|
||||||
implementation 'androidx.browser:browser:1.8.0'
|
implementation 'androidx.browser:browser:1.8.0'
|
||||||
|
|
||||||
implementation 'io.coil-kt:coil:2.5.0'
|
// Coil
|
||||||
implementation 'io.coil-kt:coil-svg:2.5.0'
|
implementation 'io.coil-kt.coil3:coil:3.0.4'
|
||||||
|
implementation 'io.coil-kt.coil3:coil-svg:3.0.4'
|
||||||
|
implementation "io.coil-kt.coil3:coil-compose:3.0.1"
|
||||||
|
implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.1")
|
||||||
|
|
||||||
|
|
||||||
implementation "io.noties.markwon:core:$markwon_version"
|
implementation "io.noties.markwon:core:$markwon_version"
|
||||||
@ -156,8 +159,7 @@ dependencies {
|
|||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5'
|
||||||
implementation 'androidx.compose.runtime:runtime-livedata'
|
implementation 'androidx.compose.runtime:runtime-livedata'
|
||||||
|
|
||||||
implementation "io.coil-kt.coil3:coil-compose:3.0.1"
|
|
||||||
implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.1")
|
|
||||||
|
|
||||||
implementation("com.google.accompanist:accompanist-permissions:0.36.0")
|
implementation("com.google.accompanist:accompanist-permissions:0.36.0")
|
||||||
}
|
}
|
||||||
@ -1,35 +1,19 @@
|
|||||||
package com.isolaatti.common
|
package com.isolaatti.common
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import coil.ImageLoader
|
import coil3.ImageLoader
|
||||||
import coil.decode.SvgDecoder
|
|
||||||
import coil.memory.MemoryCache
|
|
||||||
import com.isolaatti.MyApplication
|
import com.isolaatti.MyApplication
|
||||||
|
|
||||||
object CoilImageLoader {
|
object CoilImageLoader {
|
||||||
val imageLoader by lazy {
|
val imageLoader by lazy {
|
||||||
ImageLoader
|
ImageLoader
|
||||||
.Builder(MyApplication.myApp)
|
.Builder(MyApplication.myApp)
|
||||||
.memoryCache {
|
.build()
|
||||||
MemoryCache.Builder(MyApplication.myApp.applicationContext)
|
|
||||||
.maxSizePercent(0.25)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
.components {
|
|
||||||
add(SvgDecoder.Factory())
|
|
||||||
}.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getImageLoader(context: Context): ImageLoader {
|
fun getImageLoader(context: Context): ImageLoader {
|
||||||
return ImageLoader
|
return ImageLoader
|
||||||
.Builder(context)
|
.Builder(context)
|
||||||
.memoryCache {
|
.build()
|
||||||
MemoryCache.Builder(context)
|
|
||||||
.maxSizePercent(0.25)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
.components {
|
|
||||||
add(SvgDecoder.Factory())
|
|
||||||
}.build()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,7 +8,7 @@ import androidx.recyclerview.widget.ListAdapter
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.recyclerview.widget.RecyclerView.Adapter
|
import androidx.recyclerview.widget.RecyclerView.Adapter
|
||||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.common.CoilImageLoader.imageLoader
|
import com.isolaatti.common.CoilImageLoader.imageLoader
|
||||||
import com.isolaatti.databinding.ItemUserListBinding
|
import com.isolaatti.databinding.ItemUserListBinding
|
||||||
|
|||||||
@ -5,9 +5,6 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.isolaatti.auth.domain.AuthRepository
|
import com.isolaatti.auth.domain.AuthRepository
|
||||||
import com.isolaatti.posting.posts.domain.PostsRepository
|
|
||||||
import com.isolaatti.posting.posts.presentation.PostListingViewModelBase
|
|
||||||
import com.isolaatti.posting.posts.presentation.UpdateEvent
|
|
||||||
import com.isolaatti.profile.domain.entity.UserProfile
|
import com.isolaatti.profile.domain.entity.UserProfile
|
||||||
import com.isolaatti.profile.domain.use_case.GetProfile
|
import com.isolaatti.profile.domain.use_case.GetProfile
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import coil.load
|
import coil3.load
|
||||||
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.about.AboutActivity
|
import com.isolaatti.about.AboutActivity
|
||||||
|
|||||||
@ -4,8 +4,9 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.os.BundleCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.common.CoilImageLoader.imageLoader
|
import com.isolaatti.common.CoilImageLoader.imageLoader
|
||||||
import com.isolaatti.databinding.FragmentTouchImageViewWrapperBinding
|
import com.isolaatti.databinding.FragmentTouchImageViewWrapperBinding
|
||||||
import com.isolaatti.images.common.domain.entity.RemoteImage
|
import com.isolaatti.images.common.domain.entity.RemoteImage
|
||||||
@ -24,7 +25,7 @@ class PictureViewerImageWrapperFragment : Fragment() {
|
|||||||
): View {
|
): View {
|
||||||
binding = FragmentTouchImageViewWrapperBinding.inflate(inflater)
|
binding = FragmentTouchImageViewWrapperBinding.inflate(inflater)
|
||||||
|
|
||||||
image = arguments?.getSerializable(ARGUMENT_IMAGE) as RemoteImage
|
image = BundleCompat.getParcelable(requireArguments(), ARGUMENT_IMAGE, RemoteImage::class.java)
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.IntentCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import com.isolaatti.databinding.FragmentMainPictureViewerBinding
|
import com.isolaatti.databinding.FragmentMainPictureViewerBinding
|
||||||
@ -36,7 +37,7 @@ class PictureViewerMainFragment : Fragment() {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
images = requireActivity().intent.extras?.getSerializable(PictureViewerActivity.EXTRA_IMAGES) as Array<RemoteImage>
|
images = IntentCompat.getParcelableArrayExtra(requireActivity().intent, PictureViewerActivity.EXTRA_IMAGES, RemoteImage::class.java) as Array<RemoteImage>
|
||||||
val position = requireActivity().intent.extras?.getInt(PictureViewerActivity.EXTRA_IMAGE_POSITiON) ?: 0
|
val position = requireActivity().intent.extras?.getInt(PictureViewerActivity.EXTRA_IMAGE_POSITiON) ?: 0
|
||||||
val adapter = PictureViewerViewPagerAdapter(this, images)
|
val adapter = PictureViewerViewPagerAdapter(this, images)
|
||||||
binding.viewpager.adapter = adapter
|
binding.viewpager.adapter = adapter
|
||||||
|
|||||||
@ -31,7 +31,6 @@ class Module {
|
|||||||
.create(BuildConfig.backend))
|
.create(BuildConfig.backend))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.usePlugin(CoilImagesPlugin.create(context, CoilImageLoader.imageLoader))
|
|
||||||
.usePlugin(LinkifyPlugin.create())
|
.usePlugin(LinkifyPlugin.create())
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,8 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||||
import coil.load
|
import coil3.load
|
||||||
|
import coil3.request.fallback
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.databinding.NotificationItemBinding
|
import com.isolaatti.databinding.NotificationItemBinding
|
||||||
import com.isolaatti.notifications.domain.FollowNotification
|
import com.isolaatti.notifications.domain.FollowNotification
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import android.annotation.SuppressLint
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.common.CoilImageLoader.imageLoader
|
import com.isolaatti.common.CoilImageLoader.imageLoader
|
||||||
import com.isolaatti.databinding.CommentLayoutBinding
|
import com.isolaatti.databinding.CommentLayoutBinding
|
||||||
import com.isolaatti.posting.comments.domain.model.Comment
|
import com.isolaatti.posting.comments.domain.model.Comment
|
||||||
|
|||||||
@ -217,7 +217,6 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
|
|||||||
.create("https://isolaatti.com/"))
|
.create("https://isolaatti.com/"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.usePlugin(CoilImagesPlugin.create(requireContext(), imageLoader))
|
|
||||||
.usePlugin(LinkifyPlugin.create())
|
.usePlugin(LinkifyPlugin.create())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.common.CoilImageLoader.imageLoader
|
import com.isolaatti.common.CoilImageLoader.imageLoader
|
||||||
import com.isolaatti.databinding.FragmentEditCommentBinding
|
import com.isolaatti.databinding.FragmentEditCommentBinding
|
||||||
@ -51,7 +51,7 @@ class EditCommentDialogFragment : DialogFragment() {
|
|||||||
.create("https://isolaatti.com/"))
|
.create("https://isolaatti.com/"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.usePlugin(CoilImagesPlugin.create(requireContext(), imageLoader))
|
//.usePlugin(CoilImagesPlugin.create(requireContext(), imageLoader))
|
||||||
.usePlugin(LinkifyPlugin.create())
|
.usePlugin(LinkifyPlugin.create())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
|||||||
@ -4,25 +4,22 @@ import androidx.compose.foundation.background
|
|||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
|
||||||
import androidx.compose.foundation.layout.wrapContentSize
|
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.FilledTonalButton
|
|
||||||
import androidx.compose.material3.FilledTonalIconButton
|
import androidx.compose.material3.FilledTonalIconButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@ -31,11 +28,14 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Devices
|
import androidx.compose.ui.tooling.preview.Devices
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
|
import com.isolaatti.images.common.domain.entity.Image
|
||||||
|
import com.isolaatti.images.common.domain.entity.RemoteImage
|
||||||
import com.isolaatti.posting.posts.domain.entity.Post
|
import com.isolaatti.posting.posts.domain.entity.Post
|
||||||
import com.isolaatti.utils.UrlGen.userProfileImage
|
import com.isolaatti.utils.UrlGen.userProfileImage
|
||||||
|
|
||||||
@ -44,13 +44,17 @@ fun Post(
|
|||||||
post: Post,
|
post: Post,
|
||||||
onClick: () -> Unit = {},
|
onClick: () -> Unit = {},
|
||||||
onLike: () -> Unit = {},
|
onLike: () -> Unit = {},
|
||||||
|
onDislike: () -> Unit = {},
|
||||||
onComments: () -> Unit = {},
|
onComments: () -> Unit = {},
|
||||||
onShare: () -> Unit = {},
|
onShare: () -> Unit = {},
|
||||||
onInfo: () -> Unit = {},
|
onInfo: () -> Unit = {},
|
||||||
onOptions: () -> Unit = {},
|
onOptions: () -> Unit = {},
|
||||||
onUsernameClick: () -> Unit = {}
|
onUsernameClick: () -> Unit = {},
|
||||||
|
onImageClick: (images: List<RemoteImage>, index: Int) -> Unit = {_, _ -> },
|
||||||
|
onHashtagClick: (hashtag: String) -> Unit = {},
|
||||||
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
Card {
|
Card(modifier = modifier.padding(8.dp)) {
|
||||||
Row(modifier = Modifier.fillMaxWidth().padding(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
Row(modifier = Modifier.fillMaxWidth().padding(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = userProfileImage(post.userId),
|
model = userProfileImage(post.userId),
|
||||||
@ -78,37 +82,80 @@ fun Post(
|
|||||||
// TODO audio player here
|
// TODO audio player here
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(post.textContent, modifier = Modifier.padding(8.dp))
|
if(post.textContent.isNotBlank()) {
|
||||||
|
Text(post.textContent, modifier = Modifier.padding(8.dp))
|
||||||
|
}
|
||||||
|
|
||||||
// TODO pager
|
|
||||||
if(post.images.isNotEmpty()) {
|
if(post.images.isNotEmpty()) {
|
||||||
Box(Modifier.fillMaxWidth().aspectRatio(1f))
|
Box {
|
||||||
|
val pagerState = rememberPagerState(pageCount = {post.images.size})
|
||||||
|
HorizontalPager(
|
||||||
|
state = pagerState,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.aspectRatio(1f)
|
||||||
|
) {
|
||||||
|
val image = post.images[it]
|
||||||
|
AsyncImage(
|
||||||
|
image.reducedImageUrl, null,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(8.dp)
|
||||||
|
.clip(RoundedCornerShape(20.dp))
|
||||||
|
.clickable {
|
||||||
|
onImageClick(post.images, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(post.images.size > 1) {
|
||||||
|
Text("${pagerState.currentPage + 1} of ${pagerState.pageCount}",
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomEnd)
|
||||||
|
.padding(20.dp)
|
||||||
|
.background(Color.Black.copy(alpha = 0.5f)),
|
||||||
|
color = Color.White
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(modifier = Modifier.height(50.dp).padding(4.dp)) {
|
Row(modifier = Modifier.height(50.dp).padding(4.dp)) {
|
||||||
FilledTonalIconButton(onClick = onLike, modifier = Modifier.padding(4.dp).weight(1f)) {
|
FilledTonalIconButton(
|
||||||
|
onClick = { if(post.liked) { onDislike() } else { onLike() } },
|
||||||
|
modifier = Modifier.padding(4.dp).weight(1f)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Icon(painterResource(R.drawable.hands_clapping_solid), null, modifier = Modifier.size(30.dp))
|
Icon(
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
painterResource(R.drawable.hands_clapping_solid),
|
||||||
Text("Clap")
|
null,
|
||||||
Text(post.numberOfLikes.toString())
|
modifier = Modifier.padding(horizontal = 8.dp).size(30.dp),
|
||||||
}
|
tint = if(post.liked) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = post.numberOfLikes.toString(),
|
||||||
|
modifier = Modifier.weight(1f).padding(horizontal = 4.dp),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FilledTonalIconButton(onClick = onComments, modifier = Modifier.padding(4.dp).weight(1f)) {
|
FilledTonalIconButton(onClick = onComments, modifier = Modifier.padding(4.dp).weight(1f)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Icon(painterResource(R.drawable.comments_solid), null, modifier = Modifier.size(30.dp))
|
Icon(
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
painterResource(R.drawable.comments_solid),
|
||||||
Text("Comments")
|
null,
|
||||||
Text(post.numberOfComments.toString())
|
modifier = Modifier.padding(horizontal = 8.dp).size(30.dp)
|
||||||
}
|
)
|
||||||
|
Text(
|
||||||
|
text = post.numberOfComments.toString(),
|
||||||
|
modifier = Modifier.weight(1f).padding(horizontal = 4.dp),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FilledTonalIconButton(onClick = onShare, modifier = Modifier.padding(4.dp).weight(1f)) {
|
FilledTonalIconButton(onClick = onShare, modifier = Modifier.padding(4.dp)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Icon(
|
||||||
Icon(painterResource(R.drawable.baseline_share_24), null, modifier = Modifier.size(30.dp))
|
painterResource(R.drawable.baseline_share_24),
|
||||||
Text("Share")
|
null,
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
FilledTonalIconButton(onClick = onInfo, modifier = Modifier.padding(4.dp)) {
|
FilledTonalIconButton(onClick = onInfo, modifier = Modifier.padding(4.dp)) {
|
||||||
Icon(painterResource(R.drawable.baseline_info_24), null)
|
Icon(painterResource(R.drawable.baseline_info_24), null)
|
||||||
|
|||||||
@ -2,28 +2,39 @@ package com.isolaatti.posting.posts.domain.entity
|
|||||||
|
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import com.isolaatti.audio.common.domain.Audio
|
import com.isolaatti.audio.common.domain.Audio
|
||||||
import com.isolaatti.common.Ownable
|
import com.isolaatti.common.Ownable
|
||||||
import com.isolaatti.common.hashtagRegex
|
import com.isolaatti.common.hashtagRegex
|
||||||
import com.isolaatti.images.common.domain.entity.RemoteImage
|
import com.isolaatti.images.common.domain.entity.RemoteImage
|
||||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||||
|
|
||||||
data class Post(
|
class Post(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
var textContent: String,
|
textContent: String,
|
||||||
override val userId: Int,
|
override val userId: Int,
|
||||||
val privacy: Int,
|
val privacy: Int,
|
||||||
val date: String,
|
val date: String,
|
||||||
var audioId: String? = null,
|
var audioId: String? = null,
|
||||||
val squadId: String? = null,
|
val squadId: String? = null,
|
||||||
var numberOfLikes: Int,
|
numberOfLikes: Int,
|
||||||
var numberOfComments: Int,
|
numberOfComments: Int,
|
||||||
val userName: String,
|
val userName: String,
|
||||||
val squadName: String? = null,
|
val squadName: String? = null,
|
||||||
var liked: Boolean,
|
liked: Boolean,
|
||||||
val audio: Audio? = null,
|
val audio: Audio? = null,
|
||||||
val images: List<RemoteImage>
|
images: List<RemoteImage>
|
||||||
) : Ownable, Parcelable {
|
) : Ownable, Parcelable {
|
||||||
|
|
||||||
|
var liked by mutableStateOf(liked)
|
||||||
|
var images by mutableStateOf(images)
|
||||||
|
var textContent by mutableStateOf(textContent)
|
||||||
|
var numberOfLikes by mutableIntStateOf(numberOfLikes)
|
||||||
|
var numberOfComments by mutableStateOf(numberOfComments)
|
||||||
|
|
||||||
constructor(parcel: Parcel) : this(
|
constructor(parcel: Parcel) : this(
|
||||||
parcel.readLong(),
|
parcel.readLong(),
|
||||||
parcel.readString()!!,
|
parcel.readString()!!,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import android.view.ViewGroup
|
|||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.images.common.domain.entity.RemoteImage
|
import com.isolaatti.images.common.domain.entity.RemoteImage
|
||||||
|
|
||||||
class PostImagesViewPagerAdapter(private val images: List<RemoteImage>) :
|
class PostImagesViewPagerAdapter(private val images: List<RemoteImage>) :
|
||||||
|
|||||||
@ -16,17 +16,13 @@ class PostListingViewModel @Inject constructor(private val postsRepository: Post
|
|||||||
override fun getFeed(refresh: Boolean, hashtag: String?) {
|
override fun getFeed(refresh: Boolean, hashtag: String?) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (refresh) {
|
if (refresh) {
|
||||||
posts.value = null
|
posts.value = emptyList()
|
||||||
}
|
}
|
||||||
postsRepository.getFeed(getLastId(), hashtag).onEach { listResource ->
|
postsRepository.getFeed(getLastId(), hashtag).onEach { listResource ->
|
||||||
when (listResource) {
|
when (listResource) {
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
val eventType = if((postsList?.size ?: 0) > 0) UpdateEvent.UpdateType.PAGE_ADDED else UpdateEvent.UpdateType.REFRESH
|
|
||||||
loadingPosts.postValue(false)
|
loadingPosts.postValue(false)
|
||||||
posts.postValue(Pair(postsList?.apply {
|
posts.value += listResource.data ?: emptyList()
|
||||||
addAll(listResource.data ?: listOf())
|
|
||||||
} ?: listResource.data,
|
|
||||||
UpdateEvent(eventType, null)))
|
|
||||||
|
|
||||||
noMoreContent.postValue(listResource.data?.size == 0)
|
noMoreContent.postValue(listResource.data?.size == 0)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ 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
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@ -30,9 +31,8 @@ abstract class PostListingViewModelBase : ViewModel() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var deletePostUseCase: DeletePost
|
lateinit var deletePostUseCase: DeletePost
|
||||||
|
|
||||||
val posts: MutableLiveData<Pair<MutableList<Post>?, UpdateEvent>?> = MutableLiveData()
|
val posts: MutableStateFlow<List<Post>> = MutableStateFlow(emptyList())
|
||||||
|
|
||||||
val postsList get() = posts.value?.first
|
|
||||||
|
|
||||||
val loadingPosts = MutableLiveData(false)
|
val loadingPosts = MutableLiveData(false)
|
||||||
|
|
||||||
@ -41,7 +41,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?.last()?.id ?: 0 } catch (e: NoSuchElementException) { 0 }
|
fun getLastId(): Long = try { posts.value?.last()?.id ?: 0 } catch (e: NoSuchElementException) { 0 }
|
||||||
|
|
||||||
|
|
||||||
abstract fun getFeed(refresh: Boolean, hashtag: String?)
|
abstract fun getFeed(refresh: Boolean, hashtag: String?)
|
||||||
@ -58,18 +58,9 @@ abstract class PostListingViewModelBase : ViewModel() {
|
|||||||
Log.i(TAG, "Loading likePost($postId)")
|
Log.i(TAG, "Loading likePost($postId)")
|
||||||
}
|
}
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
val likedPost = posts.value?.first?.find { post -> post.id == like.data?.postId }
|
val likedPost = posts.value?.find { post -> post.id == like.data?.postId }
|
||||||
val index = posts.value?.first?.indexOf(likedPost)
|
likedPost?.liked = true
|
||||||
if(index != null){
|
likedPost?.numberOfLikes = like.data!!.likesCount
|
||||||
val temp = posts.value?.first?.toMutableList()
|
|
||||||
Log.d("***", temp.toString())
|
|
||||||
temp?.set(index, likedPost!!.apply {
|
|
||||||
liked = true
|
|
||||||
numberOfLikes = like.data?.likesCount ?: 0
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, index)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,16 +81,9 @@ abstract class PostListingViewModelBase : ViewModel() {
|
|||||||
Log.i(TAG, "Loading unLikePost($postId)")
|
Log.i(TAG, "Loading unLikePost($postId)")
|
||||||
}
|
}
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
val likedPost = posts.value?.first?.find { post -> post.id == like.data?.postId }
|
val likedPost = posts.value?.find { post -> post.id == like.data?.postId }
|
||||||
val index = posts.value?.first?.indexOf(likedPost)
|
likedPost?.liked = false
|
||||||
if(index != null){
|
likedPost?.numberOfLikes = like.data!!.likesCount
|
||||||
val temp = posts.value?.first?.toMutableList()
|
|
||||||
temp?.set(index, likedPost!!.apply {
|
|
||||||
liked = false
|
|
||||||
numberOfLikes = like.data?.likesCount ?: 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, index)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,12 +97,9 @@ 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?.find { post -> post.id == postId }
|
val postDeleted = posts.value?.find { post -> post.id == postId }
|
||||||
?: return@onEach
|
?: return@onEach
|
||||||
val index = posts.value?.first?.indexOf(postDeleted)
|
posts.value = posts.value.toMutableList().apply { remove(postDeleted) }
|
||||||
|
|
||||||
posts.value?.first?.removeAt(index!!)
|
|
||||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_REMOVED, index)))
|
|
||||||
}
|
}
|
||||||
is Resource.Loading -> {}
|
is Resource.Loading -> {}
|
||||||
is Resource.Error -> {}
|
is Resource.Error -> {}
|
||||||
|
|||||||
@ -1,402 +0,0 @@
|
|||||||
package com.isolaatti.posting.posts.presentation
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.text.SpannableString
|
|
||||||
import android.text.method.LinkMovementMethod
|
|
||||||
import android.text.style.ClickableSpan
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
|
||||||
import androidx.core.text.set
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
|
||||||
import coil.load
|
|
||||||
import com.google.android.material.button.MaterialButton
|
|
||||||
import com.google.android.material.card.MaterialCardView
|
|
||||||
import com.isolaatti.R
|
|
||||||
import com.isolaatti.audio.common.domain.Audio
|
|
||||||
import com.isolaatti.common.CoilImageLoader.imageLoader
|
|
||||||
import com.isolaatti.common.OnUserInteractedWithPostCallback
|
|
||||||
import com.isolaatti.databinding.PostLayoutBinding
|
|
||||||
import com.isolaatti.posting.posts.domain.entity.Post
|
|
||||||
import com.isolaatti.utils.UrlGen.userProfileImage
|
|
||||||
|
|
||||||
|
|
||||||
class PostsRecyclerViewAdapter (
|
|
||||||
private val callback: OnUserInteractedWithPostCallback
|
|
||||||
) : RecyclerView.Adapter<PostsRecyclerViewAdapter.FeedViewHolder>(){
|
|
||||||
private var postList: List<Post>? = null
|
|
||||||
inner class FeedViewHolder(val itemBinding: PostLayoutBinding) : ViewHolder(itemBinding.root) {
|
|
||||||
fun bindView(post: Post, payloads: List<Any>) {
|
|
||||||
|
|
||||||
if(payloads.isNotEmpty()) {
|
|
||||||
for(payload in payloads) {
|
|
||||||
when {
|
|
||||||
payload is LikeCountUpdatePayload -> {
|
|
||||||
itemBinding.likeButton.isEnabled = true
|
|
||||||
|
|
||||||
if(post.liked) {
|
|
||||||
itemBinding.likeButton.setIconTintResource(R.color.purple_lighter)
|
|
||||||
itemBinding.likeButton.setTextColor(itemView.context.getColor(R.color.purple_lighter))
|
|
||||||
} else {
|
|
||||||
itemBinding.likeButton.setIconTintResource(R.color.on_surface)
|
|
||||||
itemBinding.likeButton.setTextColor(itemView.context.getColor(R.color.on_surface))
|
|
||||||
}
|
|
||||||
|
|
||||||
itemBinding.likeButton.text = post.numberOfLikes.toString()
|
|
||||||
}
|
|
||||||
payload is CommentsCountUpdatePayload -> {
|
|
||||||
itemBinding.commentButton.text = post.numberOfComments.toString()
|
|
||||||
}
|
|
||||||
payload is AudioEventPayload && payload == AudioEventPayload.IsPLaying -> {
|
|
||||||
val audio = post.audio
|
|
||||||
if(audio != null){
|
|
||||||
itemBinding.audio.playButton.icon =
|
|
||||||
AppCompatResources.getDrawable(
|
|
||||||
itemView.context,
|
|
||||||
if(audio.isPlaying) R.drawable.baseline_pause_circle_24 else R.drawable.baseline_play_circle_24
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
payload is AudioEventPayload && payload == AudioEventPayload.ProgressChanged -> {
|
|
||||||
val audio = post.audio
|
|
||||||
if(audio != null){
|
|
||||||
itemBinding.audio.audioProgress.progress = audio.progress
|
|
||||||
}
|
|
||||||
}
|
|
||||||
payload is AudioEventPayload && payload == AudioEventPayload.IsLoading -> {
|
|
||||||
val audio = post.audio
|
|
||||||
if(audio != null){
|
|
||||||
itemBinding.audio.audioProgress.isIndeterminate = audio.isLoading
|
|
||||||
}
|
|
||||||
}
|
|
||||||
payload is AudioEventPayload && payload == AudioEventPayload.DurationChanged -> {
|
|
||||||
val audio = post.audio
|
|
||||||
if(audio != null){
|
|
||||||
itemBinding.audio.audioProgress.max = audio.duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
payload is AudioEventPayload && payload == AudioEventPayload.Ended -> {
|
|
||||||
val audio = post.audio
|
|
||||||
if(audio != null){
|
|
||||||
itemBinding.audio.audioProgress.progress = 0
|
|
||||||
itemBinding.audio.playButton.icon = AppCompatResources.getDrawable(itemView.context, R.drawable.baseline_play_circle_24)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
val username: TextView = itemView.findViewById(R.id.text_view_username)
|
|
||||||
username.text = post.userName
|
|
||||||
username.setOnClickListener {
|
|
||||||
callback.onProfileClick(post.userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
val profileImageView: ImageView = itemView.findViewById(R.id.avatar_picture)
|
|
||||||
profileImageView.load(userProfileImage(post.userId), imageLoader)
|
|
||||||
|
|
||||||
val dateTextView: TextView = itemView.findViewById(R.id.text_view_date)
|
|
||||||
dateTextView.text = post.date
|
|
||||||
|
|
||||||
val content: TextView = itemView.findViewById(R.id.post_content)
|
|
||||||
content.movementMethod = LinkMovementMethod.getInstance()
|
|
||||||
val spannableString = SpannableString(post.textContent).apply {
|
|
||||||
post.hashtagsSpans.forEach {
|
|
||||||
set(it.first, it.last + 1, object: ClickableSpan() {
|
|
||||||
override fun onClick(widget: View) {
|
|
||||||
callback.hashtagClicked(post.textContent.substring(it.first + 1, it.last + 1))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
content.text = spannableString
|
|
||||||
|
|
||||||
itemBinding.likeButton.isEnabled = true
|
|
||||||
|
|
||||||
if(post.liked) {
|
|
||||||
itemBinding.likeButton.setIconTintResource(R.color.purple_lighter)
|
|
||||||
itemBinding.likeButton.setTextColor(itemView.context.getColor(R.color.purple_lighter))
|
|
||||||
} else {
|
|
||||||
itemBinding.likeButton.setIconTintResource(R.color.on_surface)
|
|
||||||
itemBinding.likeButton.setTextColor(itemView.context.getColor(R.color.on_surface))
|
|
||||||
}
|
|
||||||
|
|
||||||
itemBinding.likeButton.text = post.numberOfLikes.toString()
|
|
||||||
|
|
||||||
itemBinding.commentButton.text = post.numberOfComments.toString()
|
|
||||||
|
|
||||||
val moreButton: MaterialButton = itemView.findViewById(R.id.more_button)
|
|
||||||
moreButton.setOnClickListener {
|
|
||||||
callback.onOptions(post)
|
|
||||||
}
|
|
||||||
|
|
||||||
itemBinding.likeButton.setOnClickListener {
|
|
||||||
itemBinding.likeButton.isEnabled = false
|
|
||||||
if(post.liked){
|
|
||||||
callback.onUnLiked(post.id)
|
|
||||||
} else {
|
|
||||||
callback.onLiked(post.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
itemBinding.commentButton.setOnClickListener {
|
|
||||||
callback.onComment(post.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
itemView.findViewById<MaterialCardView>(R.id.card).setOnClickListener {
|
|
||||||
callback.onOpenPost(post.id)
|
|
||||||
}
|
|
||||||
if(post.audio != null){
|
|
||||||
itemBinding.audio.apply {
|
|
||||||
root.visibility = View.VISIBLE
|
|
||||||
textViewDescription.text = post.audio.name
|
|
||||||
}
|
|
||||||
itemBinding.audio.playButton.setOnClickListener {
|
|
||||||
callback.onPlay(post.audio)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itemBinding.audio.root.visibility = View.GONE
|
|
||||||
itemBinding.audio.playButton.setOnClickListener(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(post.images.isNotEmpty()) {
|
|
||||||
itemBinding.photosViewPager.isVisible = true
|
|
||||||
itemBinding.photosViewPager.adapter = PostImagesViewPagerAdapter(post.images)
|
|
||||||
} else {
|
|
||||||
itemBinding.photosViewPager.isVisible = false
|
|
||||||
itemBinding.photosViewPager.adapter = null
|
|
||||||
}
|
|
||||||
itemBinding.shareButton.setOnClickListener {
|
|
||||||
callback.onShare(post.id)
|
|
||||||
}
|
|
||||||
itemBinding.infoButton.setOnClickListener {
|
|
||||||
callback.onMoreInfo(post.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
data class LikeCountUpdatePayload(val likeCount: Int)
|
|
||||||
data class CommentsCountUpdatePayload(val commentsCount: Int)
|
|
||||||
|
|
||||||
private var currentAudio: Audio? = null
|
|
||||||
private var currentAudioPosition: Int = -1
|
|
||||||
enum class AudioEventPayload {
|
|
||||||
ProgressChanged, IsLoading, IsPLaying, DurationChanged, Ended
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setIsPlaying(isPlaying: Boolean, audio: Audio) {
|
|
||||||
if(audio == currentAudio) {
|
|
||||||
currentAudio?.isPlaying = isPlaying
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.IsPLaying)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentAudio?.isPlaying = false
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.IsPLaying)
|
|
||||||
} else {
|
|
||||||
if(postList != null) {
|
|
||||||
for((index, post) in postList!!.withIndex()){
|
|
||||||
post.audio?.isPlaying = false
|
|
||||||
post.audio?.progress = 0
|
|
||||||
post.audio?.isLoading = false
|
|
||||||
if(post.audio != null) {
|
|
||||||
notifyItemChanged(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentAudioPosition = postList?.indexOf(postList?.find { it.audio == audio }) ?: -1
|
|
||||||
Log.d(LOG_TAG, "setIsPlaying currentAudioPosition: $currentAudioPosition")
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
currentAudio = postList?.get(currentAudioPosition)?.audio?.also { it.isPlaying = isPlaying }
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.IsPLaying)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setIsLoading(isLoading: Boolean, audio: Audio) {
|
|
||||||
if(audio == currentAudio) {
|
|
||||||
currentAudio?.isLoading = isLoading
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.IsLoading)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentAudio?.isPlaying = false
|
|
||||||
currentAudio?.isLoading = false
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.IsLoading)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentAudioPosition = postList?.indexOf(postList?.find { it.audio == audio }) ?: -1
|
|
||||||
|
|
||||||
Log.d(LOG_TAG, "setIsLoading currentAudioPosition: $currentAudioPosition")
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
postList?.get(currentAudioPosition)?.audio?.isLoading = isLoading
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.IsLoading)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setProgress(progress: Int, audio: Audio){
|
|
||||||
if(audio == currentAudio) {
|
|
||||||
audio.progress = progress
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.ProgressChanged)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentAudio?.isPlaying = false
|
|
||||||
currentAudio?.progress = 0
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.ProgressChanged)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentAudioPosition = postList?.indexOf(postList?.find { it.audio == audio }) ?: -1
|
|
||||||
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
postList?.get(currentAudioPosition)?.audio?.progress = progress
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.ProgressChanged)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setDuration(duration: Int, audio: Audio) {
|
|
||||||
if(audio == currentAudio) {
|
|
||||||
audio.duration = duration
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.ProgressChanged)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentAudio?.isPlaying = false
|
|
||||||
|
|
||||||
currentAudioPosition = postList?.indexOf(postList?.find { it.audio == audio }) ?: -1
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
postList?.get(currentAudioPosition)?.audio?.duration = duration
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.ProgressChanged)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setEnded(audio: Audio) {
|
|
||||||
if(audio == currentAudio) {
|
|
||||||
audio.isPlaying = false
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.ProgressChanged)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentAudio?.isPlaying = false
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.ProgressChanged)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentAudioPosition = postList?.indexOf(postList?.find { it.audio == audio }) ?: -1
|
|
||||||
|
|
||||||
if(currentAudioPosition > -1) {
|
|
||||||
postList?.get(currentAudioPosition)?.audio?.isPlaying = false
|
|
||||||
notifyItemChanged(currentAudioPosition, AudioEventPayload.ProgressChanged)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedViewHolder {
|
|
||||||
return FeedViewHolder(PostLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
|
||||||
}
|
|
||||||
|
|
||||||
var previousSize = 0
|
|
||||||
override fun getItemCount(): Int = postList?.size ?: 0
|
|
||||||
|
|
||||||
|
|
||||||
override fun setHasStableIds(hasStableIds: Boolean) {
|
|
||||||
super.setHasStableIds(true)
|
|
||||||
}
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
|
||||||
fun updateList(updatedFeed: List<Post>, updateEvent: UpdateEvent? = null) {
|
|
||||||
if(updateEvent == null) {
|
|
||||||
postList = updatedFeed
|
|
||||||
|
|
||||||
notifyDataSetChanged()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val postUpdated = updateEvent.affectedPosition?.let {
|
|
||||||
if(updateEvent.updateType == UpdateEvent.UpdateType.POST_REMOVED) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
postList?.get(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val position = updateEvent.affectedPosition
|
|
||||||
|
|
||||||
previousSize = itemCount
|
|
||||||
postList = updatedFeed
|
|
||||||
|
|
||||||
when(updateEvent.updateType) {
|
|
||||||
UpdateEvent.UpdateType.POST_LIKED -> {
|
|
||||||
if(postUpdated != null && position != null)
|
|
||||||
notifyItemChanged(position, LikeCountUpdatePayload(postUpdated.numberOfLikes))
|
|
||||||
}
|
|
||||||
UpdateEvent.UpdateType.POST_COMMENTED -> {
|
|
||||||
if(postUpdated != null && position != null)
|
|
||||||
notifyItemChanged(position, CommentsCountUpdatePayload(postUpdated.numberOfComments))
|
|
||||||
}
|
|
||||||
UpdateEvent.UpdateType.POST_REMOVED -> {
|
|
||||||
if(position != null)
|
|
||||||
notifyItemRemoved(position)
|
|
||||||
}
|
|
||||||
UpdateEvent.UpdateType.POST_ADDED -> {
|
|
||||||
notifyItemInserted(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateEvent.UpdateType.PAGE_ADDED -> {
|
|
||||||
notifyItemInserted(previousSize)
|
|
||||||
}
|
|
||||||
UpdateEvent.UpdateType.REFRESH -> {
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: FeedViewHolder, position: Int) {}
|
|
||||||
|
|
||||||
private var requestedNewContent = false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this method when new content has been added on onLoadMore() callback
|
|
||||||
*/
|
|
||||||
fun newContentRequestFinished() {
|
|
||||||
requestedNewContent = false
|
|
||||||
}
|
|
||||||
override fun onBindViewHolder(holder: FeedViewHolder, position: Int, payloads: List<Any>) {
|
|
||||||
holder.bindView(postList?.get(position) ?: return, payloads)
|
|
||||||
val totalItems = postList?.size
|
|
||||||
if(totalItems != null && totalItems > 0 && !requestedNewContent) {
|
|
||||||
if(position == totalItems - 1) {
|
|
||||||
requestedNewContent = true
|
|
||||||
if(payloads.isEmpty()) {
|
|
||||||
callback.onLoadMore()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val LOG_TAG = "PostsRecyclerViewAdapter"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
package com.isolaatti.posting.posts.presentation
|
|
||||||
|
|
||||||
data class UpdateEvent(val updateType: UpdateType, val affectedPosition: Int?) {
|
|
||||||
enum class UpdateType {
|
|
||||||
POST_LIKED,
|
|
||||||
POST_COMMENTED,
|
|
||||||
POST_REMOVED,
|
|
||||||
POST_ADDED,
|
|
||||||
PAGE_ADDED,
|
|
||||||
REFRESH
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,36 +1,48 @@
|
|||||||
package com.isolaatti.posting.posts.ui
|
package com.isolaatti.posting.posts.ui
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.compose.foundation.gestures.FlingBehavior
|
||||||
|
import androidx.compose.foundation.gestures.ScrollableDefaults
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.ComposeView
|
||||||
|
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import com.isolaatti.BuildConfig
|
import com.isolaatti.BuildConfig
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.audio.common.domain.Audio
|
import com.isolaatti.audio.common.domain.Audio
|
||||||
import com.isolaatti.common.Dialogs
|
import com.isolaatti.common.Dialogs
|
||||||
import com.isolaatti.common.ErrorMessageViewModel
|
import com.isolaatti.common.ErrorMessageViewModel
|
||||||
|
import com.isolaatti.common.IsolaattiTheme
|
||||||
import com.isolaatti.common.OnUserInteractedWithPostCallback
|
import com.isolaatti.common.OnUserInteractedWithPostCallback
|
||||||
import com.isolaatti.common.Ownable
|
import com.isolaatti.common.Ownable
|
||||||
import com.isolaatti.common.options_bottom_sheet.domain.OptionClicked
|
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
|
||||||
import com.isolaatti.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
|
import com.isolaatti.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
|
||||||
import com.isolaatti.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
|
import com.isolaatti.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
|
||||||
import com.isolaatti.databinding.FragmentPostListingBinding
|
|
||||||
import com.isolaatti.hashtags.ui.HashtagsPostsActivity
|
import com.isolaatti.hashtags.ui.HashtagsPostsActivity
|
||||||
import com.isolaatti.home.ui.FeedFragment
|
import com.isolaatti.home.ui.FeedFragment
|
||||||
|
import com.isolaatti.images.picture_viewer.ui.PictureViewerActivity
|
||||||
import com.isolaatti.posting.comments.ui.BottomSheetPostComments
|
import com.isolaatti.posting.comments.ui.BottomSheetPostComments
|
||||||
import com.isolaatti.posting.posts.domain.entity.Post
|
import com.isolaatti.posting.posts.domain.entity.Post
|
||||||
import com.isolaatti.posting.posts.presentation.EditPostContract
|
import com.isolaatti.posting.posts.presentation.EditPostContract
|
||||||
import com.isolaatti.posting.posts.presentation.PostListingViewModel
|
import com.isolaatti.posting.posts.presentation.PostListingViewModel
|
||||||
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
|
|
||||||
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
|
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
|
||||||
import com.isolaatti.profile.ui.ProfileActivity
|
import com.isolaatti.profile.ui.ProfileActivity
|
||||||
import com.isolaatti.reports.data.ContentType
|
import com.isolaatti.reports.data.ContentType
|
||||||
@ -38,7 +50,7 @@ import com.isolaatti.reports.ui.NewReportBottomSheetDialogFragment
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PostListingFragment : Fragment(), OnUserInteractedWithPostCallback {
|
class PostListingFragment : Fragment() {
|
||||||
companion object {
|
companion object {
|
||||||
const val ARG_HASHTAG = "hashtag"
|
const val ARG_HASHTAG = "hashtag"
|
||||||
const val LOG_TAG = "PostListingFragment"
|
const val LOG_TAG = "PostListingFragment"
|
||||||
@ -46,11 +58,9 @@ class PostListingFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
|
|
||||||
var hashtag: String? = null
|
var hashtag: String? = null
|
||||||
|
|
||||||
private lateinit var viewBinding: FragmentPostListingBinding
|
|
||||||
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
||||||
private val viewModel: PostListingViewModel by viewModels()
|
private val viewModel: PostListingViewModel by viewModels()
|
||||||
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
|
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
|
||||||
private lateinit var adapter: PostsRecyclerViewAdapter
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -59,43 +69,75 @@ class PostListingFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
viewModel.getFeed(false, hashtag)
|
viewModel.getFeed(false, hashtag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
viewBinding = FragmentPostListingBinding.inflate(inflater, container, false)
|
return ComposeView(requireContext()).apply {
|
||||||
return viewBinding.root
|
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||||
|
setContent {
|
||||||
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
|
val posts by viewModel.posts.collectAsState(emptyList())
|
||||||
|
IsolaattiTheme {
|
||||||
|
PullToRefreshBox(isRefreshing, onRefresh = {viewModel.getFeed(true, null)}) {
|
||||||
|
LazyColumn(flingBehavior = ScrollableDefaults.flingBehavior()) {
|
||||||
|
items(count = posts.size, key = {posts[it].id}) {
|
||||||
|
val post = posts[it]
|
||||||
|
com.isolaatti.posting.posts.components.Post(
|
||||||
|
modifier = Modifier.animateItem(),
|
||||||
|
post = post,
|
||||||
|
onClick = {
|
||||||
|
PostViewerActivity.startActivity(requireContext(), post.id)
|
||||||
|
},
|
||||||
|
onComments = {
|
||||||
|
val modalBottomSheet = BottomSheetPostComments.getInstance(post.id)
|
||||||
|
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostComments.TAG)
|
||||||
|
},
|
||||||
|
onOptions = {
|
||||||
|
optionsViewModel.setOptions(Options.POST_OPTIONS, FeedFragment.CALLER_ID, post)
|
||||||
|
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
||||||
|
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
||||||
|
},
|
||||||
|
onInfo = {
|
||||||
|
PostInfoActivity.startActivity(requireContext(), post.id)
|
||||||
|
},
|
||||||
|
onLike = {
|
||||||
|
viewModel.likePost(post.id)
|
||||||
|
},
|
||||||
|
onDislike = {
|
||||||
|
viewModel.unLikePost(post.id)
|
||||||
|
},
|
||||||
|
onShare = {
|
||||||
|
val intent = Intent.createChooser(Intent().apply {
|
||||||
|
action = Intent.ACTION_SEND
|
||||||
|
putExtra(Intent.EXTRA_TEXT, "${BuildConfig.backend}/pub/${post.id}")
|
||||||
|
type = "text/plain"
|
||||||
|
}, getString(R.string.share_post))
|
||||||
|
startActivity(intent)
|
||||||
|
},
|
||||||
|
onImageClick = { images, index ->
|
||||||
|
PictureViewerActivity.startActivityWithImages(requireContext(), images.toTypedArray(), index)
|
||||||
|
},
|
||||||
|
onUsernameClick = {
|
||||||
|
ProfileActivity.startActivity(requireContext(), post.userId)
|
||||||
|
},
|
||||||
|
onHashtagClick = { hashtag ->
|
||||||
|
HashtagsPostsActivity.startActivity(requireContext(), hashtag)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
adapter = PostsRecyclerViewAdapter(this)
|
|
||||||
viewBinding.feedRecyclerView.adapter = adapter
|
|
||||||
viewBinding.feedRecyclerView.setItemViewCacheSize(7)
|
|
||||||
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
|
||||||
|
|
||||||
|
|
||||||
viewBinding.swipeToRefresh.setOnRefreshListener {
|
|
||||||
viewModel.getFeed(refresh = true, hashtag)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.posts.observe(viewLifecycleOwner){
|
|
||||||
if (it?.first != null) {
|
|
||||||
adapter.updateList(it.first!!, it.second)
|
|
||||||
adapter.newContentRequestFinished()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.loadingPosts.observe(viewLifecycleOwner) {
|
|
||||||
viewBinding.loadingIndicator.visibility = if(it) View.VISIBLE else View.GONE
|
|
||||||
if(!it) {
|
|
||||||
viewBinding.swipeToRefresh.isRefreshing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
viewModel.errorLoading.observe(viewLifecycleOwner) {
|
viewModel.errorLoading.observe(viewLifecycleOwner) {
|
||||||
errorViewModel.error.postValue(it)
|
errorViewModel.error.postValue(it)
|
||||||
}
|
}
|
||||||
@ -103,19 +145,17 @@ class PostListingFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
|
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
override fun onLiked(postId: Long) = viewModel.likePost(postId)
|
override fun onLiked(postId: Long) = viewModel.likePost(postId)
|
||||||
|
|
||||||
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
||||||
|
|
||||||
override fun onOptions(post: Ownable) {
|
override fun onOptions(post: Ownable) {
|
||||||
optionsViewModel.setOptions(Options.POST_OPTIONS, FeedFragment.CALLER_ID, post)
|
|
||||||
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
|
||||||
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onComment(postId: Long) {
|
override fun onComment(postId: Long) {
|
||||||
val modalBottomSheet = BottomSheetPostComments.getInstance(postId)
|
|
||||||
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostComments.TAG)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenPost(postId: Long) {
|
override fun onOpenPost(postId: Long) {
|
||||||
@ -126,7 +166,7 @@ class PostListingFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onMoreInfo(postId: Long) {
|
override fun onMoreInfo(postId: Long) {
|
||||||
PostInfoActivity.startActivity(requireContext(), postId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onShare(postId: Long) {
|
override fun onShare(postId: Long) {
|
||||||
@ -150,6 +190,8 @@ class PostListingFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
viewModel.getFeed(false, hashtag)
|
viewModel.getFeed(false, hashtag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
private val editDiscussion = registerForActivityResult(EditPostContract()) {
|
private val editDiscussion = registerForActivityResult(EditPostContract()) {
|
||||||
if(it != null) {
|
if(it != null) {
|
||||||
viewModel.onPostUpdate(it)
|
viewModel.onPostUpdate(it)
|
||||||
|
|||||||
@ -60,10 +60,10 @@ class PostViewerViewModel @Inject constructor(private val loadSinglePost: LoadSi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLikesCount(likesCount: Int) {
|
private fun updateLikesCount(likesCount: Int) {
|
||||||
val updatedPost = post.value?.copy(numberOfLikes = likesCount)
|
// val updatedPost = post.value?.copy(numberOfLikes = likesCount)
|
||||||
if(updatedPost != null) {
|
// if(updatedPost != null) {
|
||||||
post.postValue(updatedPost!!)
|
// post.postValue(updatedPost!!)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun likeDislikePost() {
|
fun likeDislikePost() {
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import android.util.Log
|
|||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.core.app.TaskStackBuilder
|
import androidx.core.app.TaskStackBuilder
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import coil.imageLoader
|
import coil3.imageLoader
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.BuildConfig
|
import com.isolaatti.BuildConfig
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.common.IsolaattiBaseActivity
|
import com.isolaatti.common.IsolaattiBaseActivity
|
||||||
@ -153,7 +153,6 @@ class PostViewerActivity : IsolaattiBaseActivity() {
|
|||||||
.create(BuildConfig.backend))
|
.create(BuildConfig.backend))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.usePlugin(CoilImagesPlugin.create(this, imageLoader))
|
|
||||||
.usePlugin(LinkifyPlugin.create())
|
.usePlugin(LinkifyPlugin.create())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
package com.isolaatti.profile.presentation
|
package com.isolaatti.profile.presentation
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.isolaatti.followers.domain.FollowingState
|
import com.isolaatti.followers.domain.FollowingState
|
||||||
import com.isolaatti.images.common.domain.entity.RemoteImage
|
import com.isolaatti.images.common.domain.entity.RemoteImage
|
||||||
import com.isolaatti.posting.posts.presentation.PostListingViewModelBase
|
import com.isolaatti.posting.posts.presentation.PostListingViewModelBase
|
||||||
import com.isolaatti.posting.posts.presentation.UpdateEvent
|
|
||||||
import com.isolaatti.profile.domain.entity.UserProfile
|
import com.isolaatti.profile.domain.entity.UserProfile
|
||||||
import com.isolaatti.profile.domain.use_case.FollowUser
|
import com.isolaatti.profile.domain.use_case.FollowUser
|
||||||
import com.isolaatti.profile.domain.use_case.GetProfile
|
import com.isolaatti.profile.domain.use_case.GetProfile
|
||||||
@ -116,14 +116,14 @@ class ProfileViewModel @Inject constructor(
|
|||||||
override fun getFeed(refresh: Boolean, hashtag: String?) {
|
override fun getFeed(refresh: Boolean, hashtag: String?) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if(refresh) {
|
if(refresh) {
|
||||||
posts.value = Pair(null, UpdateEvent(UpdateEvent.UpdateType.REFRESH, null))
|
posts.value = emptyList()
|
||||||
getLastId()
|
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "getFeed")
|
||||||
getProfilePostsUseCase(profileId, getLastId(), false, null).onEach { feedDtoResource ->
|
getProfilePostsUseCase(profileId, getLastId(), false, null).onEach { feedDtoResource ->
|
||||||
when (feedDtoResource) {
|
when (feedDtoResource) {
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
loadingPosts.postValue(false)
|
loadingPosts.postValue(false)
|
||||||
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)))
|
posts.value += feedDtoResource.data ?: emptyList()
|
||||||
noMoreContent.postValue(feedDtoResource.data?.size == 0)
|
noMoreContent.postValue(feedDtoResource.data?.size == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.isolaatti.BuildConfig
|
import com.isolaatti.BuildConfig
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
@ -40,8 +40,6 @@ import com.isolaatti.posting.posts.domain.entity.Post
|
|||||||
import com.isolaatti.posting.posts.presentation.CreatePostContract
|
import com.isolaatti.posting.posts.presentation.CreatePostContract
|
||||||
import com.isolaatti.posting.posts.presentation.EditPostContract
|
import com.isolaatti.posting.posts.presentation.EditPostContract
|
||||||
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.UpdateEvent
|
|
||||||
import com.isolaatti.posting.posts.ui.PostInfoActivity
|
import com.isolaatti.posting.posts.ui.PostInfoActivity
|
||||||
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
|
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
|
||||||
import com.isolaatti.profile.domain.entity.UserProfile
|
import com.isolaatti.profile.domain.entity.UserProfile
|
||||||
@ -67,7 +65,6 @@ class ProfileMainFragment : Fragment() {
|
|||||||
val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
||||||
private var userId: Int? = null
|
private var userId: Int? = null
|
||||||
|
|
||||||
lateinit var postsAdapter: PostsRecyclerViewAdapter
|
|
||||||
|
|
||||||
private var audioDescriptionAudio: Audio? = null
|
private var audioDescriptionAudio: Audio? = null
|
||||||
|
|
||||||
@ -129,13 +126,13 @@ class ProfileMainFragment : Fragment() {
|
|||||||
setupUiForUserType(profile.isUserItself)
|
setupUiForUserType(profile.isUserItself)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val postsObserver: Observer<Pair<List<Post>?, 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()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
|
||||||
private val followingStateObserver: Observer<FollowingState> = Observer {
|
private val followingStateObserver: Observer<FollowingState> = Observer {
|
||||||
when(it) {
|
when(it) {
|
||||||
@ -310,8 +307,8 @@ class ProfileMainFragment : Fragment() {
|
|||||||
findNavController().navigate(ProfileMainFragmentDirections.actionDiscussionsFragmentToMainFollowersFragment(userId!!))
|
findNavController().navigate(ProfileMainFragmentDirections.actionDiscussionsFragmentToMainFollowersFragment(userId!!))
|
||||||
}
|
}
|
||||||
|
|
||||||
viewBinding.feedRecyclerView.adapter = postsAdapter
|
// viewBinding.feedRecyclerView.adapter = postsAdapter
|
||||||
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
// viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||||
|
|
||||||
viewBinding.swipeToRefresh.setOnRefreshListener {
|
viewBinding.swipeToRefresh.setOnRefreshListener {
|
||||||
viewModel.getFeed(true, null)
|
viewModel.getFeed(true, null)
|
||||||
@ -330,7 +327,7 @@ class ProfileMainFragment : Fragment() {
|
|||||||
|
|
||||||
private fun setObservers() {
|
private fun setObservers() {
|
||||||
viewModel.profile.observe(viewLifecycleOwner, profileObserver)
|
viewModel.profile.observe(viewLifecycleOwner, profileObserver)
|
||||||
viewModel.posts.observe(viewLifecycleOwner, postsObserver)
|
//viewModel.posts.observe(viewLifecycleOwner, postsObserver)
|
||||||
viewModel.followingState.observe(viewLifecycleOwner, followingStateObserver)
|
viewModel.followingState.observe(viewLifecycleOwner, followingStateObserver)
|
||||||
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
|
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
|
||||||
viewModel.loadingPosts.observe(viewLifecycleOwner) {
|
viewModel.loadingPosts.observe(viewLifecycleOwner) {
|
||||||
@ -366,11 +363,10 @@ class ProfileMainFragment : Fragment() {
|
|||||||
.create(BuildConfig.backend))
|
.create(BuildConfig.backend))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.usePlugin(CoilImagesPlugin.create(requireContext(), imageLoader))
|
|
||||||
.usePlugin(LinkifyPlugin.create())
|
.usePlugin(LinkifyPlugin.create())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
postsAdapter = PostsRecyclerViewAdapter(postListingRecyclerViewAdapterWiring )
|
//postsAdapter = PostsRecyclerViewAdapter(postListingRecyclerViewAdapterWiring )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,9 @@ import androidx.core.app.ActivityCompat
|
|||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import coil.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
|
import coil3.request.fallback
|
||||||
|
import coil3.toBitmap
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService
|
import com.google.firebase.messaging.FirebaseMessagingService
|
||||||
import com.google.firebase.messaging.RemoteMessage
|
import com.google.firebase.messaging.RemoteMessage
|
||||||
import com.isolaatti.MyApplication
|
import com.isolaatti.MyApplication
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.databinding.SearchResultItemBinding
|
import com.isolaatti.databinding.SearchResultItemBinding
|
||||||
import com.isolaatti.search.data.SearchResultDto
|
import com.isolaatti.search.data.SearchResultDto
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.databinding.UsersCarouselItemBinding
|
import com.isolaatti.databinding.UsersCarouselItemBinding
|
||||||
import com.isolaatti.profile.domain.entity.ProfileListItem
|
import com.isolaatti.profile.domain.entity.ProfileListItem
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import coil.load
|
import coil3.load
|
||||||
import com.isolaatti.databinding.FragmentSettingsBinding
|
import com.isolaatti.databinding.FragmentSettingsBinding
|
||||||
import com.isolaatti.settings.presentation.SettingsViewModel
|
import com.isolaatti.settings.presentation.SettingsViewModel
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user