添加业务逻辑

This commit is contained in:
2024-07-28 15:07:08 +08:00
parent dfbc151e4e
commit f35bde65a2
8 changed files with 355 additions and 260 deletions

View File

@@ -78,6 +78,8 @@ dependencies {
debugImplementation(libs.androidx.ui.test.manifest) debugImplementation(libs.androidx.ui.test.manifest)
implementation (libs.places) implementation (libs.places)
implementation(libs.androidx.animation) implementation(libs.androidx.animation)
implementation("io.coil-kt:coil-compose:2.7.0")
implementation("io.coil-kt:coil:2.7.0")
} }

View File

@@ -0,0 +1,98 @@
package com.aiosman.riderpro.data.comment
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.aiosman.riderpro.data.ListContainer
import java.io.IOException
import kotlin.random.Random
data class Comment(
val name: String,
val comment: String,
val date: String,
val likes: Int,
val replies: List<Comment>
)
class CommentPagingSource(
private val remoteDataSource: CommentRemoteDataSource,
) : PagingSource<Int, Comment>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Comment> {
return try {
val currentPage = params.key ?: 1
val comments = remoteDataSource.getComments(
pageNumber = currentPage
)
LoadResult.Page(
data = comments.list,
prevKey = if (currentPage == 1) null else currentPage - 1,
nextKey = if (comments.list.isEmpty()) null else comments.page + 1
)
} catch (exception: IOException) {
return LoadResult.Error(exception)
}
}
override fun getRefreshKey(state: PagingState<Int, Comment>): Int? {
return state.anchorPosition
}
}
class CommentRemoteDataSource(
private val commentService: CommentService,
) {
suspend fun getComments(pageNumber: Int): ListContainer<Comment> {
return commentService.getComments(pageNumber)
}
}
interface CommentService {
suspend fun getComments(pageNumber: Int): ListContainer<Comment>
}
class TestCommentServiceImpl : CommentService {
private val mockData = generateMockComments(100)
override suspend fun getComments(pageNumber: Int): ListContainer<Comment> {
val from = pageNumber * DataBatchSize
val to = (pageNumber + 1) * DataBatchSize
val currentSublist = mockData.subList(from, to)
return ListContainer(
total = mockData.size,
page = pageNumber,
pageSize = DataBatchSize,
list = currentSublist
)
}
private fun generateMockComments(count: Int): List<Comment> {
return (0 until count).map {
Comment(
name = "User $it",
comment = "This is comment $it",
date = "2023-02-02 11:23",
likes = Random.nextInt(0, 100),
replies = generateMockReplies()
)
}
}
private fun generateMockReplies(): List<Comment> {
val replyCount = Random.nextInt(0, 6)
return (0 until replyCount).map {
Comment(
name = "Reply User $it",
comment = "This is reply $it",
date = "2023-02-02 11:23",
likes = Random.nextInt(0, 100),
replies = emptyList()
)
}
}
companion object {
const val DataBatchSize = 5
}
}

View File

