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

View File

@@ -2,28 +2,109 @@ package com.aiosman.riderpro.data
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.R
import com.aiosman.riderpro.model.MomentItem
import com.aiosman.riderpro.data.api.ApiClient
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.test.TestDatabase
import java.io.IOException
import kotlin.math.min
import com.google.gson.annotations.SerializedName
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.net.URL
data class Moment(
@SerializedName("id")
val id: Long,
@SerializedName("textContent")
val textContent: String,
@SerializedName("images")
val images: List<Image>,
@SerializedName("user")
val user: User,
@SerializedName("likeCount")
val likeCount: Long,
@SerializedName("isLiked")
val isLiked: Boolean,
@SerializedName("favoriteCount")
val favoriteCount: Long,
@SerializedName("isFavorite")
val isFavorite: Boolean,
@SerializedName("shareCount")
val isCommented: Boolean,
@SerializedName("commentCount")
val commentCount: Long,
@SerializedName("time")
val time: String
) {
fun toMomentItem(): MomentEntity {
return MomentEntity(
id = id.toInt(),
avatar = ApiClient.BASE_SERVER + user.avatar,
nickname = user.nickName,
location = "Worldwide",
time = time,
followStatus = false,
momentTextContent = textContent,
momentPicture = R.drawable.default_moment_img,
likeCount = likeCount.toInt(),
commentCount = commentCount.toInt(),
shareCount = 0,
favoriteCount = favoriteCount.toInt(),
images = images.map { ApiClient.BASE_SERVER + it.url + "?token=${AppStore.token}" },
authorId = user.id.toInt(),
liked = isLiked,
isFavorite = isFavorite
)
}
}
data class Image(
@SerializedName("id")
val id: Long,
@SerializedName("url")
val url: String,
@SerializedName("thumbnail")
val thumbnail: String
)
data class User(
@SerializedName("id")
val id: Long,
@SerializedName("nickName")
val nickName: String,
@SerializedName("avatar")
val avatar: String
)
data class UploadImage(
val file: File,
val filename: String,
val url: String,
val ext: String
)
interface MomentService {
suspend fun getMomentById(id: Int): MomentItem
suspend fun getMomentById(id: Int): MomentEntity
suspend fun likeMoment(id: Int)
suspend fun dislikeMoment(id: Int)
suspend fun getMoments(
pageNumber: Int,
author: Int? = null,
timelineId: Int? = null
): ListContainer<MomentItem>
): ListContainer<MomentEntity>
suspend fun createMoment(
content: String,
authorId: Int,
imageUriList: List<String>,
images: List<UploadImage>,
relPostId: Int? = null
): MomentItem
): MomentEntity
suspend fun favoriteMoment(id: Int)
suspend fun unfavoriteMoment(id: Int)
}
@@ -31,8 +112,8 @@ 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> {
) : PagingSource<Int, MomentEntity>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MomentEntity> {
return try {
val currentPage = params.key ?: 1
val moments = remoteDataSource.getMoments(
@@ -51,7 +132,7 @@ class MomentPagingSource(
}
}
override fun getRefreshKey(state: PagingState<Int, MomentItem>): Int? {
override fun getRefreshKey(state: PagingState<Int, MomentEntity>): Int? {
return state.anchorPosition
}
@@ -64,7 +145,7 @@ class MomentRemoteDataSource(
pageNumber: Int,
author: Int?,
timelineId: Int?
): ListContainer<MomentItem> {
): ListContainer<MomentEntity> {
return momentService.getMoments(pageNumber, author, timelineId)
}
}
@@ -77,11 +158,11 @@ class TestMomentServiceImpl() : MomentService {
pageNumber: Int,
author: Int?,
timelineId: Int?
): ListContainer<MomentItem> {
): ListContainer<MomentEntity> {
return testMomentBackend.fetchMomentItems(pageNumber, author, timelineId)
}
override suspend fun getMomentById(id: Int): MomentItem {
override suspend fun getMomentById(id: Int): MomentEntity {
return testMomentBackend.getMomentById(id)
}
@@ -97,10 +178,18 @@ class TestMomentServiceImpl() : MomentService {
override suspend fun createMoment(
content: String,
authorId: Int,
imageUriList: List<String>,
images: List<UploadImage>,
relPostId: Int?
): MomentItem {
return testMomentBackend.createMoment(content, authorId, imageUriList, relPostId)
): MomentEntity {
return testMomentBackend.createMoment(content, authorId, images, relPostId)
}
override suspend fun favoriteMoment(id: Int) {
testMomentBackend.favoriteMoment(id)
}
override suspend fun unfavoriteMoment(id: Int) {
testMomentBackend.unfavoriteMoment(id)
}
}
@@ -113,110 +202,63 @@ class TestMomentBackend(
pageNumber: Int,
author: Int? = null,
timelineId: Int?
): ListContainer<MomentItem> {
var rawList = TestDatabase.momentData
rawList = rawList.sortedBy { it.id }.reversed()
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 || it.authorId == 1 }
}
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))
currentSublist.forEach {
val myLikeIdList =
TestDatabase.likeMomentList.filter { it.second == 1 }.map { it.first }
if (myLikeIdList.contains(it.id)) {
it.liked = true
}
if (it.relPostId != null) {
it.relMoment = rawList.first { it1 -> it1.id == it.relPostId }
}
}
// delay
kotlinx.coroutines.delay(loadDelay)
): ListContainer<MomentEntity> {
val resp = ApiClient.api.getPosts(
pageSize = DataBatchSize,
page = pageNumber,
timelineId = timelineId,
authorId = author
)
val body = resp.body() ?: throw ServiceException("Failed to get moments")
return ListContainer(
total = rawList.size,
total = body.total,
page = pageNumber,
pageSize = DataBatchSize,
list = currentSublist
list = body.list.map { it.toMomentItem() }
)
}
suspend fun getMomentById(id: Int): MomentItem {
var moment = TestDatabase.momentData.first {
it.id == id
}
val isLike = TestDatabase.likeMomentList.any {
it.first == id && it.second == 1
}
moment = moment.copy(liked = isLike)
return moment
suspend fun getMomentById(id: Int): MomentEntity {
var resp = ApiClient.api.getPost(id)
var body = resp.body()?.data ?: throw ServiceException("Failed to get moment")
return body.toMomentItem()
}
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)
TestDatabase.likeMomentList += Pair(id, 1)
ApiClient.api.likePost(id)
}
suspend fun dislikeMoment(id: Int) {
val oldMoment = TestDatabase.momentData.first {
it.id == id
}
val newMoment = oldMoment.copy(likeCount = oldMoment.likeCount - 1)
TestDatabase.updateMomentById(id, newMoment)
TestDatabase.likeMomentList = TestDatabase.likeMomentList.filter {
it.first != id
}
ApiClient.api.dislikePost(id)
}
fun createMultipartBody(file: File, name: String): MultipartBody.Part {
val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), file)
return MultipartBody.Part.createFormData(name, file.name, requestFile)
}
suspend fun createMoment(
content: String,
authorId: Int,
imageUriList: List<String>,
imageUriList: List<UploadImage>,
relPostId: Int?
): MomentItem {
TestDatabase.momentIdCounter += 1
val person = TestDatabase.accountData.first {
it.id == authorId
): MomentEntity {
val textContent = content.toRequestBody("text/plain".toMediaTypeOrNull())
val imageList = imageUriList.map { item ->
val file = item.file
createMultipartBody(file, "image")
}
val newMoment = MomentItem(
id = TestDatabase.momentIdCounter,
avatar = person.avatar,
nickname = person.nickName,
location = person.country,
time = "2023.02.02 11:23",
followStatus = false,
momentTextContent = content,
momentPicture = R.drawable.default_moment_img,
likeCount = 0,
commentCount = 0,
shareCount = 0,
favoriteCount = 0,
images = imageUriList,
authorId = person.id,
relPostId = relPostId
)
TestDatabase.momentData += newMoment
return newMoment
val response = ApiClient.api.createPost(imageList, textContent = textContent)
val body = response.body()?.data ?: throw ServiceException("Failed to create moment")
return body.toMomentItem()
}
suspend fun favoriteMoment(id: Int) {
ApiClient.api.favoritePost(id)
}
suspend fun unfavoriteMoment(id: Int) {
ApiClient.api.unfavoritePost(id)
}
}