更新UI
This commit is contained in:
@@ -2,6 +2,6 @@ package com.aiosman.riderpro
|
|||||||
|
|
||||||
object ConstVars {
|
object ConstVars {
|
||||||
// api 地址
|
// api 地址
|
||||||
const val BASE_SERVER = "http://192.168.31.250:8088"
|
// const val BASE_SERVER = "http://192.168.31.250:8088"
|
||||||
// const val BASE_SERVER = "https://8.137.22.101:8088"
|
const val BASE_SERVER = "https://8.137.22.101:8088"
|
||||||
}
|
}
|
||||||
@@ -44,13 +44,12 @@ data class Moment(
|
|||||||
val time: String
|
val time: String
|
||||||
) {
|
) {
|
||||||
fun toMomentItem(): MomentEntity {
|
fun toMomentItem(): MomentEntity {
|
||||||
val avatar = "${ApiClient.BASE_SERVER}${user.avatar}"
|
|
||||||
return MomentEntity(
|
return MomentEntity(
|
||||||
id = id.toInt(),
|
id = id.toInt(),
|
||||||
avatar = "${ApiClient.BASE_SERVER}${user.avatar}",
|
avatar = "${ApiClient.BASE_SERVER}${user.avatar}",
|
||||||
nickname = user.nickName,
|
nickname = user.nickName,
|
||||||
location = "Worldwide",
|
location = "Worldwide",
|
||||||
time = time,
|
time = ApiClient.dateFromApiString(time),
|
||||||
followStatus = false,
|
followStatus = false,
|
||||||
momentTextContent = textContent,
|
momentTextContent = textContent,
|
||||||
momentPicture = R.drawable.default_moment_img,
|
momentPicture = R.drawable.default_moment_img,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.aiosman.riderpro.exp
|
package com.aiosman.riderpro.exp
|
||||||
|
|
||||||
import android.icu.text.SimpleDateFormat
|
import android.icu.text.SimpleDateFormat
|
||||||
|
import android.icu.util.Calendar
|
||||||
import com.aiosman.riderpro.data.api.ApiClient
|
import com.aiosman.riderpro.data.api.ApiClient
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -22,4 +23,18 @@ fun Date.timeAgo(): String {
|
|||||||
days < 365 -> "$days days ago"
|
days < 365 -> "$days days ago"
|
||||||
else -> "$years years ago"
|
else -> "$years years ago"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Date.formatPostTime(): String {
|
||||||
|
val now = Calendar.getInstance()
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
calendar.time = this
|
||||||
|
val year = calendar.get(Calendar.YEAR)
|
||||||
|
var nowYear = now.get(Calendar.YEAR)
|
||||||
|
val dateFormat = if (year == nowYear) {
|
||||||
|
SimpleDateFormat("MM-dd", Locale.getDefault())
|
||||||
|
} else {
|
||||||
|
SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||||
|
}
|
||||||
|
return dateFormat.format(this)
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.aiosman.riderpro.model
|
package com.aiosman.riderpro.model
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
data class MomentImageEntity(
|
data class MomentImageEntity(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
@@ -14,7 +15,7 @@ data class MomentEntity(
|
|||||||
val avatar: String,
|
val avatar: String,
|
||||||
val nickname: String,
|
val nickname: String,
|
||||||
val location: String,
|
val location: String,
|
||||||
val time: String,
|
val time: Date,
|
||||||
val followStatus: Boolean,
|
val followStatus: Boolean,
|
||||||
val momentTextContent: String,
|
val momentTextContent: String,
|
||||||
@DrawableRes val momentPicture: Int,
|
@DrawableRes val momentPicture: Int,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.google.gson.GsonBuilder
|
|||||||
import io.github.serpro69.kfaker.faker
|
import io.github.serpro69.kfaker.faker
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
object TestDatabase {
|
object TestDatabase {
|
||||||
var momentData = emptyList<MomentEntity>()
|
var momentData = emptyList<MomentEntity>()
|
||||||
@@ -120,7 +121,7 @@ object TestDatabase {
|
|||||||
avatar = person.avatar,
|
avatar = person.avatar,
|
||||||
nickname = person.nickName,
|
nickname = person.nickName,
|
||||||
location = person.country,
|
location = person.country,
|
||||||
time = "2023.02.02 11:23",
|
time = Date(),
|
||||||
followStatus = false,
|
followStatus = false,
|
||||||
momentTextContent = "By strongarming Ducati into giving him the factory seat.Marquez effectively …",
|
momentTextContent = "By strongarming Ducati into giving him the factory seat.Marquez effectively …",
|
||||||
momentPicture = R.drawable.default_moment_img,
|
momentPicture = R.drawable.default_moment_img,
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ import ImageViewer
|
|||||||
import ModificationListScreen
|
import ModificationListScreen
|
||||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||||
import androidx.compose.animation.SharedTransitionLayout
|
import androidx.compose.animation.SharedTransitionLayout
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideInHorizontally
|
||||||
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
@@ -121,7 +126,13 @@ fun NavigationController(
|
|||||||
}
|
}
|
||||||
composable(
|
composable(
|
||||||
route = NavigationRoute.Post.route,
|
route = NavigationRoute.Post.route,
|
||||||
arguments = listOf(navArgument("id") { type = NavType.StringType })
|
arguments = listOf(navArgument("id") { type = NavType.StringType }),
|
||||||
|
enterTransition = {
|
||||||
|
fadeIn(animationSpec = tween(durationMillis = 100))
|
||||||
|
},
|
||||||
|
exitTransition = {
|
||||||
|
fadeOut(animationSpec = tween(durationMillis = 100))
|
||||||
|
}
|
||||||
) { backStackEntry ->
|
) { backStackEntry ->
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalAnimatedContentScope provides this,
|
LocalAnimatedContentScope provides this,
|
||||||
@@ -147,7 +158,16 @@ fun NavigationController(
|
|||||||
composable(route = NavigationRoute.Followers.route) {
|
composable(route = NavigationRoute.Followers.route) {
|
||||||
FollowerScreen()
|
FollowerScreen()
|
||||||
}
|
}
|
||||||
composable(route = NavigationRoute.NewPost.route) {
|
composable(
|
||||||
|
route = NavigationRoute.NewPost.route,
|
||||||
|
enterTransition = {
|
||||||
|
|
||||||
|
fadeIn(animationSpec = tween(durationMillis = 100))
|
||||||
|
},
|
||||||
|
exitTransition = {
|
||||||
|
fadeOut(animationSpec = tween(durationMillis = 100))
|
||||||
|
}
|
||||||
|
) {
|
||||||
NewPostScreen()
|
NewPostScreen()
|
||||||
}
|
}
|
||||||
composable(route = NavigationRoute.EditModification.route) {
|
composable(route = NavigationRoute.EditModification.route) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.aiosman.riderpro.ui.composables
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -46,10 +47,12 @@ fun rememberImageBitmap(imageUrl: String, imageLoader: ImageLoader): Bitmap? {
|
|||||||
@Composable
|
@Composable
|
||||||
fun CustomAsyncImage(
|
fun CustomAsyncImage(
|
||||||
context: Context,
|
context: Context,
|
||||||
imageUrl: String,
|
imageUrl: String?,
|
||||||
contentDescription: String?,
|
contentDescription: String?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
blurHash: String? = null,
|
blurHash: String? = null,
|
||||||
|
@DrawableRes
|
||||||
|
placeholderRes: Int? = null,
|
||||||
contentScale: ContentScale = ContentScale.Crop
|
contentScale: ContentScale = ContentScale.Crop
|
||||||
) {
|
) {
|
||||||
val imageLoader = getImageLoader(context)
|
val imageLoader = getImageLoader(context)
|
||||||
@@ -63,30 +66,35 @@ fun CustomAsyncImage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var bitmap by remember(imageUrl) { mutableStateOf<Bitmap?>(null) }
|
// var bitmap by remember(imageUrl) { mutableStateOf<Bitmap?>(null) }
|
||||||
|
//
|
||||||
LaunchedEffect(imageUrl) {
|
// LaunchedEffect(imageUrl) {
|
||||||
if (bitmap == null) {
|
// if (bitmap == null) {
|
||||||
val request = ImageRequest.Builder(context)
|
// val request = ImageRequest.Builder(context)
|
||||||
.data(imageUrl)
|
// .data(imageUrl)
|
||||||
.crossfade(true)
|
// .crossfade(3000)
|
||||||
.build()
|
// .build()
|
||||||
|
//
|
||||||
val result = withContext(Dispatchers.IO) {
|
// val result = withContext(Dispatchers.IO) {
|
||||||
(imageLoader.execute(request) as? SuccessResult)?.drawable?.toBitmap()
|
// (imageLoader.execute(request) as? SuccessResult)?.drawable?.toBitmap()
|
||||||
}
|
// }
|
||||||
bitmap = result
|
// bitmap = result
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = bitmap ?: ImageRequest.Builder(context)
|
model = ImageRequest.Builder(context)
|
||||||
.data(imageUrl)
|
.data(imageUrl)
|
||||||
.crossfade(true)
|
.crossfade(200)
|
||||||
.apply {
|
.apply {
|
||||||
|
if (placeholderRes != null) {
|
||||||
|
placeholder(placeholderRes)
|
||||||
|
return@apply
|
||||||
|
}
|
||||||
if (blurBitmap != null) {
|
if (blurBitmap != null) {
|
||||||
placeholder(blurBitmap.toDrawable(context.resources))
|
placeholder(blurBitmap.toDrawable(context.resources))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.build(),
|
.build(),
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.aiosman.riderpro.ui.index
|
|||||||
|
|
||||||
import androidx.compose.animation.animateColorAsState
|
import androidx.compose.animation.animateColorAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.slideInHorizontally
|
||||||
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -25,6 +27,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.navOptions
|
||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
import com.aiosman.riderpro.ui.index.tabs.add.AddPage
|
import com.aiosman.riderpro.ui.index.tabs.add.AddPage
|
||||||
@@ -35,6 +38,7 @@ import com.aiosman.riderpro.ui.index.tabs.search.SearchScreen
|
|||||||
import com.aiosman.riderpro.ui.index.tabs.shorts.ShortVideo
|
import com.aiosman.riderpro.ui.index.tabs.shorts.ShortVideo
|
||||||
import com.aiosman.riderpro.ui.index.tabs.street.StreetPage
|
import com.aiosman.riderpro.ui.index.tabs.street.StreetPage
|
||||||
import com.aiosman.riderpro.ui.message.MessagePage
|
import com.aiosman.riderpro.ui.message.MessagePage
|
||||||
|
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -56,7 +60,7 @@ fun IndexScreen() {
|
|||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
systemUiController.setNavigationBarColor(Color.Transparent)
|
// systemUiController.setNavigationBarColor(Color.Transparent)
|
||||||
}
|
}
|
||||||
Scaffold(
|
Scaffold(
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
@@ -73,8 +77,14 @@ fun IndexScreen() {
|
|||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
selected = isSelected,
|
selected = isSelected,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
||||||
if (it.route === NavigationItem.Add.route) {
|
if (it.route === NavigationItem.Add.route) {
|
||||||
navController.navigate(NavigationRoute.NewPost.route)
|
NewPostViewModel.asNewPost()
|
||||||
|
|
||||||
|
navController.navigate(
|
||||||
|
NavigationRoute.NewPost.route,
|
||||||
|
|
||||||
|
)
|
||||||
return@NavigationBarItem
|
return@NavigationBarItem
|
||||||
}
|
}
|
||||||
model.tabIndex = idx
|
model.tabIndex = idx
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import com.aiosman.riderpro.LocalAnimatedContentScope
|
|||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.LocalSharedTransitionScope
|
import com.aiosman.riderpro.LocalSharedTransitionScope
|
||||||
import com.aiosman.riderpro.R
|
import com.aiosman.riderpro.R
|
||||||
|
import com.aiosman.riderpro.exp.timeAgo
|
||||||
import com.aiosman.riderpro.model.MomentEntity
|
import com.aiosman.riderpro.model.MomentEntity
|
||||||
import com.aiosman.riderpro.model.MomentImageEntity
|
import com.aiosman.riderpro.model.MomentImageEntity
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
@@ -76,6 +77,7 @@ import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
|||||||
import com.aiosman.riderpro.ui.composables.RelPostCard
|
import com.aiosman.riderpro.ui.composables.RelPostCard
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
||||||
|
import com.aiosman.riderpro.ui.post.PostViewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -160,6 +162,7 @@ fun MomentCard(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
|
PostViewModel.preTransit(momentEntity)
|
||||||
navController.navigate("Post/${momentEntity.id}")
|
navController.navigate("Post/${momentEntity.id}")
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@@ -327,7 +330,7 @@ fun MomentTopRowGroup(momentEntity: MomentEntity) {
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
MomentPostLocation(momentEntity.location)
|
MomentPostLocation(momentEntity.location)
|
||||||
MomentPostTime(momentEntity.time)
|
MomentPostTime(momentEntity.time.timeAgo())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,7 +358,6 @@ fun PostImageView(
|
|||||||
.aspectRatio(1f),
|
.aspectRatio(1f),
|
||||||
) { page ->
|
) { page ->
|
||||||
val image = images[page]
|
val image = images[page]
|
||||||
with(sharedTransitionScope) {
|
|
||||||
// AsyncBlurImage(
|
// AsyncBlurImage(
|
||||||
// imageUrl = image.url,
|
// imageUrl = image.url,
|
||||||
// blurHash = image.blurHash ?: "",
|
// blurHash = image.blurHash ?: "",
|
||||||
@@ -375,10 +377,6 @@ fun PostImageView(
|
|||||||
blurHash = image.blurHash,
|
blurHash = image.blurHash,
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.sharedElement(
|
|
||||||
rememberSharedContentState(key = image),
|
|
||||||
animatedVisibilityScope = animatedVisibilityScope
|
|
||||||
)
|
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
// .noRippleClickable {
|
// .noRippleClickable {
|
||||||
// ImageViewerViewModel.asNew(images, page)
|
// ImageViewerViewModel.asNew(images, page)
|
||||||
@@ -387,7 +385,7 @@ fun PostImageView(
|
|||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicator container
|
// Indicator container
|
||||||
|
|||||||
@@ -53,10 +53,12 @@ import com.aiosman.riderpro.LocalNavController
|
|||||||
import com.aiosman.riderpro.LocalSharedTransitionScope
|
import com.aiosman.riderpro.LocalSharedTransitionScope
|
||||||
import com.aiosman.riderpro.R
|
import com.aiosman.riderpro.R
|
||||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||||
|
import com.aiosman.riderpro.exp.formatPostTime
|
||||||
import com.aiosman.riderpro.model.MomentEntity
|
import com.aiosman.riderpro.model.MomentEntity
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.riderpro.ui.post.PostViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
@@ -457,13 +459,13 @@ fun UserMoment(scope: LazyListScope) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MomentPostUnit(momentEntity: MomentEntity) {
|
fun MomentPostUnit(momentEntity: MomentEntity) {
|
||||||
TimeGroup(momentEntity.time)
|
TimeGroup(momentEntity.time.formatPostTime())
|
||||||
ProfileMomentCard(
|
ProfileMomentCard(
|
||||||
momentEntity.momentTextContent,
|
momentEntity.momentTextContent,
|
||||||
momentEntity.images[0].thumbnail,
|
momentEntity.images[0].thumbnail,
|
||||||
momentEntity.likeCount.toString(),
|
momentEntity.likeCount.toString(),
|
||||||
momentEntity.commentCount.toString(),
|
momentEntity.commentCount.toString(),
|
||||||
momentId = momentEntity.id
|
momentEntity = momentEntity
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,7 +498,7 @@ fun ProfileMomentCard(
|
|||||||
imageUrl: String,
|
imageUrl: String,
|
||||||
like: String,
|
like: String,
|
||||||
comment: String,
|
comment: String,
|
||||||
momentId: Int
|
momentEntity: MomentEntity
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -505,7 +507,7 @@ fun ProfileMomentCard(
|
|||||||
.border(width = 1.dp, color = Color(0f, 0f, 0f, 0.1f), shape = RoundedCornerShape(6.dp))
|
.border(width = 1.dp, color = Color(0f, 0f, 0f, 0.1f), shape = RoundedCornerShape(6.dp))
|
||||||
) {
|
) {
|
||||||
MomentCardTopContent(content)
|
MomentCardTopContent(content)
|
||||||
MomentCardPicture(imageUrl, momentId)
|
MomentCardPicture(imageUrl, momentEntity = momentEntity)
|
||||||
MomentCardOperation(like, comment)
|
MomentCardOperation(like, comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,7 +529,7 @@ fun MomentCardTopContent(content: String) {
|
|||||||
|
|
||||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
@OptIn(ExperimentalSharedTransitionApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MomentCardPicture(imageUrl: String, momentId: Int) {
|
fun MomentCardPicture(imageUrl: String, momentEntity: MomentEntity) {
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val sharedTransitionScope = LocalSharedTransitionScope.current
|
val sharedTransitionScope = LocalSharedTransitionScope.current
|
||||||
val animatedVisibilityScope = LocalAnimatedContentScope.current
|
val animatedVisibilityScope = LocalAnimatedContentScope.current
|
||||||
@@ -544,10 +546,11 @@ fun MomentCardPicture(imageUrl: String, momentId: Int) {
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
|
PostViewModel.preTransit(momentEntity)
|
||||||
navController.navigate(
|
navController.navigate(
|
||||||
NavigationRoute.Post.route.replace(
|
NavigationRoute.Post.route.replace(
|
||||||
"{id}",
|
"{id}",
|
||||||
momentId.toString()
|
momentEntity.id.toString()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ fun NewPostScreen() {
|
|||||||
}
|
}
|
||||||
StatusBarMaskLayout(
|
StatusBarMaskLayout(
|
||||||
darkIcons = true,
|
darkIcons = true,
|
||||||
|
modifier = Modifier.fillMaxSize().background(Color.White)
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ import com.aiosman.riderpro.data.AccountServiceImpl
|
|||||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||||
import com.aiosman.riderpro.data.UserService
|
import com.aiosman.riderpro.data.UserService
|
||||||
|
import com.aiosman.riderpro.exp.formatPostTime
|
||||||
import com.aiosman.riderpro.exp.timeAgo
|
import com.aiosman.riderpro.exp.timeAgo
|
||||||
import com.aiosman.riderpro.model.MomentEntity
|
import com.aiosman.riderpro.model.MomentEntity
|
||||||
import com.aiosman.riderpro.model.MomentImageEntity
|
import com.aiosman.riderpro.model.MomentImageEntity
|
||||||
@@ -104,16 +105,29 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class PostViewModel(
|
object PostViewModel : ViewModel() {
|
||||||
val postId: String
|
|
||||||
) : ViewModel() {
|
|
||||||
var service: MomentService = TestMomentServiceImpl()
|
var service: MomentService = TestMomentServiceImpl()
|
||||||
var commentService: CommentService = TestCommentServiceImpl()
|
var commentService: CommentService = TestCommentServiceImpl()
|
||||||
var userService: UserService = TestUserServiceImpl()
|
var userService: UserService = TestUserServiceImpl()
|
||||||
private var _commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
private var _commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
||||||
val commentsFlow = _commentsFlow.asStateFlow()
|
val commentsFlow = _commentsFlow.asStateFlow()
|
||||||
|
var postId: String = ""
|
||||||
|
|
||||||
|
// 预加载的 moment
|
||||||
|
|
||||||
|
var accountProfileEntity by mutableStateOf<AccountProfileEntity?>(null)
|
||||||
|
var moment by mutableStateOf<MomentEntity?>(null)
|
||||||
|
var accountService: AccountService = AccountServiceImpl()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预加载,在跳转到 PostScreen 之前设置好内容
|
||||||
|
*/
|
||||||
|
fun preTransit(momentEntity: MomentEntity?) {
|
||||||
|
this.postId = momentEntity?.id.toString()
|
||||||
|
this.moment = momentEntity
|
||||||
|
this._commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
||||||
|
this.accountProfileEntity = null
|
||||||
|
|
||||||
init {
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Pager(
|
Pager(
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||||
@@ -129,10 +143,6 @@ class PostViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var accountProfileEntity by mutableStateOf<AccountProfileEntity?>(null)
|
|
||||||
var moment by mutableStateOf<MomentEntity?>(null)
|
|
||||||
var accountService: AccountService = AccountServiceImpl()
|
|
||||||
|
|
||||||
suspend fun initData() {
|
suspend fun initData() {
|
||||||
moment = service.getMomentById(postId.toInt())
|
moment = service.getMomentById(postId.toInt())
|
||||||
moment?.let {
|
moment?.let {
|
||||||
@@ -220,20 +230,35 @@ class PostViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var avatar: String? = null
|
||||||
|
get() {
|
||||||
|
accountProfileEntity?.avatar?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
moment?.avatar?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
var nickname: String? = null
|
||||||
|
get() {
|
||||||
|
accountProfileEntity?.nickName?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
moment?.nickname?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PostScreen(
|
fun PostScreen(
|
||||||
id: String,
|
id: String,
|
||||||
) {
|
) {
|
||||||
val viewModel = viewModel<PostViewModel>(
|
val viewModel = PostViewModel
|
||||||
key = "PostViewModel_$id",
|
|
||||||
factory = object : ViewModelProvider.Factory {
|
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
|
||||||
return PostViewModel(id) as T
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val commentsPagging = viewModel.commentsFlow.collectAsLazyPagingItems()
|
val commentsPagging = viewModel.commentsFlow.collectAsLazyPagingItems()
|
||||||
@@ -283,8 +308,8 @@ fun PostScreen(
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Header(
|
Header(
|
||||||
avatar = viewModel.moment?.avatar,
|
avatar = viewModel.avatar,
|
||||||
nickname = viewModel.moment?.nickname,
|
nickname = viewModel.nickname,
|
||||||
userId = viewModel.moment?.authorId,
|
userId = viewModel.moment?.authorId,
|
||||||
isFollowing = viewModel.accountProfileEntity?.isFollowing ?: false,
|
isFollowing = viewModel.accountProfileEntity?.isFollowing ?: false,
|
||||||
onFollowClick = {
|
onFollowClick = {
|
||||||
@@ -373,10 +398,15 @@ fun Header(
|
|||||||
.size(32.dp)
|
.size(32.dp)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
avatar?.let {
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(40.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(Color.Gray.copy(alpha = 0.1f))
|
||||||
|
) {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
context,
|
context,
|
||||||
it,
|
avatar,
|
||||||
contentDescription = "Profile Picture",
|
contentDescription = "Profile Picture",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(40.dp)
|
||||||
@@ -395,7 +425,6 @@ fun Header(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Text(text = nickname ?: "", fontWeight = FontWeight.Bold)
|
Text(text = nickname ?: "", fontWeight = FontWeight.Bold)
|
||||||
Box(
|
Box(
|
||||||
@@ -441,7 +470,8 @@ fun PostImageView(
|
|||||||
state = pagerState,
|
state = pagerState,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.fillMaxWidth().background(Color.Gray.copy(alpha = 0.1f)),
|
.fillMaxWidth()
|
||||||
|
.background(Color.Gray.copy(alpha = 0.1f)),
|
||||||
) { page ->
|
) { page ->
|
||||||
val image = images[page]
|
val image = images[page]
|
||||||
with(sharedTransitionScope) {
|
with(sharedTransitionScope) {
|
||||||
@@ -514,7 +544,7 @@ fun PostDetails(
|
|||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
Text(text = "12-11 发布")
|
Text(text = "${momentEntity?.time?.formatPostTime()} 发布")
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(text = "${momentEntity?.commentCount ?: 0} Comments")
|
Text(text = "${momentEntity?.commentCount ?: 0} Comments")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user