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, @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 suspend fun createMoment( content: String, authorId: Int, images: List, 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() { override suspend fun load(params: LoadParams): LoadResult { 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? { return state.anchorPosition } } class MomentRemoteDataSource( private val momentService: MomentService, ) { suspend fun getMoments( pageNumber: Int, author: Int?, timelineId: Int?, contentSearch: String? ): ListContainer { 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 { 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, 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 { 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, 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) } }