283 lines
8.2 KiB
Kotlin
283 lines
8.2 KiB
Kotlin
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.data.api.ApiClient
|
|
import com.aiosman.riderpro.model.MomentEntity
|
|
import com.aiosman.riderpro.model.MomentImageEntity
|
|
import com.aiosman.riderpro.test.TestDatabase
|
|
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 {
|
|
val avatar = ApiClient.BASE_SERVER + user.avatar + "?token=${AppStore.token}"
|
|
return MomentEntity(
|
|
id = id.toInt(),
|
|
avatar = ApiClient.BASE_SERVER + user.avatar + "?token=${AppStore.token}",
|
|
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 {
|
|
MomentImageEntity(
|
|
url = ApiClient.BASE_SERVER + it.url + "?token=${AppStore.token}",
|
|
thumbnail = ApiClient.BASE_SERVER + it.thumbnail + "?token=${AppStore.token}",
|
|
id = it.id
|
|
)
|
|
},
|
|
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): MomentEntity
|
|
suspend fun likeMoment(id: Int)
|
|
suspend fun dislikeMoment(id: Int)
|
|
suspend fun getMoments(
|
|
pageNumber: Int,
|
|
author: Int? = null,
|
|
timelineId: Int? = null,
|
|
contentSearch: String? = null
|
|
): ListContainer<MomentEntity>
|
|
|
|
suspend fun createMoment(
|
|
content: String,
|
|
authorId: Int,
|
|
images: List<UploadImage>,
|
|
relPostId: Int? = null
|
|
): MomentEntity
|
|
|
|
suspend fun favoriteMoment(id: Int)
|
|
suspend fun unfavoriteMoment(id: Int)
|
|
}
|
|
|
|
|
|
class MomentPagingSource(
|
|
private val remoteDataSource: MomentRemoteDataSource,
|
|
private val author: Int? = null,
|
|
private val timelineId: Int? = null,
|
|
private val contentSearch: String? = null
|
|
) : PagingSource<Int, MomentEntity>() {
|
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MomentEntity> {
|
|
return try {
|
|
val currentPage = params.key ?: 1
|
|
val moments = remoteDataSource.getMoments(
|
|
pageNumber = currentPage,
|
|
author = author,
|
|
timelineId = timelineId,
|
|
contentSearch = contentSearch
|
|
)
|
|
|
|
LoadResult.Page(
|
|
data = moments.list,
|
|
prevKey = if (currentPage == 1) null else currentPage - 1,
|
|
nextKey = if (moments.list.isEmpty()) null else moments.page + 1
|
|
)
|
|
} catch (exception: IOException) {
|
|
return LoadResult.Error(exception)
|
|
}
|
|
}
|
|
|
|
override fun getRefreshKey(state: PagingState<Int, MomentEntity>): Int? {
|
|
return state.anchorPosition
|
|
}
|
|
|
|
}
|
|
|
|
class MomentRemoteDataSource(
|
|
private val momentService: MomentService,
|
|
) {
|
|
suspend fun getMoments(
|
|
pageNumber: Int,
|
|
author: Int?,
|
|
timelineId: Int?,
|
|
contentSearch: String?
|
|
): ListContainer<MomentEntity> {
|
|
return momentService.getMoments(pageNumber, author, timelineId, contentSearch)
|
|
}
|
|
}
|
|
|
|
|
|
class TestMomentServiceImpl() : MomentService {
|
|
val testMomentBackend = TestMomentBackend()
|
|
|
|
override suspend fun getMoments(
|
|
pageNumber: Int,
|
|
author: Int?,
|
|
timelineId: Int?,
|
|
contentSearch: String?
|
|
): ListContainer<MomentEntity> {
|
|
return testMomentBackend.fetchMomentItems(pageNumber, author, timelineId, contentSearch)
|
|
}
|
|
|
|
override suspend fun getMomentById(id: Int): MomentEntity {
|
|
return testMomentBackend.getMomentById(id)
|
|
}
|
|
|
|
|
|
override suspend fun likeMoment(id: Int) {
|
|
testMomentBackend.likeMoment(id)
|
|
}
|
|
|
|
override suspend fun dislikeMoment(id: Int) {
|
|
testMomentBackend.dislikeMoment(id)
|
|
}
|
|
|
|
override suspend fun createMoment(
|
|
content: String,
|
|
authorId: Int,
|
|
images: List<UploadImage>,
|
|
relPostId: Int?
|
|
): 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)
|
|
}
|
|
|
|
}
|
|
|
|
class TestMomentBackend(
|
|
private val loadDelay: Long = 500,
|
|
) {
|
|
val DataBatchSize = 5
|
|
suspend fun fetchMomentItems(
|
|
pageNumber: Int,
|
|
author: Int? = null,
|
|
timelineId: Int?,
|
|
contentSearch: String?
|
|
): ListContainer<MomentEntity> {
|
|
val resp = ApiClient.api.getPosts(
|
|
pageSize = DataBatchSize,
|
|
page = pageNumber,
|
|
timelineId = timelineId,
|
|
authorId = author,
|
|
contentSearch = contentSearch
|
|
)
|
|
val body = resp.body() ?: throw ServiceException("Failed to get moments")
|
|
return ListContainer(
|
|
total = body.total,
|
|
page = pageNumber,
|
|
pageSize = DataBatchSize,
|
|
list = body.list.map { it.toMomentItem() }
|
|
)
|
|
}
|
|
|
|
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) {
|
|
ApiClient.api.likePost(id)
|
|
}
|
|
|
|
suspend fun dislikeMoment(id: Int) {
|
|
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<UploadImage>,
|
|
relPostId: Int?
|
|
): MomentEntity {
|
|
val textContent = content.toRequestBody("text/plain".toMediaTypeOrNull())
|
|
val imageList = imageUriList.map { item ->
|
|
val file = item.file
|
|
createMultipartBody(file, "image")
|
|
}
|
|
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)
|
|
}
|
|
|
|
} |