添加更新数据
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
package com.aiosman.riderpro.data
|
package com.aiosman.riderpro.data
|
||||||
|
|
||||||
|
import com.aiosman.riderpro.test.TestDatabase
|
||||||
|
|
||||||
data class AccountProfile(
|
data class AccountProfile(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val followerCount: Int,
|
val followerCount: Int,
|
||||||
@@ -11,19 +13,16 @@ data class AccountProfile(
|
|||||||
)
|
)
|
||||||
|
|
||||||
interface AccountService {
|
interface AccountService {
|
||||||
suspend fun getAccountProfile(): AccountProfile
|
suspend fun getMyAccountProfile(): AccountProfile
|
||||||
|
suspend fun getAccountProfileById(id: Int): AccountProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestAccountServiceImpl : AccountService {
|
class TestAccountServiceImpl : AccountService {
|
||||||
override suspend fun getAccountProfile(): AccountProfile {
|
override suspend fun getMyAccountProfile(): AccountProfile {
|
||||||
return AccountProfile(
|
return TestDatabase.accountData.first { it.id == 0 }
|
||||||
id = 1,
|
}
|
||||||
followerCount = 100,
|
|
||||||
followingCount = 200,
|
override suspend fun getAccountProfileById(id: Int): AccountProfile {
|
||||||
nickName = "Aiosman",
|
return TestDatabase.accountData.first { it.id == id }
|
||||||
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"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,28 +2,43 @@ package com.aiosman.riderpro.data
|
|||||||
|
|
||||||
import androidx.paging.PagingSource
|
import androidx.paging.PagingSource
|
||||||
import androidx.paging.PagingState
|
import androidx.paging.PagingState
|
||||||
|
import com.aiosman.riderpro.test.TestDatabase
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.Calendar
|
||||||
|
import kotlin.math.min
|
||||||
import kotlin.random.Random
|
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(
|
data class Comment(
|
||||||
|
val id: Int,
|
||||||
val name: String,
|
val name: String,
|
||||||
val comment: String,
|
val comment: String,
|
||||||
val date: String,
|
val date: String,
|
||||||
val likes: Int,
|
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(
|
class CommentPagingSource(
|
||||||
private val remoteDataSource: CommentRemoteDataSource,
|
private val remoteDataSource: CommentRemoteDataSource,
|
||||||
|
private val postId: Int? = null
|
||||||
) : PagingSource<Int, Comment>() {
|
) : PagingSource<Int, Comment>() {
|
||||||
|
|
||||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Comment> {
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Comment> {
|
||||||
return try {
|
return try {
|
||||||
val currentPage = params.key ?: 1
|
val currentPage = params.key ?: 1
|
||||||
val comments = remoteDataSource.getComments(
|
val comments = remoteDataSource.getComments(
|
||||||
pageNumber = currentPage
|
pageNumber = currentPage,
|
||||||
|
postId = postId
|
||||||
)
|
)
|
||||||
|
|
||||||
LoadResult.Page(
|
LoadResult.Page(
|
||||||
data = comments.list,
|
data = comments.list,
|
||||||
prevKey = if (currentPage == 1) null else currentPage - 1,
|
prevKey = if (currentPage == 1) null else currentPage - 1,
|
||||||
@@ -43,52 +58,70 @@ class CommentPagingSource(
|
|||||||
class CommentRemoteDataSource(
|
class CommentRemoteDataSource(
|
||||||
private val commentService: CommentService,
|
private val commentService: CommentService,
|
||||||
) {
|
) {
|
||||||
suspend fun getComments(pageNumber: Int): ListContainer<Comment> {
|
suspend fun getComments(pageNumber: Int, postId: Int?): ListContainer<Comment> {
|
||||||
return commentService.getComments(pageNumber)
|
return commentService.getComments(pageNumber, postId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CommentService {
|
|
||||||
suspend fun getComments(pageNumber: Int): ListContainer<Comment>
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestCommentServiceImpl : CommentService {
|
class TestCommentServiceImpl : CommentService {
|
||||||
private val mockData = generateMockComments(100)
|
override suspend fun getComments(pageNumber: Int, postId: Int?): ListContainer<Comment> {
|
||||||
override suspend fun getComments(pageNumber: Int): ListContainer<Comment> {
|
var rawList = TestDatabase.comment
|
||||||
val from = pageNumber * DataBatchSize
|
if (postId != null) {
|
||||||
val to = (pageNumber + 1) * DataBatchSize
|
rawList = rawList.filter { it.postId == postId }
|
||||||
val currentSublist = mockData.subList(from, to)
|
}
|
||||||
|
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(
|
return ListContainer(
|
||||||
total = mockData.size,
|
total = rawList.size,
|
||||||
page = pageNumber,
|
page = pageNumber,
|
||||||
pageSize = DataBatchSize,
|
pageSize = DataBatchSize,
|
||||||
list = currentSublist
|
list = currentSublist
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateMockComments(count: Int): List<Comment> {
|
override suspend fun createComment(postId: Int, content: String, authorId: Int): Comment {
|
||||||
return (0 until count).map {
|
var author = TestDatabase.accountData.find { it.id == authorId }
|
||||||
Comment(
|
if (author == null) {
|
||||||
name = "User $it",
|
author = TestDatabase.accountData.random()
|
||||||
comment = "This is comment $it",
|
|
||||||
date = "2023-02-02 11:23",
|
|
||||||
likes = Random.nextInt(0, 100),
|
|
||||||
replies = generateMockReplies()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
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> {
|
override suspend fun likeComment(commentId: Int) {
|
||||||
val replyCount = Random.nextInt(0, 6)
|
TestDatabase.comment = TestDatabase.comment.map {
|
||||||
return (0 until replyCount).map {
|
if (it.id == commentId) {
|
||||||
Comment(
|
it.copy(likes = it.likes + 1)
|
||||||
name = "Reply User $it",
|
} else {
|
||||||
comment = "This is reply $it",
|
it
|
||||||
date = "2023-02-02 11:23",
|
}
|
||||||
likes = Random.nextInt(0, 100),
|
|
||||||
replies = emptyList()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -2,19 +2,34 @@ package com.aiosman.riderpro.data
|
|||||||
|
|
||||||
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.model.MomentItem
|
import com.aiosman.riderpro.model.MomentItem
|
||||||
import com.aiosman.riderpro.test.TestDatabase
|
import com.aiosman.riderpro.test.TestDatabase
|
||||||
import java.io.IOException
|
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(
|
class MomentPagingSource(
|
||||||
private val remoteDataSource: MomentRemoteDataSource,
|
private val remoteDataSource: MomentRemoteDataSource,
|
||||||
|
private val author: Int? = null,
|
||||||
|
private val timelineId: Int? = null
|
||||||
) : PagingSource<Int, MomentItem>() {
|
) : PagingSource<Int, MomentItem>() {
|
||||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MomentItem> {
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MomentItem> {
|
||||||
return try {
|
return try {
|
||||||
val currentPage = params.key ?: 1
|
val currentPage = params.key ?: 1
|
||||||
val moments = remoteDataSource.getMoments(
|
val moments = remoteDataSource.getMoments(
|
||||||
pageNumber = currentPage
|
pageNumber = currentPage,
|
||||||
|
author = author,
|
||||||
|
timelineId = timelineId
|
||||||
)
|
)
|
||||||
|
|
||||||
LoadResult.Page(
|
LoadResult.Page(
|
||||||
@@ -36,63 +51,88 @@ class MomentPagingSource(
|
|||||||
class MomentRemoteDataSource(
|
class MomentRemoteDataSource(
|
||||||
private val momentService: MomentService,
|
private val momentService: MomentService,
|
||||||
) {
|
) {
|
||||||
suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem> {
|
suspend fun getMoments(
|
||||||
return momentService.getMoments(pageNumber)
|
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 {
|
class TestMomentServiceImpl() : MomentService {
|
||||||
var imageList = listOf(
|
val testMomentBackend = TestMomentBackend()
|
||||||
"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",
|
override suspend fun getMoments(
|
||||||
"https://img.freepik.com/free-photo/marketing-strategy-planning-strategy-concept_53876-42950.jpg"
|
pageNumber: Int,
|
||||||
)
|
author: Int?,
|
||||||
var mockData = TestDatabase.momentData
|
timelineId: Int?
|
||||||
val testMomentBackend = TestMomentBackend(mockData)
|
): ListContainer<MomentItem> {
|
||||||
override suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem> {
|
return testMomentBackend.fetchMomentItems(pageNumber, author, timelineId)
|
||||||
return testMomentBackend.fetchMomentItems(pageNumber)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMomentById(id: Int): MomentItem {
|
override suspend fun getMomentById(id: Int): MomentItem {
|
||||||
return mockData[id]
|
return testMomentBackend.getMomentById(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun likeMoment(id: Int) {
|
override suspend fun likeMoment(id: Int) {
|
||||||
// mockData = mockData.map {
|
testMomentBackend.likeMoment(id)
|
||||||
// if (it.id == id) {
|
|
||||||
// it.copy(likeCount = it.likeCount + 1)
|
|
||||||
// } else {
|
|
||||||
// it
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// mockData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestMomentBackend(
|
class TestMomentBackend(
|
||||||
private val mockData: List<MomentItem>,
|
|
||||||
private val loadDelay: Long = 500,
|
private val loadDelay: Long = 500,
|
||||||
) {
|
) {
|
||||||
val DataBatchSize = 5
|
val DataBatchSize = 5
|
||||||
suspend fun fetchMomentItems(pageNumber: Int): ListContainer<MomentItem> {
|
suspend fun fetchMomentItems(
|
||||||
val from = pageNumber * DataBatchSize
|
pageNumber: Int,
|
||||||
val to = (pageNumber + 1) * DataBatchSize
|
author: Int? = null,
|
||||||
val currentSublist = mockData.subList(from, to)
|
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
|
// delay
|
||||||
kotlinx.coroutines.delay(loadDelay)
|
kotlinx.coroutines.delay(loadDelay)
|
||||||
return ListContainer(
|
return ListContainer(
|
||||||
total = mockData.size,
|
total = rawList.size,
|
||||||
page = pageNumber,
|
page = pageNumber,
|
||||||
pageSize = DataBatchSize,
|
pageSize = DataBatchSize,
|
||||||
list = currentSublist
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,18 +2,24 @@ package com.aiosman.riderpro.test
|
|||||||
|
|
||||||
import com.aiosman.riderpro.R
|
import com.aiosman.riderpro.R
|
||||||
import com.aiosman.riderpro.data.AccountProfile
|
import com.aiosman.riderpro.data.AccountProfile
|
||||||
|
import com.aiosman.riderpro.data.Comment
|
||||||
import com.aiosman.riderpro.model.MomentItem
|
import com.aiosman.riderpro.model.MomentItem
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
import io.github.serpro69.kfaker.faker
|
import io.github.serpro69.kfaker.faker
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
object TestDatabase {
|
object TestDatabase {
|
||||||
var momentData = emptyList<MomentItem>()
|
var momentData = emptyList<MomentItem>()
|
||||||
var accountData = emptyList<AccountProfile>()
|
var accountData = emptyList<AccountProfile>()
|
||||||
|
var comment = emptyList<Comment>()
|
||||||
|
var commentIdCounter = 0
|
||||||
|
var selfId = 1
|
||||||
var imageList = listOf(
|
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/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/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://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/02/27/00/89/240_F_227008949_5O7yXuEqTwUgs3BGqdcvrNutM5MSxs1t.jpg",
|
||||||
|
|
||||||
"https://t4.ftcdn.net/jpg/01/86/86/49/240_F_186864971_NixcoDg1zBjjN7soUNhpEVraI4vdzOFD.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://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",
|
"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"
|
"https://t3.ftcdn.net/jpg/02/65/43/04/240_F_265430460_DIHqnrziar7WL2rmW0qbDO07TbxjlPQo.jpg"
|
||||||
)
|
)
|
||||||
var followList = emptyList<Pair<Int, Int>>()
|
var followList = emptyList<Pair<Int, Int>>()
|
||||||
|
var likeCommentList = emptyList<Pair<Int, Int>>()
|
||||||
init {
|
init {
|
||||||
val faker = faker {
|
val faker = faker {
|
||||||
this.fakerConfig {
|
this.fakerConfig {
|
||||||
locale = "en"
|
locale = "en"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
accountData = (0..300).toList().mapIndexed { idx, _ ->
|
accountData = (0..100).toList().mapIndexed { idx, _ ->
|
||||||
AccountProfile(
|
AccountProfile(
|
||||||
id = idx,
|
id = idx,
|
||||||
followerCount = 0,
|
followerCount = 0,
|
||||||
@@ -52,7 +58,7 @@ object TestDatabase {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
// make a random follow rel
|
// make a random follow rel
|
||||||
for (i in 0..10000) {
|
for (i in 0..500) {
|
||||||
var person1 = accountData.random()
|
var person1 = accountData.random()
|
||||||
var persion2 = accountData.random()
|
var persion2 = accountData.random()
|
||||||
followList += Pair(person1.id, persion2.id)
|
followList += Pair(person1.id, persion2.id)
|
||||||
@@ -66,11 +72,34 @@ object TestDatabase {
|
|||||||
it
|
it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
momentData = (0..300).toList().mapIndexed { idx, _ ->
|
momentData = (0..200).toList().mapIndexed { idx, _ ->
|
||||||
val person = accountData.random()
|
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(
|
MomentItem(
|
||||||
id = idx,
|
id = idx,
|
||||||
avatar = person.avatar,
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,7 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
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
|
||||||
@@ -35,30 +36,54 @@ 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.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.paging.Pager
|
import androidx.paging.Pager
|
||||||
import androidx.paging.PagingConfig
|
import androidx.paging.PagingConfig
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
|
import androidx.paging.cachedIn
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
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
|
import com.aiosman.riderpro.data.Comment
|
||||||
import com.aiosman.riderpro.data.CommentPagingSource
|
import com.aiosman.riderpro.data.CommentPagingSource
|
||||||
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
||||||
|
import com.aiosman.riderpro.data.CommentService
|
||||||
import com.aiosman.riderpro.data.TestCommentServiceImpl
|
import com.aiosman.riderpro.data.TestCommentServiceImpl
|
||||||
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import kotlinx.coroutines.flow.Flow
|
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
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun CommentModalContent(onDismiss: () -> Unit = {}) {
|
fun CommentModalContent(postId: Int? = null, onDismiss: () -> Unit = {}) {
|
||||||
var commentSource = CommentPagingSource(
|
val model = viewModel<CommentModalViewModel>(
|
||||||
CommentRemoteDataSource(TestCommentServiceImpl())
|
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 }
|
val scope = rememberCoroutineScope()
|
||||||
).flow
|
val comments = model.commentsFlow.collectAsLazyPagingItems()
|
||||||
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) }
|
||||||
@@ -70,7 +95,14 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
|
|||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var commentText by remember { mutableStateOf("") }
|
||||||
|
suspend fun sendComment() {
|
||||||
|
if (commentText.isNotEmpty()) {
|
||||||
|
model.commentService.createComment(postId!!, commentText, 1)
|
||||||
|
commentText = ""
|
||||||
|
}
|
||||||
|
comments.refresh()
|
||||||
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
) {
|
) {
|
||||||
@@ -97,8 +129,13 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
|
|||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
) {
|
) {
|
||||||
|
CommentsSection(lazyPagingItems = comments, onLike = {
|
||||||
CommentsSection(lazyPagingItems = comments) {
|
comment: Comment ->
|
||||||
|
scope.launch {
|
||||||
|
model.commentService.likeComment(comment.id)
|
||||||
|
comments.refresh()
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,8 +164,8 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
|
|||||||
|
|
||||||
) {
|
) {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = "",
|
value = commentText,
|
||||||
onValueChange = { },
|
onValueChange = { text -> commentText = text },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
textStyle = TextStyle(
|
textStyle = TextStyle(
|
||||||
@@ -144,7 +181,11 @@ fun CommentModalContent(onDismiss: () -> Unit = {}) {
|
|||||||
contentDescription = "Send",
|
contentDescription = "Send",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(32.dp)
|
.size(32.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
scope.launch {
|
||||||
|
sendComment()
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ fun MomentsList() {
|
|||||||
MomentCard(momentItem = momentItem, onLikeClick = {
|
MomentCard(momentItem = momentItem, onLikeClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
model.likeMoment(momentItem.id)
|
model.likeMoment(momentItem.id)
|
||||||
moments.refresh()
|
// moments.refresh()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ fun MomentContentGroup(
|
|||||||
) {
|
) {
|
||||||
val displayImageUrl = momentItem.images.firstOrNull()
|
val displayImageUrl = momentItem.images.firstOrNull()
|
||||||
Text(
|
Text(
|
||||||
text = momentItem.momentTextContent,
|
text = "${momentItem.id} ${momentItem.momentTextContent}",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.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),
|
||||||
@@ -323,7 +323,7 @@ fun MomentBottomOperateRowGroup(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
systemUiController.setNavigationBarColor(Color(0xfff7f7f7))
|
systemUiController.setNavigationBarColor(Color(0xfff7f7f7))
|
||||||
CommentModalContent() {
|
CommentModalContent(postId = momentItem.id) {
|
||||||
systemUiController.setNavigationBarColor(Color.Black)
|
systemUiController.setNavigationBarColor(Color.Black)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,57 @@
|
|||||||
package com.aiosman.riderpro.ui.index.tabs.moment
|
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.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.Pager
|
import androidx.paging.Pager
|
||||||
import androidx.paging.PagingConfig
|
import androidx.paging.PagingConfig
|
||||||
import androidx.paging.PagingData
|
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.MomentPagingSource
|
||||||
import com.aiosman.riderpro.data.MomentRemoteDataSource
|
import com.aiosman.riderpro.data.MomentRemoteDataSource
|
||||||
import com.aiosman.riderpro.data.MomentService
|
import com.aiosman.riderpro.data.MomentService
|
||||||
|
import com.aiosman.riderpro.data.TestAccountServiceImpl
|
||||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||||
import com.aiosman.riderpro.model.MomentItem
|
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() {
|
object MomentViewModel : ViewModel() {
|
||||||
val momentService: MomentService = TestMomentServiceImpl()
|
private val momentService: MomentService = TestMomentServiceImpl()
|
||||||
var momentListPagingSource = MomentPagingSource(
|
private val _momentsFlow = MutableStateFlow<PagingData<MomentItem>>(PagingData.empty())
|
||||||
MomentRemoteDataSource(momentService)
|
val momentsFlow = _momentsFlow.asStateFlow()
|
||||||
)
|
val accountService: AccountService = TestAccountServiceImpl()
|
||||||
var momentsFlow: Flow<PagingData<MomentItem>> = Pager(
|
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
init {
|
||||||
pagingSourceFactory = {
|
viewModelScope.launch {
|
||||||
MomentPagingSource(
|
val profile = accountService.getMyAccountProfile()
|
||||||
MomentRemoteDataSource(momentService)
|
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) {
|
suspend fun likeMoment(id: Int) {
|
||||||
momentService.likeMoment(id)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -18,18 +18,20 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
object MyProfileViewModel {
|
object MyProfileViewModel {
|
||||||
val service: AccountService = TestAccountServiceImpl()
|
val service: AccountService = TestAccountServiceImpl()
|
||||||
var profile by mutableStateOf<AccountProfile?>(null)
|
var profile by mutableStateOf<AccountProfile?>(null)
|
||||||
|
var momentsFlow by mutableStateOf<Flow<PagingData<MomentItem>>?>(null)
|
||||||
suspend fun loadProfile() {
|
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 followerCount get() = profile?.followerCount ?: 0
|
||||||
val followingCount get() = profile?.followingCount ?: 0
|
val followingCount get() = profile?.followingCount ?: 0
|
||||||
val bio get() = profile?.bio ?: ""
|
val bio get() = profile?.bio ?: ""
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.layout.widthIn
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListScope
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -51,7 +49,7 @@ fun ProfilePage() {
|
|||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
model.loadProfile()
|
model.loadProfile()
|
||||||
}
|
}
|
||||||
val profile = model.momentsFlow.collectAsLazyPagingItems()
|
val moments = model.momentsFlow?.collectAsLazyPagingItems()
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -67,10 +65,13 @@ fun ProfilePage() {
|
|||||||
|
|
||||||
RidingStyle()
|
RidingStyle()
|
||||||
}
|
}
|
||||||
items(profile.itemCount) { idx ->
|
moments?.let {
|
||||||
val momentItem = profile[idx] ?: return@items
|
items(it.itemCount) { idx ->
|
||||||
MomentPostUnit(momentItem)
|
val momentItem = it[idx] ?: return@items
|
||||||
|
MomentPostUnit(momentItem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,7 +410,7 @@ fun MomentPostUnit(momentItem: MomentItem) {
|
|||||||
TimeGroup(momentItem.time)
|
TimeGroup(momentItem.time)
|
||||||
MomentCard(
|
MomentCard(
|
||||||
momentItem.momentTextContent,
|
momentItem.momentTextContent,
|
||||||
momentItem.momentPicture,
|
momentItem.images[0],
|
||||||
momentItem.likeCount.toString(),
|
momentItem.likeCount.toString(),
|
||||||
momentItem.commentCount.toString()
|
momentItem.commentCount.toString()
|
||||||
)
|
)
|
||||||
@@ -439,7 +440,7 @@ fun TimeGroup(time: String = "2024.06.08 12:23") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MomentCard(content: String, @DrawableRes picture: Int, like: String, comment: String) {
|
fun MomentCard(content: String, imageUrl: String, like: String, comment: String) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.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))
|
.border(width = 1.dp, color = Color(0f, 0f, 0f, 0.1f), shape = RoundedCornerShape(6.dp))
|
||||||
) {
|
) {
|
||||||
MomentCardTopContent(content)
|
MomentCardTopContent(content)
|
||||||
MomentCardPicture(picture)
|
MomentCardPicture(imageUrl)
|
||||||
MomentCardOperation(like, comment)
|
MomentCardOperation(like, comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,13 +469,15 @@ fun MomentCardTopContent(content: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MomentCardPicture(@DrawableRes drawable: Int) {
|
fun MomentCardPicture(imageUrl:String) {
|
||||||
Image(
|
AsyncImage(
|
||||||
|
imageUrl,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp), painter = painterResource(id = drawable), contentDescription = ""
|
.padding(16.dp),
|
||||||
|
contentDescription = "",
|
||||||
|
contentScale = ContentScale.FillWidth
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -66,11 +66,14 @@ import androidx.paging.compose.collectAsLazyPagingItems
|
|||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.R
|
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.Comment
|
||||||
import com.aiosman.riderpro.data.CommentPagingSource
|
import com.aiosman.riderpro.data.CommentPagingSource
|
||||||
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
||||||
import com.aiosman.riderpro.data.TestCommentServiceImpl
|
import com.aiosman.riderpro.data.TestCommentServiceImpl
|
||||||
import com.aiosman.riderpro.data.MomentService
|
import com.aiosman.riderpro.data.MomentService
|
||||||
|
import com.aiosman.riderpro.data.TestAccountServiceImpl
|
||||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||||
import com.aiosman.riderpro.model.MomentItem
|
import com.aiosman.riderpro.model.MomentItem
|
||||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||||
@@ -101,9 +104,14 @@ fun PostScreen(
|
|||||||
val scrollState = rememberLazyListState()
|
val scrollState = rememberLazyListState()
|
||||||
val uiController = rememberSystemUiController()
|
val uiController = rememberSystemUiController()
|
||||||
var moment by remember { mutableStateOf<MomentItem?>(null) }
|
var moment by remember { mutableStateOf<MomentItem?>(null) }
|
||||||
|
var accountProfile by remember { mutableStateOf<AccountProfile?>(null) }
|
||||||
|
var accountService: AccountService = TestAccountServiceImpl()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
uiController.setNavigationBarColor(Color.White)
|
uiController.setNavigationBarColor(Color.White)
|
||||||
moment = service.getMomentById(id.toInt())
|
moment = service.getMomentById(id.toInt())
|
||||||
|
moment?.let {
|
||||||
|
accountProfile = accountService.getAccountProfileById(it.authorId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
StatusBarMaskLayout {
|
StatusBarMaskLayout {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -115,7 +123,7 @@ fun PostScreen(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Header()
|
Header(accountProfile)
|
||||||
Column(modifier = Modifier.animateContentSize()) {
|
Column(modifier = Modifier.animateContentSize()) {
|
||||||
AnimatedVisibility(visible = showCollapseContent) {
|
AnimatedVisibility(visible = showCollapseContent) {
|
||||||
// collapse content
|
// collapse content
|
||||||
@@ -148,7 +156,7 @@ fun PostScreen(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|
||||||
) {
|
) {
|
||||||
CommentsSection(lazyPagingItems = lazyPagingItems, scrollState) {
|
CommentsSection(lazyPagingItems = lazyPagingItems, scrollState, onLike = {}) {
|
||||||
showCollapseContent = it
|
showCollapseContent = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +166,7 @@ fun PostScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Header() {
|
fun Header(accountProfile: AccountProfile?) {
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -177,15 +185,22 @@ fun Header() {
|
|||||||
|
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Image(
|
accountProfile?.let {
|
||||||
painter = painterResource(id = R.drawable.default_avatar), // Replace with your image resource
|
AsyncImage(
|
||||||
contentDescription = "Profile Picture",
|
accountProfile.avatar,
|
||||||
modifier = Modifier
|
contentDescription = "Profile Picture",
|
||||||
.size(40.dp)
|
modifier = Modifier
|
||||||
.clip(CircleShape)
|
.size(40.dp)
|
||||||
)
|
.clip(CircleShape),
|
||||||
|
contentScale = ContentScale.Crop
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Text(text = "Diego Morata", fontWeight = FontWeight.Bold)
|
accountProfile?.let {
|
||||||
|
Text(text = accountProfile.nickName, fontWeight = FontWeight.Bold)
|
||||||
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(20.dp)
|
.height(20.dp)
|
||||||
@@ -269,25 +284,23 @@ fun PostDetails(
|
|||||||
momentItem: MomentItem?
|
momentItem: MomentItem?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Text(
|
|
||||||
text = momentItem?.momentTextContent ?:"",
|
|
||||||
fontSize = 16.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
)
|
|
||||||
Text(text = "12-11 发布")
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
Text(text = "共231条评论")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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(
|
fun CommentsSection(
|
||||||
lazyPagingItems: LazyPagingItems<Comment>,
|
lazyPagingItems: LazyPagingItems<Comment>,
|
||||||
scrollState: LazyListState = rememberLazyListState(),
|
scrollState: LazyListState = rememberLazyListState(),
|
||||||
|
onLike: (Comment) -> Unit,
|
||||||
onWillCollapse: (Boolean) -> Unit
|
onWillCollapse: (Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@@ -305,7 +319,9 @@ fun CommentsSection(
|
|||||||
) {
|
) {
|
||||||
items(lazyPagingItems.itemCount) { idx ->
|
items(lazyPagingItems.itemCount) { idx ->
|
||||||
val item = lazyPagingItems[idx] ?: return@items
|
val item = lazyPagingItems[idx] ?: return@items
|
||||||
CommentItem(item)
|
CommentItem(item,onLike={
|
||||||
|
onLike(item)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,15 +339,16 @@ fun CommentsSection(
|
|||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommentItem(comment: Comment) {
|
fun CommentItem(comment: Comment,onLike:()->Unit = {}) {
|
||||||
Column {
|
Column {
|
||||||
Row(modifier = Modifier.padding(vertical = 8.dp)) {
|
Row(modifier = Modifier.padding(vertical = 8.dp)) {
|
||||||
Image(
|
AsyncImage(
|
||||||
painter = painterResource(id = R.drawable.default_avatar), // Replace with your image resource
|
comment.avatar,
|
||||||
contentDescription = "Comment Profile Picture",
|
contentDescription = "Comment Profile Picture",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(40.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape),
|
||||||
|
contentScale = ContentScale.Crop
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Column {
|
Column {
|
||||||
@@ -341,7 +358,9 @@ fun CommentItem(comment: Comment) {
|
|||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
IconButton(onClick = { /*TODO*/ }) {
|
IconButton(onClick = {
|
||||||
|
onLike()
|
||||||
|
}) {
|
||||||
Icon(Icons.Filled.Favorite, contentDescription = "Like")
|
Icon(Icons.Filled.Favorite, contentDescription = "Like")
|
||||||
}
|
}
|
||||||
Text(text = comment.likes.toString())
|
Text(text = comment.likes.toString())
|
||||||
|
|||||||
@@ -37,18 +37,22 @@ fun AccountProfile(id:String) {
|
|||||||
// val model = MyProfileViewModel
|
// val model = MyProfileViewModel
|
||||||
val userService: UserService = TestUserServiceImpl()
|
val userService: UserService = TestUserServiceImpl()
|
||||||
var userProfile by remember { mutableStateOf<AccountProfile?>(null) }
|
var userProfile by remember { mutableStateOf<AccountProfile?>(null) }
|
||||||
var momentListPagingSource = MomentPagingSource(
|
val momentService = TestMomentServiceImpl()
|
||||||
MomentRemoteDataSource(TestMomentServiceImpl())
|
var momentsFlow by remember { mutableStateOf<Flow<PagingData<MomentItem>>?>(null) }
|
||||||
)
|
|
||||||
val momentsFlow: Flow<PagingData<MomentItem>> = Pager(
|
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
|
||||||
pagingSourceFactory = { momentListPagingSource }
|
|
||||||
).flow
|
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
userProfile = userService.getUserProfile(id)
|
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()
|
val systemUiController = rememberSystemUiController()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
systemUiController.setNavigationBarColor(
|
systemUiController.setNavigationBarColor(
|
||||||
@@ -70,13 +74,14 @@ fun AccountProfile(id:String) {
|
|||||||
CarGroup()
|
CarGroup()
|
||||||
userProfile?.let {
|
userProfile?.let {
|
||||||
UserInformation(isSelf = false, accountProfile = it)
|
UserInformation(isSelf = false, accountProfile = it)
|
||||||
|
|
||||||
}
|
}
|
||||||
RidingStyle()
|
RidingStyle()
|
||||||
}
|
}
|
||||||
items(items.itemCount) { idx ->
|
if (items != null) {
|
||||||
val momentItem = items[idx] ?: return@items
|
items(items.itemCount) { idx ->
|
||||||
MomentPostUnit(momentItem)
|
val momentItem = items[idx] ?: return@items
|
||||||
|
MomentPostUnit(momentItem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user