@@ -1,12 +1,12 @@
package com.aiosman.riderpro.data.moment package com.aiosman.riderpro.data.moment
import android.net.http.HttpException
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.paging.PagingState import androidx.paging.PagingState
import com.aiosman.riderpro.R import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.ListContainer import com.aiosman.riderpro.data.ListContainer
import com.aiosman.riderpro.model.MomentItem import com.aiosman.riderpro.model.MomentItem
import java.io.IOException import java.io.IOException
import kotlin.random.Random
class MomentPagingSource( class MomentPagingSource(
private val remoteDataSource: MomentRemoteDataSource, private val remoteDataSource: MomentRemoteDataSource,
@@ -45,9 +45,15 @@ class MomentRemoteDataSource(
interface MomentService { interface MomentService {
suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem> suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem>
suspend fun getMomentById(id: Int): MomentItem
} }
class TestMomentServiceImpl() : MomentService { class TestMomentServiceImpl() : MomentService {
var imageList = listOf(
"https://img.freepik.com/free-photo/white-billboard-template_23-2147726635.jpg?t=st=1722150015~exp=1722153615~hmac=5540620196d7898215d822be26353c87a63d51bbfb2b814e032626e1948a1583&w=740",
"https://img.freepik.com/free-photo/minimal-clothing-label-fashion-brands_53876-111053.jpg?w=1060&t=st=1722150122~exp=1722150722~hmac=67f8a2b6abfe3d08714cf0cc0085485c3221e1ba00dda14378b03753dce39153",
"https://img.freepik.com/free-photo/marketing-strategy-planning-strategy-concept_53876-42950.jpg"
)
val mockData = (0..300).toList().mapIndexed { idx, _ -> val mockData = (0..300).toList().mapIndexed { idx, _ ->
MomentItem( MomentItem(
id = idx, id = idx,
@@ -61,13 +67,18 @@ class TestMomentServiceImpl() : MomentService {
likeCount = 21, likeCount = 21,
commentCount = 43, commentCount = 43,
shareCount = 33, shareCount = 33,
favoriteCount = 211 favoriteCount = 211,
images = imageList.shuffled().take(3),
) )
} }
val testMomentBackend = TestMomentBackend(mockData) val testMomentBackend = TestMomentBackend(mockData)
override suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem> { override suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem> {
return testMomentBackend.fetchMomentItems(pageNumber) return testMomentBackend.fetchMomentItems(pageNumber)
} }
override suspend fun getMomentById(id: Int): MomentItem {
return mockData[id]
}
} }
class TestMomentBackend( class TestMomentBackend(

View File

@@ -15,7 +15,8 @@ data class MomentItem(
val likeCount: Int, val likeCount: Int,
val commentCount: Int, val commentCount: Int,
val shareCount: Int, val shareCount: Int,
val favoriteCount: Int val favoriteCount: Int,
val images: List<String> = emptyList()
) )
val momentTestItem = MomentItem( val momentTestItem = MomentItem(

View File

@@ -35,13 +35,32 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.compose.collectAsLazyPagingItems
import com.aiosman.riderpro.ui.post.CommentsSection import com.aiosman.riderpro.ui.post.CommentsSection
import com.aiosman.riderpro.R import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.comment.Comment
import com.aiosman.riderpro.data.comment.CommentPagingSource
import com.aiosman.riderpro.data.comment.CommentRemoteDataSource
import com.aiosman.riderpro.data.comment.TestCommentServiceImpl
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel.momentListPagingSource
import kotlinx.coroutines.flow.Flow
@Preview @Preview
@Composable @Composable
fun CommentModalContent(onDismiss: () -> Unit = {}) { fun CommentModalContent(onDismiss: () -> Unit = {}) {
var commentSource = CommentPagingSource(
CommentRemoteDataSource(TestCommentServiceImpl())
)
val commentsFlow: Flow<PagingData<Comment>> = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = { commentSource }
).flow
val comments = commentsFlow.collectAsLazyPagingItems()
val insets = WindowInsets val insets = WindowInsets
val imePadding = insets.ime.getBottom(density = LocalDensity.current) val imePadding = insets.ime.getBottom(density = LocalDensity.current)
var bottomPadding by remember { mutableStateOf(0.dp) } var bottomPadding by remember { mutableStateOf(0.dp) }
@@ -80,7 +99,11 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.weight(1f) .weight(1f)
) { ) {
CommentsSection{}
CommentsSection(lazyPagingItems = comments) {
}
} }
Box( Box(
modifier = Modifier modifier = Modifier
@@ -131,7 +154,6 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
} }
} }
} }

View File

@@ -0,0 +1,76 @@
package com.aiosman.riderpro.ui.composables
import androidx.compose.foundation.Image
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.fillMaxWidth
import androidx.compose.foundation.layout.height
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.foundation.text.BasicTextField
import androidx.compose.runtime.Composable
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.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.aiosman.riderpro.R
@Composable
fun EditCommentBottomModal() {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color(0xfff7f7f7))
.padding(horizontal = 16.dp, vertical = 8.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.Center),
verticalAlignment = Alignment.CenterVertically
) {
// rounded
Box(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.clip(RoundedCornerShape(20.dp))
.background(Color(0xffe5e5e5))
.padding(horizontal = 16.dp, vertical = 12.dp)
) {
BasicTextField(
value = "",
onValueChange = { },
modifier = Modifier
.fillMaxWidth(),
textStyle = TextStyle(
color = Color.Black,
fontWeight = FontWeight.Normal
),
minLines = 5
)
}
Spacer(modifier = Modifier.width(16.dp))
Image(
painter = painterResource(id = R.drawable.rider_pro_send),
contentDescription = "Send",
modifier = Modifier
.size(32.dp)
)
}
}
}

View File

