添加更新数据

This commit is contained in:
2024-07-29 16:50:07 +08:00
parent d23c5f5c7e
commit 53c71973ae
11 changed files with 398 additions and 189 deletions

View File

@@ -1,5 +1,7 @@
package com.aiosman.riderpro.data
import com.aiosman.riderpro.test.TestDatabase
data class AccountProfile(
val id: Int,
val followerCount: Int,
@@ -11,19 +13,16 @@ data class AccountProfile(
)
interface AccountService {
suspend fun getAccountProfile(): AccountProfile
suspend fun getMyAccountProfile(): AccountProfile
suspend fun getAccountProfileById(id: Int): AccountProfile
}
class TestAccountServiceImpl : AccountService {
override suspend fun getAccountProfile(): AccountProfile {
return AccountProfile(
id = 1,
followerCount = 100,
followingCount = 200,
nickName = "Aiosman",
avatar = "https://img.freepik.com/free-photo/white-billboard-template_23-2147726635.jpg?t=st=1722150015~exp=1722153615~hmac=5540620196d7898215d822be26353c87a63d51bbfb2b814e032626e1948a1583&w=740",
bio = "I am a software engineer",
country = "Nigeria"
)
override suspend fun getMyAccountProfile(): AccountProfile {
return TestDatabase.accountData.first { it.id == 0 }
}
override suspend fun getAccountProfileById(id: Int): AccountProfile {
return TestDatabase.accountData.first { it.id == id }
}
}

View File

@@ -2,28 +2,43 @@ package com.aiosman.riderpro.data
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.aiosman.riderpro.test.TestDatabase
import java.io.IOException
import java.util.Calendar
import kotlin.math.min
import kotlin.random.Random
interface CommentService {
suspend fun getComments(pageNumber: Int, postId: Int? = null): ListContainer<Comment>
suspend fun createComment(postId: Int, content: String, authorId: Int): Comment
suspend fun likeComment(commentId: Int)
}
data class Comment(
val id: Int,
val name: String,
val comment: String,
val date: String,
val likes: Int,
val replies: List<Comment>
val replies: List<Comment>,
val postId: Int = 0,
val avatar: String,
val author: Int,
val liked: Boolean,
)
class CommentPagingSource(
private val remoteDataSource: CommentRemoteDataSource,
private val postId: Int? = null
) : 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
pageNumber = currentPage,
postId = postId
)
LoadResult.Page(
data = comments.list,
prevKey = if (currentPage == 1) null else currentPage - 1,
@@ -43,52 +58,70 @@ class CommentPagingSource(
class CommentRemoteDataSource(
private val commentService: CommentService,
) {
suspend fun getComments(pageNumber: Int): ListContainer<Comment> {
return commentService.getComments(pageNumber)
suspend fun getComments(pageNumber: Int, postId: Int?): ListContainer<Comment> {
return commentService.getComments(pageNumber, postId)
}
}
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)
override suspend fun getComments(pageNumber: Int, postId: Int?): ListContainer<Comment> {
var rawList = TestDatabase.comment
if (postId != null) {
rawList = rawList.filter { it.postId == postId }
}
val from = (pageNumber - 1) * DataBatchSize
val to = (pageNumber) * DataBatchSize
rawList = rawList.sortedBy { -it.id }
if (from >= rawList.size) {
return ListContainer(
total = rawList.size,
page = pageNumber,
pageSize = DataBatchSize,
list = emptyList()
)
}
rawList = rawList.sortedBy { -it.id }
val currentSublist = rawList.subList(from, min(to, rawList.size))
return ListContainer(
total = mockData.size,
total = rawList.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()
)
override suspend fun createComment(postId: Int, content: String, authorId: Int): Comment {
var author = TestDatabase.accountData.find { it.id == authorId }
if (author == null) {
author = TestDatabase.accountData.random()
}
TestDatabase.commentIdCounter += 1
val newComment = Comment(
name = author.nickName,
comment = content,
date = Calendar.getInstance().time.toString(),
likes = 0,
replies = emptyList(),
postId = postId,
avatar = author.avatar,
author = author.id,
id = TestDatabase.commentIdCounter,
liked = false
)
TestDatabase.comment += newComment
return newComment
}
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()
)
override suspend fun likeComment(commentId: Int) {
TestDatabase.comment = TestDatabase.comment.map {
if (it.id == commentId) {
it.copy(likes = it.likes + 1)
} else {
it
}
}
}
companion object {

View File

@@ -2,19 +2,34 @@ package com.aiosman.riderpro.data
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.aiosman.riderpro.R
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.test.TestDatabase
import java.io.IOException
import kotlin.math.min
interface MomentService {
suspend fun getMomentById(id: Int): MomentItem
suspend fun likeMoment(id: Int)
suspend fun getMoments(
pageNumber: Int,
author: Int? = null,
timelineId: Int? = null
): ListContainer<MomentItem>
}
class MomentPagingSource(
private val remoteDataSource: MomentRemoteDataSource,
private val author: Int? = null,
private val timelineId: Int? = null
) : PagingSource<Int, MomentItem>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MomentItem> {
return try {
val currentPage = params.key ?: 1
val moments = remoteDataSource.getMoments(
pageNumber = currentPage
pageNumber = currentPage,
author = author,
timelineId = timelineId
)
LoadResult.Page(
@@ -36,63 +51,88 @@ class MomentPagingSource(
class MomentRemoteDataSource(
private val momentService: MomentService,
) {
suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem> {
return momentService.getMoments(pageNumber)
suspend fun getMoments(
pageNumber: Int,
author: Int?,
timelineId: Int?
): ListContainer<MomentItem> {
return momentService.getMoments(pageNumber, author, timelineId)
}
}
interface MomentService {
suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem>
suspend fun getMomentById(id: Int): MomentItem
suspend fun likeMoment(id: Int)
}
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"
)
var mockData = TestDatabase.momentData
val testMomentBackend = TestMomentBackend(mockData)
override suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem> {
return testMomentBackend.fetchMomentItems(pageNumber)
val testMomentBackend = TestMomentBackend()
override suspend fun getMoments(
pageNumber: Int,
author: Int?,
timelineId: Int?
): ListContainer<MomentItem> {
return testMomentBackend.fetchMomentItems(pageNumber, author, timelineId)
}
override suspend fun getMomentById(id: Int): MomentItem {
return mockData[id]
return testMomentBackend.getMomentById(id)
}
override suspend fun likeMoment(id: Int) {
// mockData = mockData.map {
// if (it.id == id) {
// it.copy(likeCount = it.likeCount + 1)
// } else {
// it
// }
// }
// mockData
testMomentBackend.likeMoment(id)
}
}
class TestMomentBackend(
private val mockData: List<MomentItem>,
private val loadDelay: Long = 500,
) {
val DataBatchSize = 5
suspend fun fetchMomentItems(pageNumber: Int): ListContainer<MomentItem> {
val from = pageNumber * DataBatchSize
val to = (pageNumber + 1) * DataBatchSize
val currentSublist = mockData.subList(from, to)
suspend fun fetchMomentItems(
pageNumber: Int,
author: Int? = null,
timelineId: Int?
): ListContainer<MomentItem> {
var rawList = TestDatabase.momentData
if (author != null) {
rawList = rawList.filter { it.authorId == author }
}
if (timelineId != null) {
val followIdList = TestDatabase.followList.filter {
it.first == timelineId
}.map { it.second }
rawList = rawList.filter { it.authorId in followIdList }
}
val from = (pageNumber - 1) * DataBatchSize
val to = (pageNumber) * DataBatchSize
if (from >= rawList.size) {
return ListContainer(
total = rawList.size,
page = pageNumber,
pageSize = DataBatchSize,
list = emptyList()
)
}
val currentSublist = rawList.subList(from, min(to, rawList.size))
// delay
kotlinx.coroutines.delay(loadDelay)
return ListContainer(
total = mockData.size,
total = rawList.size,
page = pageNumber,
pageSize = DataBatchSize,
list = currentSublist
)
}
suspend fun getMomentById(id: Int): MomentItem {
return TestDatabase.momentData[id]
}
suspend fun likeMoment(id: Int) {
val oldMoment = TestDatabase.momentData.first {
it.id == id
}
val newMoment = oldMoment.copy(likeCount = oldMoment.likeCount + 1)
TestDatabase.updateMomentById(id, newMoment)
}
}

View File

@@ -2,18 +2,24 @@ package com.aiosman.riderpro.test
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.AccountProfile
import com.aiosman.riderpro.data.Comment
import com.aiosman.riderpro.model.MomentItem
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import io.github.serpro69.kfaker.faker
import java.io.File
object TestDatabase {
var momentData = emptyList<MomentItem>()
var accountData = emptyList<AccountProfile>()
var comment = emptyList<Comment>()
var commentIdCounter = 0
var selfId = 1
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",
"https://t4.ftcdn.net/jpg/02/27/00/89/240_F_227008949_5O7yXuEqTwUgs3BGqdcvrNutM5MSxs1t.jpg",
"https://t4.ftcdn.net/jpg/01/86/86/49/240_F_186864971_NixcoDg1zBjjN7soUNhpEVraI4vdzOFD.jpg",
"https://t3.ftcdn.net/jpg/00/84/01/30/240_F_84013057_fsOdzBgskSFUyWyD6YKjIAdtKdBPiKRD.jpg",
"https://t4.ftcdn.net/jpg/00/93/89/23/240_F_93892312_SNyGGruVaWKpJQiVG314gIQmS4EAghdy.jpg",
@@ -32,14 +38,14 @@ object TestDatabase {
"https://t3.ftcdn.net/jpg/02/65/43/04/240_F_265430460_DIHqnrziar7WL2rmW0qbDO07TbxjlPQo.jpg"
)
var followList = emptyList<Pair<Int, Int>>()
var likeCommentList = emptyList<Pair<Int, Int>>()
init {
val faker = faker {
this.fakerConfig {
locale = "en"
}
}
accountData = (0..300).toList().mapIndexed { idx, _ ->
accountData = (0..100).toList().mapIndexed { idx, _ ->
AccountProfile(
id = idx,
followerCount = 0,
@@ -52,7 +58,7 @@ object TestDatabase {
)
}
// make a random follow rel
for (i in 0..10000) {
for (i in 0..500) {
var person1 = accountData.random()
var persion2 = accountData.random()
followList += Pair(person1.id, persion2.id)
@@ -66,11 +72,34 @@ object TestDatabase {
it
}
}
}
momentData = (0..300).toList().mapIndexed { idx, _ ->
momentData = (0..200).toList().mapIndexed { idx, _ ->
val person = accountData.random()
// make fake comment
for (i in 0..faker.random.nextInt(0, 5)) {
commentIdCounter += 1
val commentPerson = accountData.random()
var newComment = Comment(
name = commentPerson.nickName,
comment = "this is comment ${commentIdCounter}",
date = "2023-02-02 11:23",
likes = 0,
replies = emptyList(),
postId = idx,
avatar = commentPerson.avatar,
author = commentPerson.id,
id = commentIdCounter,
liked = false
)
// generate like comment list
for (likeIdx in 0..faker.random.nextInt(0, 5)) {
val likePerson = accountData.random()
likeCommentList += Pair(commentIdCounter, likePerson.id)
newComment = newComment.copy(likes = newComment.likes + 1)
}
comment += newComment
}
MomentItem(
id = idx,
avatar = person.avatar,
@@ -89,4 +118,24 @@ object TestDatabase {
)
}
}
fun updateMomentById(id: Int, momentItem: MomentItem) {
momentData = momentData.map {
if (it.id == id) {
momentItem
} else {
it
}
}
}
fun saveResultToJsonFile() {
val gson: Gson = GsonBuilder().setPrettyPrinting().create()
// save accountData to json file
File("accountData.json").writeText(accountData.toString())
// save momentData to json file
// save comment to json file
}
}

View File

@@ -23,6 +23,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
@@ -35,30 +36,54 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
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.CommentPagingSource
import com.aiosman.riderpro.data.CommentRemoteDataSource
import com.aiosman.riderpro.data.CommentService
import com.aiosman.riderpro.data.TestCommentServiceImpl
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
class CommentModalViewModel(
postId: Int?
):ViewModel(){
val commentService:CommentService = TestCommentServiceImpl()
val commentsFlow: Flow<PagingData<Comment>> = Pager(
config = PagingConfig(pageSize = 20, enablePlaceholders = false),
pagingSourceFactory = {
CommentPagingSource(
CommentRemoteDataSource(commentService),
postId
)
}
).flow.cachedIn(viewModelScope)
}
@Preview
@Composable
fun CommentModalContent(onDismiss: () -> Unit = {}) {
var commentSource = CommentPagingSource(
CommentRemoteDataSource(TestCommentServiceImpl())
fun CommentModalContent(postId: Int? = null, onDismiss: () -> Unit = {}) {
val model = viewModel<CommentModalViewModel>(
factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return CommentModalViewModel(postId) as T
}
}
)
val commentsFlow: Flow<PagingData<Comment>> = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = { commentSource }
).flow
val comments = commentsFlow.collectAsLazyPagingItems()
val scope = rememberCoroutineScope()
val comments = model.commentsFlow.collectAsLazyPagingItems()
val insets = WindowInsets
val imePadding = insets.ime.getBottom(density = LocalDensity.current)
var bottomPadding by remember { mutableStateOf(0.dp) }
@@ -70,7 +95,14 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
onDismiss()
}
}
var commentText by remember { mutableStateOf("") }
suspend fun sendComment() {
if (commentText.isNotEmpty()) {
model.commentService.createComment(postId!!, commentText, 1)
commentText = ""
}
comments.refresh()
}
Column(
modifier = Modifier
) {
@@ -97,8 +129,13 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
.padding(horizontal = 16.dp)
.weight(1f)
) {
CommentsSection(lazyPagingItems = comments) {
CommentsSection(lazyPagingItems = comments, onLike = {
comment: Comment ->
scope.launch {
model.commentService.likeComment(comment.id)
comments.refresh()
}
}) {
}
@@ -127,8 +164,8 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
) {
BasicTextField(
value = "",
onValueChange = { },
value = commentText,
onValueChange = { text -> commentText = text },
modifier = Modifier
.fillMaxWidth(),
textStyle = TextStyle(
@@ -144,7 +181,11 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
contentDescription = "Send",
modifier = Modifier
.size(32.dp)
.noRippleClickable {
scope.launch {
sendComment()
}
}
)
}

View File

@@ -72,7 +72,7 @@ fun MomentsList() {
MomentCard(momentItem = momentItem, onLikeClick = {
scope.launch {
model.likeMoment(momentItem.id)
moments.refresh()
// moments.refresh()
}
})
}
@@ -253,7 +253,7 @@ fun MomentContentGroup(
) {
val displayImageUrl = momentItem.images.firstOrNull()
Text(
text = momentItem.momentTextContent,
text = "${momentItem.id} ${momentItem.momentTextContent}",
modifier = Modifier
.fillMaxWidth()
.padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp),
@@ -323,7 +323,7 @@ fun MomentBottomOperateRowGroup(
)
) {
systemUiController.setNavigationBarColor(Color(0xfff7f7f7))
CommentModalContent() {
CommentModalContent(postId = momentItem.id) {
systemUiController.setNavigationBarColor(Color.Black)
}
}

View File

@@ -1,39 +1,57 @@
package com.aiosman.riderpro.ui.index.tabs.moment
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.toMutableStateList
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.aiosman.riderpro.R
import androidx.paging.cachedIn
import androidx.paging.map
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.MomentPagingSource
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 kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
object MomentViewModel : ViewModel() {
val momentService: MomentService = TestMomentServiceImpl()
var momentListPagingSource = MomentPagingSource(
MomentRemoteDataSource(momentService)
)
var momentsFlow: Flow<PagingData<MomentItem>> = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
MomentPagingSource(
MomentRemoteDataSource(momentService)
)
private val momentService: MomentService = TestMomentServiceImpl()
private val _momentsFlow = MutableStateFlow<PagingData<MomentItem>>(PagingData.empty())
val momentsFlow = _momentsFlow.asStateFlow()
val accountService: AccountService = TestAccountServiceImpl()
init {
viewModelScope.launch {
val profile = accountService.getMyAccountProfile()
Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = { MomentPagingSource(
MomentRemoteDataSource(momentService),
timelineId = profile.id
) }
).flow.cachedIn(viewModelScope).collectLatest {
_momentsFlow.value = it
}
}
).flow
}
suspend fun likeMoment(id: Int) {
momentService.likeMoment(id)
val currentPagingData = _momentsFlow.value
val updatedPagingData = currentPagingData.map { momentItem ->
if (momentItem.id == id) {
momentItem.copy(likeCount = momentItem.likeCount + 1)
} else {
momentItem
}
}
_momentsFlow.value = updatedPagingData
}
}

View File

@@ -18,18 +18,20 @@ import kotlinx.coroutines.flow.Flow
object MyProfileViewModel {
val service: AccountService = TestAccountServiceImpl()
var profile by mutableStateOf<AccountProfile?>(null)
var momentsFlow by mutableStateOf<Flow<PagingData<MomentItem>>?>(null)
suspend fun loadProfile() {
profile = service.getAccountProfile()
profile = service.getMyAccountProfile()
momentsFlow = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
MomentPagingSource(
MomentRemoteDataSource(TestMomentServiceImpl()),
author = profile?.id ?: 0,
)
}
).flow
}
var momentListPagingSource = MomentPagingSource(
MomentRemoteDataSource(TestMomentServiceImpl())
)
val momentsFlow: Flow<PagingData<MomentItem>> = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = { momentListPagingSource }
).flow
val followerCount get() = profile?.followerCount ?: 0
val followingCount get() = profile?.followingCount ?: 0
val bio get() = profile?.bio ?: ""

View File

@@ -19,9 +19,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -51,7 +49,7 @@ fun ProfilePage() {
LaunchedEffect(Unit) {
model.loadProfile()
}
val profile = model.momentsFlow.collectAsLazyPagingItems()
val moments = model.momentsFlow?.collectAsLazyPagingItems()
LazyColumn(
modifier = Modifier
.fillMaxSize()
@@ -67,10 +65,13 @@ fun ProfilePage() {
RidingStyle()
}
items(profile.itemCount) { idx ->
val momentItem = profile[idx] ?: return@items
MomentPostUnit(momentItem)
moments?.let {
items(it.itemCount) { idx ->
val momentItem = it[idx] ?: return@items
MomentPostUnit(momentItem)
}
}
}
}
@@ -409,7 +410,7 @@ fun MomentPostUnit(momentItem: MomentItem) {
TimeGroup(momentItem.time)
MomentCard(
momentItem.momentTextContent,
momentItem.momentPicture,
momentItem.images[0],
momentItem.likeCount.toString(),
momentItem.commentCount.toString()
)
@@ -439,7 +440,7 @@ fun TimeGroup(time: String = "2024.06.08 12:23") {
}
@Composable
fun MomentCard(content: String, @DrawableRes picture: Int, like: String, comment: String) {
fun MomentCard(content: String, imageUrl: String, like: String, comment: String) {
Column(
modifier = Modifier
.fillMaxWidth()
@@ -447,7 +448,7 @@ fun MomentCard(content: String, @DrawableRes picture: Int, like: String, comment
.border(width = 1.dp, color = Color(0f, 0f, 0f, 0.1f), shape = RoundedCornerShape(6.dp))
) {
MomentCardTopContent(content)
MomentCardPicture(picture)
MomentCardPicture(imageUrl)
MomentCardOperation(like, comment)
}
}
@@ -468,13 +469,15 @@ fun MomentCardTopContent(content: String) {
}
@Composable
fun MomentCardPicture(@DrawableRes drawable: Int) {
Image(
fun MomentCardPicture(imageUrl:String) {
AsyncImage(
imageUrl,
modifier = Modifier
.fillMaxSize()
.padding(16.dp), painter = painterResource(id = drawable), contentDescription = ""
.padding(16.dp),
contentDescription = "",
contentScale = ContentScale.FillWidth
)
}
@Composable

View File

@@ -66,11 +66,14 @@ import androidx.paging.compose.collectAsLazyPagingItems
import coil.compose.AsyncImage
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.AccountProfile
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.Comment
import com.aiosman.riderpro.data.CommentPagingSource
import com.aiosman.riderpro.data.CommentRemoteDataSource
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.ui.composables.StatusBarMaskLayout
@@ -101,9 +104,14 @@ fun PostScreen(
val scrollState = rememberLazyListState()
val uiController = rememberSystemUiController()
var moment by remember { mutableStateOf<MomentItem?>(null) }
var accountProfile by remember { mutableStateOf<AccountProfile?>(null) }
var accountService: AccountService = TestAccountServiceImpl()
LaunchedEffect(Unit) {
uiController.setNavigationBarColor(Color.White)
moment = service.getMomentById(id.toInt())
moment?.let {
accountProfile = accountService.getAccountProfileById(it.authorId)
}
}
StatusBarMaskLayout {
Scaffold(
@@ -115,7 +123,7 @@ fun PostScreen(
modifier = Modifier
.fillMaxSize()
) {
Header()
Header(accountProfile)
Column(modifier = Modifier.animateContentSize()) {
AnimatedVisibility(visible = showCollapseContent) {
// collapse content
@@ -148,7 +156,7 @@ fun PostScreen(
.fillMaxWidth()
) {
CommentsSection(lazyPagingItems = lazyPagingItems, scrollState) {
CommentsSection(lazyPagingItems = lazyPagingItems, scrollState, onLike = {}) {
showCollapseContent = it
}
}
@@ -158,7 +166,7 @@ fun PostScreen(
}
@Composable
fun Header() {
fun Header(accountProfile: AccountProfile?) {
val navController = LocalNavController.current
Row(
modifier = Modifier
@@ -177,15 +185,22 @@ fun Header() {
)
Spacer(modifier = Modifier.width(8.dp))
Image(
painter = painterResource(id = R.drawable.default_avatar), // Replace with your image resource
contentDescription = "Profile Picture",
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
)
accountProfile?.let {
AsyncImage(
accountProfile.avatar,
contentDescription = "Profile Picture",
modifier = Modifier
.size(40.dp)
.clip(CircleShape),
contentScale = ContentScale.Crop
)
}
Spacer(modifier = Modifier.width(8.dp))
Text(text = "Diego Morata", fontWeight = FontWeight.Bold)
accountProfile?.let {
Text(text = accountProfile.nickName, fontWeight = FontWeight.Bold)
}
Box(
modifier = Modifier
.height(20.dp)
@@ -269,25 +284,23 @@ fun PostDetails(
momentItem: MomentItem?
) {
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.wrapContentHeight()
) {
Text(
text = momentItem?.momentTextContent ?:"",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
)
Text(text = "12-11 发布")
Spacer(modifier = Modifier.height(8.dp))
Text(text = "共231条评论")
}
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.wrapContentHeight()
) {
Text(
text = momentItem?.momentTextContent ?: "",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
)
Text(text = "12-11 发布")
Spacer(modifier = Modifier.height(8.dp))
Text(text = "共231条评论")
}
}
@@ -296,6 +309,7 @@ fun PostDetails(
fun CommentsSection(
lazyPagingItems: LazyPagingItems<Comment>,
scrollState: LazyListState = rememberLazyListState(),
onLike: (Comment) -> Unit,
onWillCollapse: (Boolean) -> Unit
) {
LazyColumn(
@@ -305,7 +319,9 @@ fun CommentsSection(
) {
items(lazyPagingItems.itemCount) { idx ->
val item = lazyPagingItems[idx] ?: return@items
CommentItem(item)
CommentItem(item,onLike={
onLike(item)
})
}
}
@@ -323,15 +339,16 @@ fun CommentsSection(
@Composable
fun CommentItem(comment: Comment) {
fun CommentItem(comment: Comment,onLike:()->Unit = {}) {
Column {
Row(modifier = Modifier.padding(vertical = 8.dp)) {
Image(
painter = painterResource(id = R.drawable.default_avatar), // Replace with your image resource
AsyncImage(
comment.avatar,
contentDescription = "Comment Profile Picture",
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.clip(CircleShape),
contentScale = ContentScale.Crop
)
Spacer(modifier = Modifier.width(8.dp))
Column {
@@ -341,7 +358,9 @@ fun CommentItem(comment: Comment) {
}
Spacer(modifier = Modifier.weight(1f))
Column(horizontalAlignment = Alignment.CenterHorizontally) {
IconButton(onClick = { /*TODO*/ }) {
IconButton(onClick = {
onLike()
}) {
Icon(Icons.Filled.Favorite, contentDescription = "Like")
}
Text(text = comment.likes.toString())

View File

@@ -37,18 +37,22 @@ fun AccountProfile(id:String) {
// val model = MyProfileViewModel
val userService: UserService = TestUserServiceImpl()
var userProfile by remember { mutableStateOf<AccountProfile?>(null) }
var momentListPagingSource = MomentPagingSource(
MomentRemoteDataSource(TestMomentServiceImpl())
)
val momentsFlow: Flow<PagingData<MomentItem>> = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = { momentListPagingSource }
).flow
val momentService = TestMomentServiceImpl()
var momentsFlow by remember { mutableStateOf<Flow<PagingData<MomentItem>>?>(null) }
LaunchedEffect(Unit) {
userProfile = userService.getUserProfile(id)
momentsFlow = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
MomentPagingSource(
MomentRemoteDataSource(momentService),
author = id.toInt()
)
}
).flow
}
val items = momentsFlow.collectAsLazyPagingItems()
val items = momentsFlow?.collectAsLazyPagingItems()
val systemUiController = rememberSystemUiController()
LaunchedEffect(Unit) {
systemUiController.setNavigationBarColor(
@@ -70,13 +74,14 @@ fun AccountProfile(id:String) {
CarGroup()
userProfile?.let {
UserInformation(isSelf = false, accountProfile = it)
}
RidingStyle()
}
items(items.itemCount) { idx ->
val momentItem = items[idx] ?: return@items
MomentPostUnit(momentItem)
if (items != null) {
items(items.itemCount) { idx ->
val momentItem = items[idx] ?: return@items
MomentPostUnit(momentItem)
}
}
}
}