diff --git a/app/src/main/java/com/aiosman/riderpro/data/MomentService.kt b/app/src/main/java/com/aiosman/riderpro/data/MomentService.kt index 0a321bc..a72a932 100644 --- a/app/src/main/java/com/aiosman/riderpro/data/MomentService.kt +++ b/app/src/main/java/com/aiosman/riderpro/data/MomentService.kt @@ -148,6 +148,11 @@ interface MomentService { * @param id 动态ID */ suspend fun unfavoriteMoment(id: Int) + + /** + * 删除动态 + */ + suspend fun deleteMoment(id: Int) } diff --git a/app/src/main/java/com/aiosman/riderpro/data/api/RiderProAPI.kt b/app/src/main/java/com/aiosman/riderpro/data/api/RiderProAPI.kt index 5e45366..1d80e87 100644 --- a/app/src/main/java/com/aiosman/riderpro/data/api/RiderProAPI.kt +++ b/app/src/main/java/com/aiosman/riderpro/data/api/RiderProAPI.kt @@ -14,6 +14,7 @@ import okhttp3.MultipartBody import okhttp3.RequestBody import retrofit2.Response import retrofit2.http.Body +import retrofit2.http.DELETE import retrofit2.http.GET import retrofit2.http.Multipart import retrofit2.http.PATCH @@ -251,4 +252,9 @@ interface RiderProAPI { @POST("register/google") suspend fun registerWithGoogle(@Body body: GoogleRegisterRequestBody): Response + @DELETE("post/{id}") + suspend fun deletePost( + @Path("id") id: Int + ): Response + } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/entity/Moment.kt b/app/src/main/java/com/aiosman/riderpro/entity/Moment.kt index 76f5133..d1641f1 100644 --- a/app/src/main/java/com/aiosman/riderpro/entity/Moment.kt +++ b/app/src/main/java/com/aiosman/riderpro/entity/Moment.kt @@ -123,6 +123,10 @@ class MomentServiceImpl() : MomentService { momentBackend.unfavoriteMoment(id) } + override suspend fun deleteMoment(id: Int) { + momentBackend.deleteMoment(id) + } + } class MomentBackend { @@ -195,6 +199,10 @@ class MomentBackend { ApiClient.api.unfavoritePost(id) } + suspend fun deleteMoment(id: Int) { + ApiClient.api.deletePost(id) + } + } /** diff --git a/app/src/main/java/com/aiosman/riderpro/ui/composables/DropdownMenu.kt b/app/src/main/java/com/aiosman/riderpro/ui/composables/DropdownMenu.kt new file mode 100644 index 0000000..a3cbfce --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/composables/DropdownMenu.kt @@ -0,0 +1,83 @@ +package com.aiosman.riderpro.ui.composables + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.aiosman.riderpro.R +import com.aiosman.riderpro.ui.NavigationRoute +import com.aiosman.riderpro.ui.modifiers.noRippleClickable +import kotlinx.coroutines.launch + +data class MenuItem( + val title: String, + val icon: Int, + val action: () -> Unit + +) +@Composable +fun DropdownMenu( + expanded: Boolean = false, + menuItems: List = emptyList(), + width: Int? = null, + onDismissRequest: () -> Unit = {}, +) { + MaterialTheme( + shapes = MaterialTheme.shapes.copy( + extraSmall = RoundedCornerShape( + 16.dp + ) + ) + ) { + androidx.compose.material3.DropdownMenu( + expanded = expanded, + onDismissRequest = onDismissRequest, + modifier = Modifier + .apply { + width?.let { width(width.dp) } + } + .background(Color.White) + ) { + for (item in menuItems) { + Box( + modifier = Modifier + .padding(vertical = 14.dp, horizontal = 24.dp) + .noRippleClickable { + item.action() + }) { + Row { + Text( + item.title, + fontWeight = FontWeight.W500 + ) + if (width != null) { + Spacer(modifier = Modifier.weight(1f)) + + }else{ + Spacer(modifier = Modifier.width(16.dp)) + } + Icon( + painter = painterResource(id = item.icon), + contentDescription = "", + modifier = Modifier.size(24.dp) + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/imageviewer/imageviewer.kt b/app/src/main/java/com/aiosman/riderpro/ui/imageviewer/imageviewer.kt index 0782b08..074f8a8 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/imageviewer/imageviewer.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/imageviewer/imageviewer.kt @@ -35,8 +35,7 @@ fun ImageViewer() { val animatedVisibilityScope = LocalAnimatedContentScope.current val context = LocalContext.current LaunchedEffect(Unit) { - systemUiController.setStatusBarColor(Color.Black) - systemUiController.setNavigationBarColor(Color.Black) + } StatusBarMaskLayout( modifier = Modifier.background(Color.Black), diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/message/MessageList.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/message/MessageList.kt index 34843f7..8633c35 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/message/MessageList.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/message/MessageList.kt @@ -51,6 +51,7 @@ import com.aiosman.riderpro.exp.timeAgo import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder import com.aiosman.riderpro.ui.composables.CustomAsyncImage +import com.aiosman.riderpro.ui.composables.StatusBarSpacer import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.google.accompanist.systemuicontroller.rememberSystemUiController import kotlinx.coroutines.launch @@ -80,11 +81,7 @@ fun NotificationsScreen() { Column( modifier = Modifier.fillMaxSize() ) { - Spacer( - modifier = Modifier.padding( - bottom = navigationBarPaddings - ) - ) + StatusBarSpacer() Box(modifier = Modifier .fillMaxWidth() .weight(1f) @@ -92,17 +89,6 @@ fun NotificationsScreen() { Column( modifier = Modifier.fillMaxSize(), ) { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 24.dp) - ) { - Image( - painter = painterResource(id = R.drawable.rider_pro_message_title), - contentDescription = "Back", - modifier = Modifier.width(120.dp) - ) - } Row( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/Moment.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/Moment.kt index c505123..6eea44f 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/Moment.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/Moment.kt @@ -90,19 +90,13 @@ fun MomentsList() { var dataFlow = model.momentsFlow var moments = dataFlow.collectAsLazyPagingItems() val scope = rememberCoroutineScope() - var refreshing by remember { mutableStateOf(false) } - val state = rememberPullRefreshState(refreshing, onRefresh = { - model.refreshPager() + val state = rememberPullRefreshState(model.refreshing, onRefresh = { + model.refreshPager( + pullRefresh = true + ) }) val navigationBarPaddings = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp - LaunchedEffect(moments.loadState) { - if (moments.loadState.refresh is LoadState.Loading) { - refreshing = true - } else { - refreshing = false - } - } val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues() Column( modifier = Modifier @@ -154,7 +148,7 @@ fun MomentsList() { ) } } - PullRefreshIndicator(refreshing, state, Modifier.align(Alignment.TopCenter)) + PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter)) } } } @@ -388,32 +382,6 @@ fun PostImageView( ) } - - // Indicator container -// if (images.size > 1) { -// Row( -// modifier = Modifier -// .padding(8.dp) -// .fillMaxWidth(), -// horizontalArrangement = Arrangement.Center -// ) { -// images.forEachIndexed { index, _ -> -// Box( -// modifier = Modifier -// .size(8.dp) -// .clip(CircleShape) -// .background( -// if (pagerState.currentPage == index) Color.Red else Color.Gray.copy( -// alpha = 0.5f -// ) -// ) -// .padding(4.dp) -// ) -// Spacer(modifier = Modifier.width(8.dp)) -// } -// } -// } - } } diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/MomentViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/MomentViewModel.kt index a7ebd75..e81cab8 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/MomentViewModel.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/MomentViewModel.kt @@ -9,6 +9,7 @@ import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData import androidx.paging.cachedIn +import androidx.paging.filter import androidx.paging.map import com.aiosman.riderpro.data.AccountService import com.aiosman.riderpro.entity.MomentPagingSource @@ -28,17 +29,25 @@ object MomentViewModel : ViewModel() { private val _momentsFlow = MutableStateFlow>(PagingData.empty()) val momentsFlow = _momentsFlow.asStateFlow() val accountService: AccountService = AccountServiceImpl() - var existsException = mutableStateOf(false) + var existsMoment = mutableStateOf(false) + var refreshing by mutableStateOf(false) init { refreshPager() } - fun refreshPager() { + + fun refreshPager(pullRefresh: Boolean = false) { viewModelScope.launch { + if (pullRefresh) { + refreshing = true + } val profile = accountService.getMyAccountProfile() // 检查是否有动态 val existMoments = momentService.getMoments(timelineId = profile.id, pageNumber = 1) if (existMoments.list.isEmpty()) { - existsException.value = true + existsMoment.value = true + } + if (pullRefresh) { + refreshing = false } Pager( config = PagingConfig(pageSize = 5, enablePlaceholders = false), @@ -84,6 +93,7 @@ object MomentViewModel : ViewModel() { } _momentsFlow.value = updatedPagingData } + suspend fun onAddComment(id: Int) { val currentPagingData = _momentsFlow.value updateCommentCount(id) @@ -118,10 +128,12 @@ object MomentViewModel : ViewModel() { } _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 -> @@ -133,8 +145,17 @@ object MomentViewModel : ViewModel() { } _momentsFlow.value = updatedPagingData } + suspend fun unfavoriteMoment(id: Int) { momentService.unfavoriteMoment(id) updateUnfavoriteCount(id) } + + fun deleteMoment(id: Int) { + val currentPagingData = _momentsFlow.value + val updatedPagingData = currentPagingData.filter { momentItem -> + momentItem.id != id + } + _momentsFlow.value = updatedPagingData + } } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/search/SearchScreen.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/search/SearchScreen.kt index be4eab1..1e46655 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/search/SearchScreen.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/search/SearchScreen.kt @@ -128,7 +128,6 @@ fun SearchScreen() { } if (model.showResult) { - Spacer(modifier = Modifier.padding(8.dp)) TabRow( selectedTabIndex = selectedTabIndex.value, backgroundColor = Color.White, @@ -236,15 +235,22 @@ fun MomentResultTab() { var dataFlow = model.momentsFlow var moments = dataFlow.collectAsLazyPagingItems() Box( - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() + .background(Color(0xFFF0F2F5)) ) { LazyColumn( modifier = Modifier.fillMaxSize(), ) { items(moments.itemCount) { idx -> val momentItem = moments[idx] ?: return@items - Spacer(modifier = Modifier.padding(8.dp)) - MomentCard(momentEntity = momentItem, hideAction = true) + Box( + modifier = Modifier + .fillMaxWidth().background(Color.White) + ) { + MomentCard(momentEntity = momentItem, hideAction = true) + } + Spacer(modifier = Modifier.padding(16.dp)) } } } diff --git a/app/src/main/java/com/aiosman/riderpro/ui/post/NewPostViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/post/NewPostViewModel.kt index d2d517b..e28049f 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/post/NewPostViewModel.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/post/NewPostViewModel.kt @@ -11,6 +11,7 @@ import com.aiosman.riderpro.data.MomentService import com.aiosman.riderpro.entity.MomentServiceImpl import com.aiosman.riderpro.data.UploadImage import com.aiosman.riderpro.entity.MomentEntity +import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel import com.aiosman.riderpro.ui.index.tabs.profile.MyProfileViewModel import com.aiosman.riderpro.ui.modification.Modification import kotlinx.coroutines.Dispatchers @@ -78,6 +79,7 @@ object NewPostViewModel : ViewModel() { momentService.createMoment(textContent, 1, uploadImageList, relPostId) // 刷新个人动态 MyProfileViewModel.loadProfile() + MomentViewModel.refreshPager() } suspend fun init() { diff --git a/app/src/main/java/com/aiosman/riderpro/ui/post/Post.kt b/app/src/main/java/com/aiosman/riderpro/ui/post/Post.kt index 1f9c396..c266a34 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/post/Post.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/post/Post.kt @@ -1,9 +1,7 @@ package com.aiosman.riderpro.ui.post import android.util.Log -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExperimentalSharedTransitionApi -import androidx.compose.animation.animateContentSize import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -30,12 +28,7 @@ import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Edit -import androidx.compose.material.icons.filled.Favorite import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -52,6 +45,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext @@ -62,235 +56,45 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.PagingData -import androidx.paging.cachedIn import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.map import com.aiosman.riderpro.AppState import com.aiosman.riderpro.LocalAnimatedContentScope import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.LocalSharedTransitionScope import com.aiosman.riderpro.R -import com.aiosman.riderpro.entity.AccountProfileEntity -import com.aiosman.riderpro.data.AccountService import com.aiosman.riderpro.entity.CommentEntity -import com.aiosman.riderpro.entity.CommentPagingSource -import com.aiosman.riderpro.data.CommentRemoteDataSource -import com.aiosman.riderpro.data.CommentService -import com.aiosman.riderpro.data.CommentServiceImpl -import com.aiosman.riderpro.data.MomentService -import com.aiosman.riderpro.data.AccountServiceImpl -import com.aiosman.riderpro.entity.MomentServiceImpl -import com.aiosman.riderpro.data.UserServiceImpl -import com.aiosman.riderpro.data.UserService -import com.aiosman.riderpro.exp.formatPostTime -import com.aiosman.riderpro.exp.timeAgo import com.aiosman.riderpro.entity.MomentEntity import com.aiosman.riderpro.entity.MomentImageEntity +import com.aiosman.riderpro.exp.formatPostTime +import com.aiosman.riderpro.exp.timeAgo import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.composables.AnimatedFavouriteIcon import com.aiosman.riderpro.ui.composables.AnimatedLikeIcon -import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder import com.aiosman.riderpro.ui.composables.CustomAsyncImage import com.aiosman.riderpro.ui.composables.EditCommentBottomModal import com.aiosman.riderpro.ui.composables.StatusBarSpacer import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel -import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel import com.aiosman.riderpro.ui.modifiers.noRippleClickable -import com.google.accompanist.systemuicontroller.rememberSystemUiController -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -object PostViewModel : ViewModel() { - var service: MomentService = MomentServiceImpl() - var commentService: CommentService = CommentServiceImpl() - var userService: UserService = UserServiceImpl() - private var _commentsFlow = MutableStateFlow>(PagingData.empty()) - val commentsFlow = _commentsFlow.asStateFlow() - var postId: String = "" - - // 预加载的 moment - - var accountProfileEntity by mutableStateOf(null) - var moment by mutableStateOf(null) - var accountService: AccountService = AccountServiceImpl() - - /** - * 预加载,在跳转到 PostScreen 之前设置好内容 - */ - fun preTransit(momentEntity: MomentEntity?) { - this.postId = momentEntity?.id.toString() - this.moment = momentEntity - viewModelScope.launch { - Pager( - config = PagingConfig(pageSize = 5, enablePlaceholders = false), - pagingSourceFactory = { - CommentPagingSource( - CommentRemoteDataSource(commentService), - postId = postId.toInt() - ) - } - ).flow.cachedIn(viewModelScope).collectLatest { - _commentsFlow.value = it - } - } - } - - fun reloadComment() { - viewModelScope.launch { - Pager( - config = PagingConfig(pageSize = 5, enablePlaceholders = false), - pagingSourceFactory = { - CommentPagingSource( - CommentRemoteDataSource(commentService), - postId = postId.toInt() - ) - } - ).flow.cachedIn(viewModelScope).collectLatest { - _commentsFlow.value = it - } - } - } - - suspend fun initData() { - moment = service.getMomentById(postId.toInt()) -// moment?.let { -// accountProfileEntity = userService.getUserProfile(it.authorId.toString()) -// } - } - - suspend fun likeComment(commentId: Int) { - commentService.likeComment(commentId) - val currentPagingData = commentsFlow.value - val updatedPagingData = currentPagingData.map { comment -> - if (comment.id == commentId) { - comment.copy(liked = !comment.liked, likes = comment.likes + 1) - } else { - comment - } - } - _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, likes = comment.likes - 1) - } else { - comment - } - } - _commentsFlow.value = updatedPagingData - } - - suspend fun createComment(content: String) { - commentService.createComment(postId.toInt(), content) - this.moment = service.getMomentById(postId.toInt()) - MomentViewModel.updateCommentCount(postId.toInt()) - reloadComment() - } - - suspend fun likeMoment() { - moment?.let { - service.likeMoment(it.id) - moment = moment?.copy(likeCount = moment?.likeCount?.plus(1) ?: 0, liked = true) - MomentViewModel.updateLikeCount(it.id) - } - } - - suspend fun dislikeMoment() { - moment?.let { - service.dislikeMoment(it.id) - moment = moment?.copy(likeCount = moment?.likeCount?.minus(1) ?: 0, liked = false) - // update home list - MomentViewModel.updateDislikeMomentById(it.id) - } - } - - suspend fun favoriteMoment() { - moment?.let { - service.favoriteMoment(it.id) - moment = - moment?.copy(favoriteCount = moment?.favoriteCount?.plus(1) ?: 0, isFavorite = true) - } - } - - suspend fun unfavoriteMoment() { - moment?.let { - service.unfavoriteMoment(it.id) - moment = moment?.copy( - favoriteCount = moment?.favoriteCount?.minus(1) ?: 0, - isFavorite = false - ) - } - } - - suspend fun followUser() { - accountProfileEntity?.let { - userService.followUser(it.id.toString()) - accountProfileEntity = accountProfileEntity?.copy(isFollowing = true) - } - } - - suspend fun unfollowUser() { - accountProfileEntity?.let { - userService.unFollowUser(it.id.toString()) - accountProfileEntity = accountProfileEntity?.copy(isFollowing = false) - } - } - - 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 fun PostScreen( id: String, ) { val viewModel = PostViewModel val scope = rememberCoroutineScope() - val commentsPagging = viewModel.commentsFlow.collectAsLazyPagingItems() - var showCollapseContent by remember { mutableStateOf(false) } - val scrollState = rememberLazyListState() + val showMenuModal by remember { mutableStateOf(false) } + val navController = LocalNavController.current LaunchedEffect(Unit) { viewModel.initData() } - Scaffold( modifier = Modifier.fillMaxSize(), bottomBar = { - BottomNavigationBar( + PostBottomBar( onLikeClick = { scope.launch { if (viewModel.moment?.liked == true) { @@ -338,6 +142,11 @@ fun PostScreen( viewModel.followUser() } } + }, + onDeleteClick = { + viewModel.deleteMoment { + navController.popBackStack() + } } ) LazyColumn( @@ -352,13 +161,11 @@ fun PostScreen( .aspectRatio(383f / 527f) ) { PostImageView( - id, viewModel.moment?.images ?: emptyList() ) } PostDetails( - id, viewModel.moment ) Spacer(modifier = Modifier.height(16.dp)) @@ -417,16 +224,40 @@ fun PostScreen( } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun Header( avatar: String?, nickname: String?, userId: Int?, isFollowing: Boolean, - onFollowClick: () -> Unit + onFollowClick: () -> Unit, + onDeleteClick: () -> Unit = {} ) { val navController = LocalNavController.current val context = LocalContext.current + var expanded by remember { mutableStateOf(false) } + if (expanded) { + ModalBottomSheet( + onDismissRequest = { + expanded = false + }, + containerColor = Color.White, + sheetState = rememberModalBottomSheetState( + skipPartiallyExpanded = true + ), + dragHandle = {}, + shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), + windowInsets = WindowInsets(0) + ) { + PostMenuModal( + onDeleteClick = { + onDeleteClick() + expanded = false + } + ) + } + } Row( modifier = Modifier .fillMaxWidth() @@ -498,8 +329,18 @@ fun Header( ) } } - - + Spacer(modifier = Modifier.weight(1f)) + Box { + Image( + modifier = Modifier + .height(20.dp) + .noRippleClickable { + expanded = true + }, + painter = painterResource(id = R.drawable.rider_pro_more_horizon), + contentDescription = "" + ) + } } } @@ -507,7 +348,6 @@ fun Header( @OptIn(ExperimentalFoundationApi::class, ExperimentalSharedTransitionApi::class) @Composable fun PostImageView( - postId: String, images: List, ) { val pagerState = rememberPagerState(pageCount = { images.size }) @@ -579,7 +419,6 @@ fun PostImageView( @OptIn(ExperimentalSharedTransitionApi::class) @Composable fun PostDetails( - postId: String, momentEntity: MomentEntity? ) { @@ -665,8 +504,8 @@ fun CommentItem(commentEntity: CommentEntity, onLike: () -> Unit = {}) { Column( modifier = Modifier.weight(1f) ) { - Text(text = commentEntity.name, fontWeight = FontWeight.Bold, fontSize = 14.sp) - Text(text = commentEntity.comment, fontSize = 12.sp) + Text(text = commentEntity.name, fontWeight = FontWeight.W600, fontSize = 14.sp) + Text(text = commentEntity.comment, fontSize = 14.sp) Text( text = commentEntity.date.timeAgo(context), fontSize = 12.sp, @@ -680,9 +519,9 @@ fun CommentItem(commentEntity: CommentEntity, onLike: () -> Unit = {}) { AnimatedLikeIcon( liked = commentEntity.liked, onClick = onLike, - modifier = Modifier.size(16.dp) + modifier = Modifier.size(20.dp) ) - Text(text = commentEntity.likes.toString(), fontSize = 11.sp) + Text(text = commentEntity.likes.toString(), fontSize = 12.sp) } } Spacer(modifier = Modifier.height(8.dp)) @@ -698,7 +537,7 @@ fun CommentItem(commentEntity: CommentEntity, onLike: () -> Unit = {}) { @OptIn(ExperimentalMaterial3Api::class) @Composable -fun BottomNavigationBar( +fun PostBottomBar( onCreateComment: (String) -> Unit = {}, onLikeClick: () -> Unit = {}, onFavoriteClick: () -> Unit = {}, @@ -789,4 +628,51 @@ fun BottomNavigationBar( ) } +} + +@Composable +fun PostMenuModal( + onDeleteClick: () -> Unit = {} +) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 24.dp, horizontal = 24.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Column( + modifier = Modifier, + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier + .clip(CircleShape) + .background(Color(0xFFE5E5E5)) + .padding(8.dp) + .noRippleClickable { + onDeleteClick() + } + ) { + Image( + painter = painterResource(id = R.drawable.rider_pro_delete), + contentDescription = "Delete", + modifier = Modifier.size(24.dp), + colorFilter = ColorFilter.tint(Color.Black) + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = "Delete", + fontSize = 14.sp, + fontWeight = FontWeight.Bold + ) + } + } + } } \ No newline at end of file