@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@@ -36,6 +37,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@@ -43,6 +45,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import coil.compose.AsyncImage
import com.aiosman.riderpro.LocalAnimatedContentScope 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
@@ -251,34 +254,30 @@ fun MomentTopRowGroup(momentItem: MomentItem) {
fun MomentContentGroup( fun MomentContentGroup(
momentItem: MomentItem, momentItem: MomentItem,
) { ) {
val sharedTransitionScope = LocalSharedTransitionScope.current // val sharedTransitionScope = LocalSharedTransitionScope.current
val animatedContentScope = LocalAnimatedContentScope.current // val animatedContentScope = LocalAnimatedContentScope.current
with(sharedTransitionScope) { val displayImageUrl = momentItem.images.firstOrNull()
Text( Text(
text = momentItem.momentTextContent, text = momentItem.momentTextContent,
modifier = Modifier modifier = Modifier
.sharedElement(
sharedTransitionScope.rememberSharedContentState(key = "text-${momentItem.id}"),
animatedVisibilityScope = animatedContentScope
)
.fillMaxWidth() .fillMaxWidth()
.padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp), .padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp),
fontSize = 16.sp fontSize = 16.sp
) )
Image( displayImageUrl?.let {
AsyncImage(
it,
modifier = Modifier modifier = Modifier
.sharedElement( .fillMaxWidth()
sharedTransitionScope.rememberSharedContentState(key = "image-${momentItem.id}"), .aspectRatio(1f),
animatedVisibilityScope = animatedContentScope contentScale = ContentScale.Crop,
)
.fillMaxWidth(),
painter = painterResource(id = momentItem.momentPicture),
contentDescription = "" contentDescription = ""
) )
} }
} }
@Composable @Composable
fun MomentOperateBtn(@DrawableRes icon: Int, count: String) { fun MomentOperateBtn(@DrawableRes icon: Int, count: String) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {

View File

@@ -36,8 +36,10 @@ import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
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
@@ -56,36 +58,66 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import coil.compose.AsyncImage
import com.aiosman.riderpro.LocalAnimatedContentScope import com.aiosman.riderpro.LocalAnimatedContentScope
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.comment.Comment
import com.aiosman.riderpro.data.comment.CommentPagingSource
import com.aiosman.riderpro.data.comment.CommentRemoteDataSource
import com.aiosman.riderpro.data.comment.TestCommentServiceImpl
import com.aiosman.riderpro.data.moment.MomentService
import com.aiosman.riderpro.data.moment.TestMomentServiceImpl
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.ui.comment.CommentModalContent
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
import com.aiosman.riderpro.ui.composables.EditCommentBottomModal
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
fun makeMockImages(): List<PostImage> {
return listOf(
PostImage(R.drawable.default_moment_img, "Image 1"),
PostImage(R.drawable.default_avatar, "Image 2"),
PostImage(R.drawable.rider_pro_moment_demo_1, "Image 3")
)
}
@OptIn(ExperimentalSharedTransitionApi::class) @OptIn(ExperimentalSharedTransitionApi::class)
@Composable @Composable
fun PostScreen( fun PostScreen(
id: String, id: String,
) { ) {
var service: MomentService = TestMomentServiceImpl()
var commentSource = CommentPagingSource(
CommentRemoteDataSource(TestCommentServiceImpl())
)
val commentsFlow: Flow<PagingData<Comment>> = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = { commentSource }
).flow
val lazyPagingItems = commentsFlow.collectAsLazyPagingItems()
var showCollapseContent by remember { mutableStateOf(true) } var showCollapseContent by remember { mutableStateOf(true) }
val scrollState = rememberLazyListState() val scrollState = rememberLazyListState()
val uiController = rememberSystemUiController()
var moment by remember { mutableStateOf<MomentItem?>(null) }
LaunchedEffect(Unit) {
uiController.setNavigationBarColor(Color.White)
moment = service.getMomentById(id.toInt())
}
StatusBarMaskLayout { StatusBarMaskLayout {
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
bottomBar = { BottomNavigationBar() } bottomBar = { BottomNavigationBar() }
) { ) {
it it
Column(modifier = Modifier.fillMaxSize()) { Column(
modifier = Modifier
.fillMaxSize()
) {
Header() Header()
Column(modifier = Modifier.animateContentSize()) { Column(modifier = Modifier.animateContentSize()) {
AnimatedVisibility(visible = showCollapseContent) { AnimatedVisibility(visible = showCollapseContent) {
@@ -99,12 +131,13 @@ fun PostScreen(
) { ) {
PostImageView( PostImageView(
id, id,
makeMockImages(), moment?.images ?: emptyList()
) )
} }
PostDetails( PostDetails(
id, id,
moment
) )
} }
} }
@@ -114,18 +147,18 @@ fun PostScreen(
.fillMaxWidth() .fillMaxWidth()
) { ) {
CommentsSection(scrollState) { CommentsSection(lazyPagingItems = lazyPagingItems, scrollState) {
showCollapseContent = it showCollapseContent = it
} }
} }
} }
} }
} }
} }
@Composable @Composable
fun Header() { fun Header() {
val navController = LocalNavController.current
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -136,6 +169,9 @@ fun Header() {
painter = painterResource(id = R.drawable.rider_pro_nav_back), // Replace with your image resource painter = painterResource(id = R.drawable.rider_pro_nav_back), // Replace with your image resource
contentDescription = "Back", contentDescription = "Back",
modifier = Modifier modifier = Modifier
.noRippleClickable {
navController.popBackStack()
}
.size(32.dp) .size(32.dp)
) )
@@ -171,37 +207,27 @@ fun Header() {
} }
} }
data class PostImage(
val imgRes: Int,
val description: String
)
@OptIn(ExperimentalFoundationApi::class, ExperimentalSharedTransitionApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun PostImageView( fun PostImageView(
postId: String, postId: String,
images: List<PostImage>, images: List<String>,
) { ) {
val sharedTransitionScope = LocalSharedTransitionScope.current
val animatedContentScope = LocalAnimatedContentScope.current
val pagerState = rememberPagerState(pageCount = { images.size }) val pagerState = rememberPagerState(pageCount = { images.size })
with(sharedTransitionScope) {
Column { Column {
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.fillMaxWidth() .fillMaxWidth(),
) { page -> ) { page ->
Image( val image = images[page]
painter = painterResource(id = images[page].imgRes), AsyncImage(
contentDescription = images[page].description, image,
contentDescription = "Image",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier.Companion modifier = Modifier
.sharedElement(
sharedTransitionScope.rememberSharedContentState(key = "image-$postId"),
animatedVisibilityScope = animatedContentScope
)
.fillMaxSize() .fillMaxSize()
) )
} }
@@ -232,196 +258,46 @@ fun PostImageView(
} }
} }
} }
}
} }
@OptIn(ExperimentalSharedTransitionApi::class) @OptIn(ExperimentalSharedTransitionApi::class)
@Composable @Composable
fun PostDetails( fun PostDetails(
postId: String, postId: String,
momentItem: MomentItem?
) { ) {
val sharedTransitionScope = LocalSharedTransitionScope.current momentItem?.let {
val animatedContentScope = LocalAnimatedContentScope.current
with(sharedTransitionScope) {
Column(modifier = Modifier.padding(16.dp)) { Column(modifier = Modifier.padding(16.dp)) {
Text(text = "By strongarming Ducati into giving him the factory seat.Marquez effectively …", fontSize = 16.sp, fontWeight = FontWeight.Bold, modifier = Modifier.Companion.sharedElement( Text(
sharedTransitionScope.rememberSharedContentState(key = "text-$postId"), text = momentItem.momentTextContent,
animatedVisibilityScope = animatedContentScope fontSize = 16.sp,
)) fontWeight = FontWeight.Bold,
)
Text(text = "12-11 发布") Text(text = "12-11 发布")
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text(text = "共231条评论") Text(text = "共231条评论")
} }
} }
}
fun MakeMockComments(): List<Comment> {
return listOf(
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = listOf(
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
)
)
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
),
Comment(
name = "Diego Morata",
comment = "这里太适合骑行了",
date = "3 days ago",
likes = 200,
replies = emptyList()
)
)
} }
@Composable @Composable
fun CommentsSection( fun CommentsSection(
lazyPagingItems: LazyPagingItems<Comment>,
scrollState: LazyListState = rememberLazyListState(), scrollState: LazyListState = rememberLazyListState(),
onWillCollapse: (Boolean) -> Unit onWillCollapse: (Boolean) -> Unit
) { ) {
val items = MakeMockComments()
LazyColumn( LazyColumn(
state = scrollState, modifier = Modifier state = scrollState, modifier = Modifier
.padding(start = 16.dp, end = 16.dp) .padding(start = 16.dp, end = 16.dp)
.fillMaxHeight() .fillMaxHeight()
) { ) {
items(items) { comment -> items(lazyPagingItems.itemCount) { idx ->
CommentItem(comment) val item = lazyPagingItems[idx] ?: return@items
CommentItem(item)
} }
} }
@@ -437,14 +313,6 @@ fun CommentsSection(
} }
} }
data class Comment(
val name: String,
val comment: String,
val date: String,
val likes: Int,
val replies: List<Comment>
)
@Composable @Composable
fun CommentItem(comment: Comment) { fun CommentItem(comment: Comment) {
@@ -485,6 +353,21 @@ fun CommentItem(comment: Comment) {
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun BottomNavigationBar() { fun BottomNavigationBar() {
val systemUiController = rememberSystemUiController()
var showCommentModal by remember { mutableStateOf(false) }
if (showCommentModal) {
ModalBottomSheet(
onDismissRequest = { showCommentModal = false },
containerColor = Color.White,
sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true
),
dragHandle = {},
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
) {
EditCommentBottomModal()
}
}
Column( Column(
modifier = Modifier.background(Color.White) modifier = Modifier.background(Color.White)
) { ) {
@@ -503,6 +386,9 @@ fun BottomNavigationBar() {
.weight(1f) .weight(1f)
.height(31.dp) .height(31.dp)
.padding(8.dp) .padding(8.dp)
.noRippleClickable {
showCommentModal = true
}
) { ) {
Row( Row(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically