This commit is contained in:
2024-08-11 17:15:17 +08:00
parent 2dc0ee3307
commit 19527f17c3
32 changed files with 1082 additions and 417 deletions

View File

@@ -159,7 +159,11 @@ fun NavigationController(
route = NavigationRoute.AccountProfile.route,
arguments = listOf(navArgument("id") { type = NavType.StringType })
) {
AccountProfile(it.arguments?.getString("id")!!)
CompositionLocalProvider(
LocalAnimatedContentScope provides this,
) {
AccountProfile(it.arguments?.getString("id")!!)
}
}
composable(route = NavigationRoute.SignUp.route) {
SignupScreen()

View File

@@ -31,7 +31,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import com.aiosman.riderpro.data.AccountProfile
import com.aiosman.riderpro.data.AccountProfileEntity
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.TestAccountServiceImpl
import com.aiosman.riderpro.data.TestUserServiceImpl
@@ -47,7 +47,7 @@ fun AccountEditScreen() {
var name by remember { mutableStateOf("") }
var bio by remember { mutableStateOf("") }
var profile by remember {
mutableStateOf<AccountProfile?>(
mutableStateOf<AccountProfileEntity?>(
null
)
}

View File

@@ -47,7 +47,7 @@ import androidx.paging.cachedIn
import androidx.paging.compose.collectAsLazyPagingItems
import com.aiosman.riderpro.ui.post.CommentsSection
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.Comment
import com.aiosman.riderpro.data.CommentEntity
import com.aiosman.riderpro.data.CommentPagingSource
import com.aiosman.riderpro.data.CommentRemoteDataSource
import com.aiosman.riderpro.data.CommentService
@@ -57,10 +57,10 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
class CommentModalViewModel(
postId: Int?
val postId: Int?
) : ViewModel() {
val commentService: CommentService = TestCommentServiceImpl()
val commentsFlow: Flow<PagingData<Comment>> = Pager(
val commentsFlow: Flow<PagingData<CommentEntity>> = Pager(
config = PagingConfig(pageSize = 20, enablePlaceholders = false),
pagingSourceFactory = {
CommentPagingSource(
@@ -69,6 +69,12 @@ class CommentModalViewModel(
)
}
).flow.cachedIn(viewModelScope)
suspend fun createComment(content: String) {
postId?.let {
commentService.createComment(postId, content)
}
}
}
@Preview
@@ -104,8 +110,7 @@ fun CommentModalContent(
var commentText by remember { mutableStateOf("") }
suspend fun sendComment() {
if (commentText.isNotEmpty()) {
model.commentService.createComment(postId!!, commentText, 1)
commentText = ""
model.createComment(commentText)
}
comments.refresh()
onCommentAdded()
@@ -136,13 +141,16 @@ fun CommentModalContent(
.padding(horizontal = 16.dp)
.weight(1f)
) {
CommentsSection(lazyPagingItems = comments, onLike = { comment: Comment ->
CommentsSection(lazyPagingItems = comments, onLike = { commentEntity: CommentEntity ->
scope.launch {
model.commentService.likeComment(comment.id)
if (commentEntity.liked) {
model.commentService.dislikeComment(commentEntity.id)
} else {
model.commentService.likeComment(commentEntity.id)
}
comments.refresh()
}
}) {
}
}

View File

@@ -0,0 +1,68 @@
package com.aiosman.riderpro.ui.composables
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.res.painterResource
import com.aiosman.riderpro.R
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import kotlinx.coroutines.launch
@Composable
fun AnimatedFavouriteIcon(
modifier: Modifier = Modifier,
isFavourite: Boolean = false,
onClick: (() -> Unit)? = null
) {
val animatableRotation = remember { Animatable(0f) }
val animatedColor by animateColorAsState(targetValue = if (isFavourite) Color(0xFFd83737) else Color.Black)
val scope = rememberCoroutineScope()
suspend fun shake() {
repeat(2) {
animatableRotation.animateTo(
targetValue = 10f,
animationSpec = tween(100)
) {
}
animatableRotation.animateTo(
targetValue = -10f,
animationSpec = tween(100)
) {
}
}
animatableRotation.animateTo(
targetValue = 0f,
animationSpec = tween(100)
)
}
Box(contentAlignment = Alignment.Center, modifier = Modifier.noRippleClickable {
onClick?.invoke()
// Trigger shake animation
scope.launch {
shake()
}
}) {
Image(
painter = painterResource(id = R.drawable.rider_pro_favoriate),
contentDescription = "Like",
modifier = modifier.graphicsLayer {
rotationZ = animatableRotation.value
},
colorFilter = ColorFilter.tint(animatedColor)
)
}
}

View File

@@ -9,19 +9,19 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.ui.index.tabs.moment.MomentTopRowGroup
@Composable
fun RelPostCard(
momentItem: MomentItem,
momentEntity: MomentEntity,
modifier: Modifier = Modifier,
) {
val image = momentItem.images.firstOrNull()
val image = momentEntity.images.firstOrNull()
Column(
modifier = modifier
) {
MomentTopRowGroup(momentItem = momentItem)
MomentTopRowGroup(momentEntity = momentEntity)
Box(
modifier=Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
) {

View File

@@ -53,18 +53,20 @@ import androidx.compose.ui.unit.sp
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import coil.compose.AsyncImage
import com.aiosman.riderpro.LocalAnimatedContentScope
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.LocalSharedTransitionScope
import com.aiosman.riderpro.R
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.comment.CommentModalContent
import com.aiosman.riderpro.ui.composables.AnimatedCounter
import com.aiosman.riderpro.ui.composables.AnimatedFavouriteIcon
import com.aiosman.riderpro.ui.composables.AnimatedLikeIcon
import com.aiosman.riderpro.ui.composables.RelPostCard
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.aiosman.riderpro.ui.post.NewPostViewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterialApi::class)
@@ -88,10 +90,12 @@ fun MomentsList() {
}
Box(Modifier.pullRefresh(state)) {
LazyColumn {
LazyColumn(
modifier = Modifier.fillMaxSize(),
) {
items(moments.itemCount) { idx ->
val momentItem = moments[idx] ?: return@items
MomentCard(momentItem = momentItem,
MomentCard(momentEntity = momentItem,
onAddComment = {
scope.launch {
model.onAddComment(momentItem.id)
@@ -105,6 +109,15 @@ fun MomentsList() {
model.likeMoment(momentItem.id)
}
}
},
onFavoriteClick = {
scope.launch {
if (momentItem.isFavorite) {
model.unfavoriteMoment(momentItem.id)
} else {
model.favoriteMoment(momentItem.id)
}
}
}
)
}
@@ -115,38 +128,40 @@ fun MomentsList() {
@Composable
fun MomentCard(
momentItem: MomentItem,
momentEntity: MomentEntity,
onLikeClick: () -> Unit,
onFavoriteClick: () -> Unit = {},
onAddComment: () -> Unit = {}
) {
val navController = LocalNavController.current
Column(
modifier = Modifier.fillMaxWidth()
) {
MomentTopRowGroup(momentItem = momentItem)
MomentTopRowGroup(momentEntity = momentEntity)
Column(
modifier = Modifier
.fillMaxWidth()
.noRippleClickable {
navController.navigate("Post/${momentItem.id}")
navController.navigate("Post/${momentEntity.id}")
}
) {
MomentContentGroup(momentItem = momentItem)
MomentContentGroup(momentEntity = momentEntity)
}
val momentOperateBtnBoxModifier = Modifier
.fillMaxHeight()
.weight(1f)
ModificationListHeader()
// ModificationListHeader()
MomentBottomOperateRowGroup(
momentOperateBtnBoxModifier,
momentItem = momentItem,
momentEntity = momentEntity,
onLikeClick = onLikeClick,
onAddComment = onAddComment,
onShareClick = {
NewPostViewModel.asNewPost()
NewPostViewModel.relPostId = momentItem.id
NewPostViewModel.relPostId = momentEntity.id
navController.navigate(NavigationRoute.NewPost.route)
}
},
onFavoriteClick = onFavoriteClick
)
}
}
@@ -248,7 +263,7 @@ fun MomentPostTime(time: String) {
}
@Composable
fun MomentTopRowGroup(momentItem: MomentItem) {
fun MomentTopRowGroup(momentEntity: MomentEntity) {
val navController = LocalNavController.current
Row(
modifier = Modifier
@@ -256,7 +271,7 @@ fun MomentTopRowGroup(momentItem: MomentItem) {
.padding(top = 0.dp, bottom = 0.dp, start = 24.dp, end = 24.dp)
) {
AsyncImage(
momentItem.avatar,
momentEntity.avatar,
contentDescription = "",
modifier = Modifier
.size(40.dp)
@@ -264,7 +279,7 @@ fun MomentTopRowGroup(momentItem: MomentItem) {
navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
momentItem.authorId.toString()
momentEntity.authorId.toString()
)
)
},
@@ -281,7 +296,7 @@ fun MomentTopRowGroup(momentItem: MomentItem) {
.height(22.dp),
verticalAlignment = Alignment.CenterVertically
) {
MomentName(momentItem.nickname)
MomentName(momentEntity.nickname)
MomentFollowBtn()
}
Row(
@@ -290,8 +305,8 @@ fun MomentTopRowGroup(momentItem: MomentItem) {
.height(21.dp),
verticalAlignment = Alignment.CenterVertically
) {
MomentPostLocation(momentItem.location)
MomentPostTime(momentItem.time)
MomentPostLocation(momentEntity.location)
MomentPostTime(momentEntity.time)
}
}
}
@@ -300,28 +315,40 @@ fun MomentTopRowGroup(momentItem: MomentItem) {
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun MomentContentGroup(
momentItem: MomentItem,
momentEntity: MomentEntity,
) {
val displayImageUrl = momentItem.images.firstOrNull()
val displayImageUrl = momentEntity.images.firstOrNull()
val sharedTransitionScope = LocalSharedTransitionScope.current
val animatedVisibilityScope = LocalAnimatedContentScope.current
Text(
text = "${momentItem.id} ${momentItem.momentTextContent}",
text = "${momentEntity.momentTextContent}",
modifier = Modifier
.fillMaxWidth()
.padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp),
fontSize = 16.sp
)
if (momentItem.relMoment != null) {
RelPostCard(momentItem = momentItem.relMoment!!, modifier = Modifier.background(Color(0xFFF8F8F8)))
}else{
if (momentEntity.relMoment != null) {
RelPostCard(
momentEntity = momentEntity.relMoment!!,
modifier = Modifier.background(Color(0xFFF8F8F8))
)
} else {
displayImageUrl?.let {
AsyncImage(
it,
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f),
contentScale = ContentScale.Crop,
contentDescription = ""
)
with(sharedTransitionScope) {
AsyncImage(
it,
modifier = Modifier
.sharedElement(
rememberSharedContentState(key = it),
animatedVisibilityScope = animatedVisibilityScope
)
.fillMaxWidth()
.aspectRatio(1f),
contentScale = ContentScale.Crop,
contentDescription = ""
)
}
}
}
@@ -366,8 +393,9 @@ fun MomentBottomOperateRowGroup(
modifier: Modifier,
onLikeClick: () -> Unit = {},
onAddComment: () -> Unit = {},
onFavoriteClick: () -> Unit = {},
onShareClick: () -> Unit = {},
momentItem: MomentItem
momentEntity: MomentEntity
) {
var systemUiController = rememberSystemUiController()
var showCommentModal by remember { mutableStateOf(false) }
@@ -380,7 +408,7 @@ fun MomentBottomOperateRowGroup(
)
) {
systemUiController.setNavigationBarColor(Color(0xfff7f7f7))
CommentModalContent(postId = momentItem.id, onCommentAdded = {
CommentModalContent(postId = momentEntity.id, onCommentAdded = {
showCommentModal = false
onAddComment()
}) {
@@ -397,10 +425,10 @@ fun MomentBottomOperateRowGroup(
modifier = modifier,
contentAlignment = Alignment.Center
) {
MomentOperateBtn(count = momentItem.likeCount.toString()) {
MomentOperateBtn(count = momentEntity.likeCount.toString()) {
AnimatedLikeIcon(
modifier = Modifier.size(24.dp),
liked = momentItem.liked
liked = momentEntity.liked
) {
onLikeClick()
}
@@ -417,28 +445,34 @@ fun MomentBottomOperateRowGroup(
) {
MomentOperateBtn(
icon = R.drawable.rider_pro_moment_comment,
count = momentItem.commentCount.toString()
count = momentEntity.commentCount.toString()
)
}
// Box(
// modifier = modifier.noRippleClickable {
// onShareClick()
// },
// contentAlignment = Alignment.Center
// ) {
// MomentOperateBtn(
// icon = R.drawable.rider_pro_share,
// count = momentEntity.shareCount.toString()
// )
// }
Box(
modifier = modifier.noRippleClickable {
onShareClick()
onFavoriteClick()
},
contentAlignment = Alignment.Center
) {
MomentOperateBtn(
icon = R.drawable.rider_pro_share,
count = momentItem.shareCount.toString()
)
}
Box(
modifier = modifier,
contentAlignment = Alignment.Center
) {
MomentOperateBtn(
icon = R.drawable.rider_pro_favoriate,
count = momentItem.favoriteCount.toString()
)
MomentOperateBtn(count = momentEntity.favoriteCount.toString()) {
AnimatedFavouriteIcon(
modifier = Modifier.size(24.dp),
isFavourite = momentEntity.isFavorite
) {
onFavoriteClick()
}
}
}
}
}

View File

@@ -13,7 +13,7 @@ import com.aiosman.riderpro.data.MomentRemoteDataSource
import com.aiosman.riderpro.data.MomentService
import com.aiosman.riderpro.data.TestAccountServiceImpl
import com.aiosman.riderpro.data.TestMomentServiceImpl
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.model.MomentEntity
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
@@ -22,7 +22,7 @@ import kotlinx.coroutines.launch
object MomentViewModel : ViewModel() {
private val momentService: MomentService = TestMomentServiceImpl()
private val _momentsFlow = MutableStateFlow<PagingData<MomentItem>>(PagingData.empty())
private val _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
val momentsFlow = _momentsFlow.asStateFlow()
val accountService: AccountService = TestAccountServiceImpl()
init {
@@ -91,6 +91,7 @@ object MomentViewModel : ViewModel() {
updateCommentCount(id)
}
fun updateDislikeMomentById(id: Int) {
val currentPagingData = _momentsFlow.value
val updatedPagingData = currentPagingData.map { momentItem ->
@@ -108,4 +109,34 @@ object MomentViewModel : ViewModel() {
updateDislikeMomentById(id)
}
fun updateFavoriteCount(id: Int) {
val currentPagingData = _momentsFlow.value
val updatedPagingData = currentPagingData.map { momentItem ->
if (momentItem.id == id) {
momentItem.copy(favoriteCount = momentItem.favoriteCount + 1, isFavorite = true)
} else {
momentItem
}
}
_momentsFlow.value = updatedPagingData
}
suspend fun favoriteMoment(id: Int) {
momentService.favoriteMoment(id)
updateFavoriteCount(id)
}
fun updateUnfavoriteCount(id: Int) {
val currentPagingData = _momentsFlow.value
val updatedPagingData = currentPagingData.map { momentItem ->
if (momentItem.id == id) {
momentItem.copy(favoriteCount = momentItem.favoriteCount - 1, isFavorite = false)
} else {
momentItem
}
}
_momentsFlow.value = updatedPagingData
}
suspend fun unfavoriteMoment(id: Int) {
momentService.unfavoriteMoment(id)
updateUnfavoriteCount(id)
}
}

View File

@@ -3,27 +3,25 @@ package com.aiosman.riderpro.ui.index.tabs.profile
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.navigation.NavController
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.data.AccountProfile
import com.aiosman.riderpro.data.AccountProfileEntity
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.TestAccountServiceImpl
import com.aiosman.riderpro.data.MomentPagingSource
import com.aiosman.riderpro.data.MomentRemoteDataSource
import com.aiosman.riderpro.data.TestMomentServiceImpl
import com.aiosman.riderpro.data.TestUserServiceImpl
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.model.MomentEntity
import kotlinx.coroutines.flow.Flow
object MyProfileViewModel {
val service: AccountService = TestAccountServiceImpl()
val userService = TestUserServiceImpl()
var profile by mutableStateOf<AccountProfile?>(null)
var momentsFlow by mutableStateOf<Flow<PagingData<MomentItem>>?>(null)
var profile by mutableStateOf<AccountProfileEntity?>(null)
var momentsFlow by mutableStateOf<Flow<PagingData<MomentEntity>>?>(null)
suspend fun loadProfile() {
profile = service.getMyAccountProfile()
momentsFlow = Pager(

View File

@@ -1,6 +1,7 @@
package com.aiosman.riderpro.ui.index.tabs.profile
import androidx.annotation.DrawableRes
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
@@ -46,10 +47,12 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.paging.compose.collectAsLazyPagingItems
import coil.compose.AsyncImage
import com.aiosman.riderpro.LocalAnimatedContentScope
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.LocalSharedTransitionScope
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.AccountProfile
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.data.AccountProfileEntity
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import kotlinx.coroutines.launch
@@ -119,9 +122,8 @@ fun ProfilePage() {
}
CarGroup()
model.profile?.let {
UserInformation(accountProfile = it)
UserInformation(accountProfileEntity = it)
}
RidingStyle()
}
moments?.let {
@@ -184,7 +186,11 @@ fun CarTopPicture() {
}
@Composable
fun UserInformation(isSelf: Boolean = true, accountProfile: AccountProfile) {
fun UserInformation(
isSelf: Boolean = true,
accountProfileEntity: AccountProfileEntity,
onFollowClick: () -> Unit = {}
) {
Column(
modifier = Modifier
.fillMaxWidth()
@@ -193,21 +199,25 @@ fun UserInformation(isSelf: Boolean = true, accountProfile: AccountProfile) {
) {
Row(modifier = Modifier.fillMaxWidth()) {
val userInfoModifier = Modifier.weight(1f)
UserInformationFollowers(userInfoModifier, accountProfile)
UserInformationBasic(userInfoModifier, accountProfile)
UserInformationFollowing(userInfoModifier, accountProfile)
UserInformationFollowers(userInfoModifier, accountProfileEntity)
UserInformationBasic(userInfoModifier, accountProfileEntity)
UserInformationFollowing(userInfoModifier, accountProfileEntity)
}
UserInformationSlogan()
CommunicationOperatorGroup(isSelf = isSelf)
CommunicationOperatorGroup(
isSelf = isSelf,
isFollowing = accountProfileEntity.isFollowing,
onFollowClick = onFollowClick
)
}
}
@Composable
fun UserInformationFollowers(modifier: Modifier, accountProfile: AccountProfile) {
fun UserInformationFollowers(modifier: Modifier, accountProfileEntity: AccountProfileEntity) {
Column(modifier = modifier.padding(top = 31.dp)) {
Text(
modifier = Modifier.padding(bottom = 5.dp),
text = accountProfile.followerCount.toString(),
text = accountProfileEntity.followerCount.toString(),
fontSize = 24.sp,
color = Color.Black,
style = TextStyle(fontWeight = FontWeight.Bold)
@@ -229,7 +239,7 @@ fun UserInformationFollowers(modifier: Modifier, accountProfile: AccountProfile)
}
@Composable
fun UserInformationBasic(modifier: Modifier, accountProfile: AccountProfile) {
fun UserInformationBasic(modifier: Modifier, accountProfileEntity: AccountProfileEntity) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -242,7 +252,7 @@ fun UserInformationBasic(modifier: Modifier, accountProfile: AccountProfile) {
painter = painterResource(id = R.drawable.avatar_bold), contentDescription = ""
)
AsyncImage(
accountProfile.avatar,
accountProfileEntity.avatar,
modifier = Modifier
.size(width = 88.dp, height = 88.dp)
.clip(
@@ -257,7 +267,7 @@ fun UserInformationBasic(modifier: Modifier, accountProfile: AccountProfile) {
modifier = Modifier
.widthIn(max = 220.dp)
.padding(top = 8.dp),
text = accountProfile.nickName,
text = accountProfileEntity.nickName,
fontSize = 32.sp,
color = Color.Black,
style = TextStyle(fontWeight = FontWeight.Bold),
@@ -265,7 +275,7 @@ fun UserInformationBasic(modifier: Modifier, accountProfile: AccountProfile) {
)
Text(
modifier = Modifier.padding(top = 4.dp),
text = accountProfile.country,
text = accountProfileEntity.country,
fontSize = 12.sp,
color = Color.Gray
)
@@ -279,14 +289,14 @@ fun UserInformationBasic(modifier: Modifier, accountProfile: AccountProfile) {
}
@Composable
fun UserInformationFollowing(modifier: Modifier, accountProfile: AccountProfile) {
fun UserInformationFollowing(modifier: Modifier, accountProfileEntity: AccountProfileEntity) {
Column(
modifier = modifier.padding(top = 6.dp),
horizontalAlignment = Alignment.End
) {
Text(
modifier = Modifier.padding(bottom = 5.dp),
text = accountProfile.followingCount.toString(),
text = accountProfileEntity.followingCount.toString(),
fontSize = 24.sp,
color = Color.Black,
style = TextStyle(fontWeight = FontWeight.Bold)
@@ -320,7 +330,11 @@ fun UserInformationSlogan() {
}
@Composable
fun CommunicationOperatorGroup(isSelf: Boolean = true) {
fun CommunicationOperatorGroup(
isSelf: Boolean = true,
isFollowing: Boolean = false,
onFollowClick: () -> Unit
) {
val navController = LocalNavController.current
Row(
modifier = Modifier
@@ -329,7 +343,11 @@ fun CommunicationOperatorGroup(isSelf: Boolean = true) {
) {
if (!isSelf) {
Box(
modifier = Modifier.size(width = 142.dp, height = 40.dp),
modifier = Modifier
.size(width = 142.dp, height = 40.dp)
.noRippleClickable {
onFollowClick()
},
contentAlignment = Alignment.Center
) {
Image(
@@ -338,7 +356,7 @@ fun CommunicationOperatorGroup(isSelf: Boolean = true) {
contentDescription = ""
)
Text(
text = "FOLLOW",
text = if (isFollowing) "FOLLOWING" else "FOLLOW",
fontSize = 16.sp,
color = Color.White,
style = TextStyle(fontWeight = FontWeight.Bold)
@@ -472,13 +490,14 @@ fun UserMoment(scope: LazyListScope) {
}
@Composable
fun MomentPostUnit(momentItem: MomentItem) {
TimeGroup(momentItem.time)
MomentCard(
momentItem.momentTextContent,
momentItem.images[0],
momentItem.likeCount.toString(),
momentItem.commentCount.toString()
fun MomentPostUnit(momentEntity: MomentEntity) {
TimeGroup(momentEntity.time)
ProfileMomentCard(
momentEntity.momentTextContent,
momentEntity.images[0],
momentEntity.likeCount.toString(),
momentEntity.commentCount.toString(),
momentId = momentEntity.id
)
}
@@ -506,7 +525,13 @@ fun TimeGroup(time: String = "2024.06.08 12:23") {
}
@Composable
fun MomentCard(content: String, imageUrl: String, like: String, comment: String) {
fun ProfileMomentCard(
content: String,
imageUrl: String,
like: String,
comment: String,
momentId: Int
) {
Column(
modifier = Modifier
.fillMaxWidth()
@@ -514,7 +539,7 @@ fun MomentCard(content: String, imageUrl: String, like: String, comment: String)
.border(width = 1.dp, color = Color(0f, 0f, 0f, 0.1f), shape = RoundedCornerShape(6.dp))
) {
MomentCardTopContent(content)
MomentCardPicture(imageUrl)
MomentCardPicture(imageUrl, momentId)
MomentCardOperation(like, comment)
}
}
@@ -534,16 +559,35 @@ fun MomentCardTopContent(content: String) {
}
}
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun MomentCardPicture(imageUrl: String) {
AsyncImage(
imageUrl,
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
contentDescription = "",
contentScale = ContentScale.FillWidth
)
fun MomentCardPicture(imageUrl: String, momentId: Int) {
val navController = LocalNavController.current
val sharedTransitionScope = LocalSharedTransitionScope.current
val animatedVisibilityScope = LocalAnimatedContentScope.current
with(sharedTransitionScope) {
AsyncImage(
imageUrl,
modifier = Modifier
.sharedElement(
rememberSharedContentState(key = imageUrl),
animatedVisibilityScope = animatedVisibilityScope
)
.fillMaxSize()
.padding(16.dp)
.noRippleClickable {
navController.navigate(
NavigationRoute.Post.route.replace(
"{id}",
momentId.toString()
)
)
},
contentDescription = "",
contentScale = ContentScale.FillWidth
)
}
}
@Composable

View File

@@ -1,5 +1,6 @@
package com.aiosman.riderpro.ui.login
import android.widget.Toast
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -15,23 +16,106 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.ServiceException
import com.aiosman.riderpro.data.TestAccountServiceImpl
import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Composable
fun EmailSignupScreen() {
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var confirmPassword by remember { mutableStateOf("") }
var rememberMe by remember { mutableStateOf(false) }
var acceptTerms by remember { mutableStateOf(false) }
var acceptPromotions by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val navController = LocalNavController.current
val context = LocalContext.current
val accountService: AccountService = TestAccountServiceImpl()
fun validateForm(): Boolean {
if (email.isEmpty()) {
Toast.makeText(context, "Email is required", Toast.LENGTH_SHORT).show()
return false
}
if (password.isEmpty()) {
Toast.makeText(context, "Password is required", Toast.LENGTH_SHORT).show()
return false
}
if (confirmPassword.isEmpty()) {
Toast.makeText(context, "Confirm password is required", Toast.LENGTH_SHORT).show()
return false
}
if (password != confirmPassword) {
Toast.makeText(context, "Password does not match", Toast.LENGTH_SHORT).show()
return false
}
if (!acceptTerms) {
Toast.makeText(context, "You must accept terms", Toast.LENGTH_SHORT).show()
return false
}
if (!acceptPromotions) {
Toast.makeText(context, "You must accept promotions", Toast.LENGTH_SHORT).show()
return false
}
return true
}
suspend fun registerUser() {
if (!validateForm()) return
// 注册
try {
accountService.registerUserWithPassword(email, password)
} catch (e: ServiceException) {
scope.launch(Dispatchers.Main) {
Toast.makeText(context, "Failed to register", Toast.LENGTH_SHORT).show()
}
}
// 获取 token
val authResp = accountService.loginUserWithPassword(email, password)
if (authResp.token != null) {
scope.launch(Dispatchers.Main) {
Toast.makeText(context, "Successfully registered", Toast.LENGTH_SHORT).show()
}
}
AppStore.apply {
token = authResp.token
this.rememberMe = rememberMe
saveData()
}
// 获取token 信息
try {
accountService.getMyAccount()
} catch (e: ServiceException) {
scope.launch(Dispatchers.Main) {
Toast.makeText(context, "Failed to get account", Toast.LENGTH_SHORT).show()
}
}
scope.launch(Dispatchers.Main) {
navController.navigate(NavigationRoute.Index.route) {
popUpTo(NavigationRoute.Login.route) { inclusive = true }
}
}
}
StatusBarMaskLayout {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
@@ -74,9 +158,9 @@ fun EmailSignupScreen() {
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp),
text = password,
text = confirmPassword,
onValueChange = {
password = it
confirmPassword = it
},
password = true,
label = "Confirm password",
@@ -149,7 +233,11 @@ fun EmailSignupScreen() {
.height(48.dp),
text = "LET'S RIDE".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_red_bg
)
) {
scope.launch(Dispatchers.IO) {
registerUser()
}
}
}
}
}

View File

@@ -1,5 +1,6 @@
package com.aiosman.riderpro.ui.login
import android.widget.Toast
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
@@ -26,6 +27,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
@@ -38,6 +40,7 @@ import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.ServiceException
import com.aiosman.riderpro.data.TestAccountServiceImpl
import com.aiosman.riderpro.data.TestUserServiceImpl
import com.aiosman.riderpro.data.UserService
@@ -57,18 +60,24 @@ fun UserAuthScreen() {
var accountService: AccountService = TestAccountServiceImpl()
val scope = rememberCoroutineScope()
val navController = LocalNavController.current
val context = LocalContext.current
fun onLogin() {
scope.launch {
val authResp = accountService.loginUserWithPassword(email, password)
if (authResp.token != null) {
AppStore.apply {
token = authResp.token
this.rememberMe = rememberMe
saveData()
}
navController.navigate(NavigationRoute.Index.route) {
popUpTo(NavigationRoute.Login.route) { inclusive = true }
try {
val authResp = accountService.loginUserWithPassword(email, password)
if (authResp.token != null) {
AppStore.apply {
token = authResp.token
this.rememberMe = rememberMe
saveData()
}
navController.navigate(NavigationRoute.Index.route) {
popUpTo(NavigationRoute.Login.route) { inclusive = true }
}
}
} catch (e: ServiceException) {
// handle error
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
}
}

View File

@@ -2,6 +2,7 @@ package com.aiosman.riderpro.ui.post
import android.app.Activity
import android.content.Intent
import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image
@@ -63,6 +64,7 @@ fun NewPostScreen() {
val model = NewPostViewModel
val systemUiController = rememberSystemUiController()
val navController = LocalNavController.current
val context = LocalContext.current
LaunchedEffect(Unit) {
systemUiController.setNavigationBarColor(color = Color.Transparent)
model.init()
@@ -76,7 +78,7 @@ fun NewPostScreen() {
) {
NewPostTopBar {
model.viewModelScope.launch {
model.createMoment()
model.createMoment(context = context)
navController.popBackStack()
}
}
@@ -93,7 +95,7 @@ fun NewPostScreen() {
modifier = Modifier.clip(RoundedCornerShape(8.dp)).background(color = Color(0xFFEEEEEE)).padding(24.dp)
) {
RelPostCard(
momentItem = it,
momentEntity = it,
modifier = Modifier.fillMaxWidth()
)
}
@@ -177,7 +179,9 @@ fun AddImageGrid() {
val uri = result.data?.data
if (uri != null) {
model.imageUriList += uri.toString()
// get filename and extension
}
}
}
val stroke = Stroke(

View File

@@ -1,16 +1,22 @@
package com.aiosman.riderpro.ui.post
import android.content.Context
import android.net.Uri
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aiosman.riderpro.data.MomentService
import com.aiosman.riderpro.data.TestMomentServiceImpl
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.data.UploadImage
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.ui.modification.Modification
import kotlinx.coroutines.launch
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
object NewPostViewModel : ViewModel() {
@@ -20,7 +26,7 @@ object NewPostViewModel : ViewModel() {
var modificationList by mutableStateOf<List<Modification>>(listOf())
var imageUriList by mutableStateOf(listOf<String>())
var relPostId by mutableStateOf<Int?>(null)
var relMoment by mutableStateOf<MomentItem?>(null)
var relMoment by mutableStateOf<MomentEntity?>(null)
fun asNewPost() {
textContent = ""
searchPlaceAddressResult = null
@@ -29,16 +35,39 @@ object NewPostViewModel : ViewModel() {
relPostId = null
}
suspend fun createMoment() {
momentService.createMoment(
content = textContent,
authorId = 1,
imageUriList = imageUriList,
relPostId = relPostId
)
suspend fun uriToFile(context: Context, uri: Uri): File {
val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
val tempFile = withContext(Dispatchers.IO) {
File.createTempFile("temp", null, context.cacheDir)
}
inputStream?.use { input ->
FileOutputStream(tempFile).use { output ->
input.copyTo(output)
}
}
return tempFile
}
suspend fun init(){
suspend fun createMoment(context: Context) {
val uploadImageList = emptyList<UploadImage>().toMutableList()
for (uri in imageUriList) {
val cursor = context.contentResolver.query(Uri.parse(uri), null, null, null, null)
cursor?.use {
if (it.moveToFirst()) {
val displayName = it.getString(it.getColumnIndex("_display_name"))
val extension = displayName.substringAfterLast(".")
Log.d("NewPost", "File name: $displayName, extension: $extension")
// read as file
val file = uriToFile(context, Uri.parse(uri))
Log.d("NewPost", "File size: ${file.length()}")
uploadImageList += UploadImage(file, displayName, uri, extension)
}
}
}
momentService.createMoment(textContent, 1, uploadImageList, relPostId)
}
suspend fun init() {
relPostId?.let {
val moment = momentService.getMomentById(it)
relMoment = moment

View File

@@ -74,9 +74,9 @@ import com.aiosman.riderpro.LocalAnimatedContentScope
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.LocalSharedTransitionScope
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.AccountProfile
import com.aiosman.riderpro.data.AccountProfileEntity
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.Comment
import com.aiosman.riderpro.data.CommentEntity
import com.aiosman.riderpro.data.CommentPagingSource
import com.aiosman.riderpro.data.CommentRemoteDataSource
import com.aiosman.riderpro.data.CommentService
@@ -84,7 +84,7 @@ import com.aiosman.riderpro.data.TestCommentServiceImpl
import com.aiosman.riderpro.data.MomentService
import com.aiosman.riderpro.data.TestAccountServiceImpl
import com.aiosman.riderpro.data.TestMomentServiceImpl
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
@@ -103,7 +103,7 @@ class PostViewModel(
) : ViewModel() {
var service: MomentService = TestMomentServiceImpl()
var commentService: CommentService = TestCommentServiceImpl()
private var _commentsFlow = MutableStateFlow<PagingData<Comment>>(PagingData.empty())
private var _commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
val commentsFlow = _commentsFlow.asStateFlow()
init {
@@ -120,17 +120,16 @@ class PostViewModel(
_commentsFlow.value = it
}
}
}
var accountProfile by mutableStateOf<AccountProfile?>(null)
var moment by mutableStateOf<MomentItem?>(null)
var accountProfileEntity by mutableStateOf<AccountProfileEntity?>(null)
var moment by mutableStateOf<MomentEntity?>(null)
var accountService: AccountService = TestAccountServiceImpl()
suspend fun initData() {
moment = service.getMomentById(postId.toInt())
moment?.let {
accountProfile = accountService.getAccountProfileById(it.authorId)
accountProfileEntity = accountService.getAccountProfileById(it.authorId)
}
}
@@ -147,8 +146,21 @@ class PostViewModel(
_commentsFlow.value = updatedPagingData
}
suspend fun unlikeComment(commentId: Int) {
commentService.dislikeComment(commentId)
val currentPagingData = commentsFlow.value
val updatedPagingData = currentPagingData.map { comment ->
if (comment.id == commentId) {
comment.copy(liked = !comment.liked)
} else {
comment
}
}
_commentsFlow.value = updatedPagingData
}
suspend fun createComment(content: String) {
commentService.createComment(postId.toInt(), content, 1)
commentService.createComment(postId.toInt(), content)
MomentViewModel.updateCommentCount(postId.toInt())
}
@@ -212,7 +224,7 @@ fun PostScreen(
commentsPagging.refresh()
}
},
momentItem = viewModel.moment
momentEntity = viewModel.moment
)
}
) {
@@ -221,7 +233,11 @@ fun PostScreen(
modifier = Modifier
.fillMaxSize()
) {
Header(viewModel.accountProfile)
Header(
avatar = viewModel.moment?.avatar,
nickname = viewModel.moment?.nickname,
userId = viewModel.moment?.authorId
)
Column(modifier = Modifier.animateContentSize()) {
AnimatedVisibility(visible = showCollapseContent) {
// collapse content
@@ -256,9 +272,13 @@ fun PostScreen(
CommentsSection(
lazyPagingItems = commentsPagging,
scrollState,
onLike = { comment: Comment ->
onLike = { commentEntity: CommentEntity ->
scope.launch {
viewModel.likeComment(comment.id)
if (commentEntity.liked) {
viewModel.unlikeComment(commentEntity.id)
} else {
viewModel.likeComment(commentEntity.id)
}
}
}) {
showCollapseContent = it
@@ -270,7 +290,7 @@ fun PostScreen(
}
@Composable
fun Header(accountProfile: AccountProfile?) {
fun Header(avatar: String?, nickname: String?, userId: Int?) {
val navController = LocalNavController.current
Row(
modifier = Modifier
@@ -288,30 +308,30 @@ fun Header(accountProfile: AccountProfile?) {
.size(32.dp)
)
Spacer(modifier = Modifier.width(8.dp))
accountProfile?.let {
avatar?.let {
AsyncImage(
accountProfile.avatar,
it,
contentDescription = "Profile Picture",
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.noRippleClickable {
navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
accountProfile.id.toString()
userId?.let {
navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
userId.toString()
)
)
)
}
},
contentScale = ContentScale.Crop
)
}
Spacer(modifier = Modifier.width(8.dp))
accountProfile?.let {
Text(text = accountProfile.nickName, fontWeight = FontWeight.Bold)
}
Spacer(modifier = Modifier.width(8.dp))
Text(text = nickname ?: "", fontWeight = FontWeight.Bold)
Box(
modifier = Modifier
.height(20.dp)
@@ -350,7 +370,7 @@ fun PostImageView(
state = pagerState,
modifier = Modifier
.weight(1f)
.fillMaxWidth().background(Color.Black),
.fillMaxWidth(),
) { page ->
val image = images[page]
with(sharedTransitionScope) {
@@ -407,7 +427,7 @@ fun PostImageView(
@Composable
fun PostDetails(
postId: String,
momentItem: MomentItem?
momentEntity: MomentEntity?
) {
Column(
@@ -418,22 +438,22 @@ fun PostDetails(
) {
Text(
text = momentItem?.momentTextContent ?: "",
text = momentEntity?.momentTextContent ?: "",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
)
Text(text = "12-11 发布")
Spacer(modifier = Modifier.height(8.dp))
Text(text = "${momentItem?.commentCount ?: 0} Comments")
Text(text = "${momentEntity?.commentCount ?: 0} Comments")
}
}
@Composable
fun CommentsSection(
lazyPagingItems: LazyPagingItems<Comment>,
lazyPagingItems: LazyPagingItems<CommentEntity>,
scrollState: LazyListState = rememberLazyListState(),
onLike: (Comment) -> Unit,
onLike: (CommentEntity) -> Unit,
onWillCollapse: (Boolean) -> Unit
) {
LazyColumn(
@@ -463,11 +483,11 @@ fun CommentsSection(
@Composable
fun CommentItem(comment: Comment, onLike: () -> Unit = {}) {
fun CommentItem(commentEntity: CommentEntity, onLike: () -> Unit = {}) {
Column {
Row(modifier = Modifier.padding(vertical = 8.dp)) {
AsyncImage(
comment.avatar,
commentEntity.avatar,
contentDescription = "Comment Profile Picture",
modifier = Modifier
.size(40.dp)
@@ -476,9 +496,9 @@ fun CommentItem(comment: Comment, onLike: () -> Unit = {}) {
)
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(text = comment.name, fontWeight = FontWeight.Bold)
Text(text = comment.comment)
Text(text = comment.date, fontSize = 12.sp, color = Color.Gray)
Text(text = commentEntity.name, fontWeight = FontWeight.Bold)
Text(text = commentEntity.comment)
Text(text = commentEntity.date, fontSize = 12.sp, color = Color.Gray)
}
Spacer(modifier = Modifier.weight(1f))
Column(horizontalAlignment = Alignment.CenterHorizontally) {
@@ -488,17 +508,17 @@ fun CommentItem(comment: Comment, onLike: () -> Unit = {}) {
Icon(
Icons.Filled.Favorite,
contentDescription = "Like",
tint = if (comment.liked) Color.Red else Color.Gray
tint = if (commentEntity.liked) Color.Red else Color.Gray
)
}
Text(text = comment.likes.toString())
Text(text = commentEntity.likes.toString())
}
}
Spacer(modifier = Modifier.height(8.dp))
Column(
modifier = Modifier.padding(start = 16.dp)
) {
comment.replies.forEach { reply ->
commentEntity.replies.forEach { reply ->
CommentItem(reply)
}
}
@@ -510,7 +530,7 @@ fun CommentItem(comment: Comment, onLike: () -> Unit = {}) {
fun BottomNavigationBar(
onCreateComment: (String) -> Unit = {},
onLikeClick: () -> Unit = {},
momentItem: MomentItem?
momentEntity: MomentEntity?
) {
val systemUiController = rememberSystemUiController()
var showCommentModal by remember { mutableStateOf(false) }
@@ -568,10 +588,10 @@ fun BottomNavigationBar(
Icon(
Icons.Filled.Favorite,
contentDescription = "like",
tint = if (momentItem?.liked == true) Color.Red else Color.Gray
tint = if (momentEntity?.liked == true) Color.Red else Color.Gray
)
}
Text(text = momentItem?.likeCount.toString())
Text(text = momentEntity?.likeCount.toString())
IconButton(
onClick = { /*TODO*/ }) {
Icon(Icons.Filled.Star, contentDescription = "Send")

View File

@@ -9,6 +9,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -17,13 +18,13 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.compose.collectAsLazyPagingItems
import com.aiosman.riderpro.data.AccountProfile
import com.aiosman.riderpro.data.AccountProfileEntity
import com.aiosman.riderpro.data.MomentPagingSource
import com.aiosman.riderpro.data.MomentRemoteDataSource
import com.aiosman.riderpro.data.TestMomentServiceImpl
import com.aiosman.riderpro.data.TestUserServiceImpl
import com.aiosman.riderpro.data.UserService
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.index.tabs.profile.CarGroup
import com.aiosman.riderpro.ui.index.tabs.profile.MomentPostUnit
@@ -31,15 +32,15 @@ import com.aiosman.riderpro.ui.index.tabs.profile.RidingStyle
import com.aiosman.riderpro.ui.index.tabs.profile.UserInformation
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
@Composable
fun AccountProfile(id:String) {
// val model = MyProfileViewModel
val userService: UserService = TestUserServiceImpl()
var userProfile by remember { mutableStateOf<AccountProfile?>(null) }
var userProfile by remember { mutableStateOf<AccountProfileEntity?>(null) }
val momentService = TestMomentServiceImpl()
var momentsFlow by remember { mutableStateOf<Flow<PagingData<MomentItem>>?>(null) }
var momentsFlow by remember { mutableStateOf<Flow<PagingData<MomentEntity>>?>(null) }
val scope = rememberCoroutineScope()
LaunchedEffect(Unit) {
userProfile = userService.getUserProfile(id)
momentsFlow = Pager(
@@ -73,7 +74,21 @@ fun AccountProfile(id:String) {
item {
CarGroup()
userProfile?.let {
UserInformation(isSelf = false, accountProfile = it)
UserInformation(
isSelf = false,
accountProfileEntity = it,
onFollowClick = {
scope.launch {
if (it.isFollowing) {
userService.unFollowUser(id)
userProfile = userProfile?.copy(isFollowing = false)
} else {
userService.followUser(id)
userProfile = userProfile?.copy(isFollowing = true)
}
}
},
)
}
RidingStyle()
}