2024-07-29 00:01:09 +08:00
|
|
|
package com.aiosman.riderpro.data
|
|
|
|
|
|
2024-08-17 17:40:21 +08:00
|
|
|
import androidx.paging.PagingSource
|
|
|
|
|
import androidx.paging.PagingState
|
2024-08-11 21:17:02 +08:00
|
|
|
import com.aiosman.riderpro.AppStore
|
2024-08-11 17:15:17 +08:00
|
|
|
import com.aiosman.riderpro.data.api.ApiClient
|
2024-08-13 22:32:27 +08:00
|
|
|
import com.aiosman.riderpro.data.api.ChangePasswordRequestBody
|
2024-08-11 17:15:17 +08:00
|
|
|
import com.aiosman.riderpro.data.api.LoginUserRequestBody
|
|
|
|
|
import com.aiosman.riderpro.data.api.RegisterRequestBody
|
2024-08-20 19:48:12 +08:00
|
|
|
import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody
|
2024-07-29 16:50:07 +08:00
|
|
|
import com.aiosman.riderpro.test.TestDatabase
|
2024-08-20 19:48:12 +08:00
|
|
|
import com.google.gson.annotations.SerializedName
|
2024-08-11 21:17:02 +08:00
|
|
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
|
|
|
|
import okhttp3.MultipartBody
|
|
|
|
|
import okhttp3.RequestBody
|
|
|
|
|
import okhttp3.RequestBody.Companion.asRequestBody
|
|
|
|
|
import okhttp3.RequestBody.Companion.toRequestBody
|
|
|
|
|
import java.io.File
|
2024-08-17 17:40:21 +08:00
|
|
|
import java.io.IOException
|
2024-08-20 19:48:12 +08:00
|
|
|
import java.util.Date
|
2024-07-29 16:50:07 +08:00
|
|
|
|
2024-08-20 19:48:12 +08:00
|
|
|
data class AccountLikeEntity(
|
|
|
|
|
val post: NoticePostEntity,
|
|
|
|
|
val user: NoticeUserEntity,
|
|
|
|
|
val likeTime: Date,
|
|
|
|
|
)
|
|
|
|
|
data class AccountFavouriteEntity(
|
|
|
|
|
val post: NoticePostEntity,
|
|
|
|
|
val user: NoticeUserEntity,
|
|
|
|
|
val favoriteTime: Date,
|
|
|
|
|
)
|
2024-08-11 17:15:17 +08:00
|
|
|
data class AccountProfileEntity(
|
2024-07-29 00:01:09 +08:00
|
|
|
val id: Int,
|
|
|
|
|
val followerCount: Int,
|
|
|
|
|
val followingCount: Int,
|
|
|
|
|
val nickName: String,
|
|
|
|
|
val avatar: String,
|
|
|
|
|
val bio: String,
|
|
|
|
|
val country: String,
|
2024-08-11 17:15:17 +08:00
|
|
|
val isFollowing: Boolean
|
2024-07-29 00:01:09 +08:00
|
|
|
)
|
2024-08-11 21:17:02 +08:00
|
|
|
|
|
|
|
|
data class AccountProfile(
|
2024-08-11 17:15:17 +08:00
|
|
|
val id: Int,
|
|
|
|
|
val username: String,
|
|
|
|
|
val nickname: String,
|
|
|
|
|
val avatar: String,
|
|
|
|
|
val followingCount: Int,
|
|
|
|
|
val followerCount: Int,
|
|
|
|
|
val isFollowing: Boolean
|
|
|
|
|
) {
|
|
|
|
|
fun toAccountProfileEntity(): AccountProfileEntity {
|
|
|
|
|
return AccountProfileEntity(
|
|
|
|
|
id = id,
|
|
|
|
|
followerCount = followerCount,
|
|
|
|
|
followingCount = followingCount,
|
|
|
|
|
nickName = nickname,
|
2024-08-11 21:17:02 +08:00
|
|
|
avatar = ApiClient.BASE_SERVER + avatar + "?token=${AppStore.token}",
|
2024-08-11 17:15:17 +08:00
|
|
|
bio = "",
|
|
|
|
|
country = "Worldwide",
|
|
|
|
|
isFollowing = isFollowing
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-11 21:17:02 +08:00
|
|
|
|
2024-08-20 19:48:12 +08:00
|
|
|
data class NoticePostEntity(
|
|
|
|
|
val id: Int,
|
|
|
|
|
val textContent: String,
|
|
|
|
|
val images: List<Image>,
|
|
|
|
|
val time: Date,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
data class NoticePost(
|
|
|
|
|
@SerializedName("id")
|
|
|
|
|
val id: Int,
|
|
|
|
|
@SerializedName("textContent")
|
|
|
|
|
val textContent: String,
|
|
|
|
|
@SerializedName("images")
|
|
|
|
|
val images: List<Image>,
|
|
|
|
|
@SerializedName("time")
|
|
|
|
|
val time: String,
|
|
|
|
|
) {
|
|
|
|
|
fun toNoticePostEntity(): NoticePostEntity {
|
|
|
|
|
return NoticePostEntity(
|
|
|
|
|
id = id,
|
|
|
|
|
textContent = textContent,
|
|
|
|
|
images = images.map {
|
|
|
|
|
it.copy(
|
|
|
|
|
url = ApiClient.BASE_SERVER + it.url + "?token=${AppStore.token}",
|
|
|
|
|
thumbnail = ApiClient.BASE_SERVER + it.thumbnail + "?token=${AppStore.token}",
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
time = ApiClient.dateFromApiString(time)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data class NoticeUserEntity(
|
|
|
|
|
val id: Int,
|
|
|
|
|
val nickName: String,
|
|
|
|
|
val avatar: String,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
data class NoticeUser(
|
|
|
|
|
@SerializedName("id")
|
|
|
|
|
val id: Int,
|
|
|
|
|
@SerializedName("nickName")
|
|
|
|
|
val nickName: String,
|
|
|
|
|
@SerializedName("avatar")
|
|
|
|
|
val avatar: String,
|
|
|
|
|
) {
|
|
|
|
|
fun toNoticeUserEntity(): NoticeUserEntity {
|
|
|
|
|
return NoticeUserEntity(
|
|
|
|
|
id = id,
|
|
|
|
|
nickName = nickName,
|
|
|
|
|
avatar = ApiClient.BASE_SERVER + avatar + "?token=${AppStore.token}",
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data class AccountLike(
|
|
|
|
|
@SerializedName("isUnread")
|
|
|
|
|
val isUnread: Boolean,
|
|
|
|
|
@SerializedName("post")
|
|
|
|
|
val post: NoticePost,
|
|
|
|
|
@SerializedName("user")
|
|
|
|
|
val user: NoticeUser,
|
|
|
|
|
@SerializedName("likeTime")
|
|
|
|
|
val likeTime: String,
|
|
|
|
|
) {
|
|
|
|
|
fun toAccountLikeEntity(): AccountLikeEntity {
|
|
|
|
|
return AccountLikeEntity(
|
|
|
|
|
post = post.toNoticePostEntity(),
|
|
|
|
|
user = user.toNoticeUserEntity(),
|
|
|
|
|
likeTime = ApiClient.dateFromApiString(likeTime)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data class AccountFavourite(
|
|
|
|
|
@SerializedName("isUnread")
|
|
|
|
|
val isUnread: Boolean,
|
|
|
|
|
@SerializedName("post")
|
|
|
|
|
val post: NoticePost,
|
|
|
|
|
@SerializedName("user")
|
|
|
|
|
val user: NoticeUser,
|
|
|
|
|
@SerializedName("favoriteTime")
|
|
|
|
|
val favouriteTime: String,
|
|
|
|
|
) {
|
|
|
|
|
fun toAccountFavouriteEntity(): AccountFavouriteEntity {
|
|
|
|
|
return AccountFavouriteEntity(
|
|
|
|
|
post = post.toNoticePostEntity(),
|
|
|
|
|
user = user.toNoticeUserEntity(),
|
|
|
|
|
favoriteTime = ApiClient.dateFromApiString(favouriteTime)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data class AccountFollow(
|
|
|
|
|
@SerializedName("id")
|
|
|
|
|
val id: Int,
|
|
|
|
|
@SerializedName("username")
|
|
|
|
|
val username: String,
|
|
|
|
|
@SerializedName("nickname")
|
|
|
|
|
val nickname: String,
|
|
|
|
|
@SerializedName("avatar")
|
|
|
|
|
val avatar: String,
|
|
|
|
|
@SerializedName("isUnread")
|
|
|
|
|
val isUnread: Boolean,
|
|
|
|
|
@SerializedName("userId")
|
|
|
|
|
val userId: Int,
|
|
|
|
|
@SerializedName("isFollowing")
|
|
|
|
|
val isFollowing: Boolean,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
//{
|
|
|
|
|
// "likeCount": 0,
|
|
|
|
|
// "followCount": 0,
|
|
|
|
|
// "favoriteCount": 0
|
|
|
|
|
//}
|
|
|
|
|
data class AccountNotice(
|
|
|
|
|
@SerializedName("likeCount")
|
|
|
|
|
val likeCount: Int,
|
|
|
|
|
@SerializedName("followCount")
|
|
|
|
|
val followCount: Int,
|
|
|
|
|
@SerializedName("favoriteCount")
|
|
|
|
|
val favoriteCount: Int,
|
|
|
|
|
@SerializedName("commentCount")
|
|
|
|
|
val commentCount: Int,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LikeItemPagingSource(
|
|
|
|
|
private val accountService: AccountService,
|
|
|
|
|
) : PagingSource<Int, AccountLikeEntity>() {
|
|
|
|
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AccountLikeEntity> {
|
|
|
|
|
return try {
|
|
|
|
|
val currentPage = params.key ?: 1
|
|
|
|
|
val likes = accountService.getMyLikeNotice(
|
|
|
|
|
page = currentPage,
|
|
|
|
|
pageSize = 20,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
LoadResult.Page(
|
|
|
|
|
data = likes.list.map {
|
|
|
|
|
it.toAccountLikeEntity()
|
|
|
|
|
},
|
|
|
|
|
prevKey = if (currentPage == 1) null else currentPage - 1,
|
|
|
|
|
nextKey = if (likes.list.isEmpty()) null else likes.page + 1
|
|
|
|
|
)
|
|
|
|
|
} catch (exception: IOException) {
|
|
|
|
|
return LoadResult.Error(exception)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun getRefreshKey(state: PagingState<Int, AccountLikeEntity>): Int? {
|
|
|
|
|
return state.anchorPosition
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class FavoriteItemPagingSource(
|
|
|
|
|
private val accountService: AccountService,
|
|
|
|
|
) : PagingSource<Int, AccountFavouriteEntity>() {
|
|
|
|
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AccountFavouriteEntity> {
|
|
|
|
|
return try {
|
|
|
|
|
val currentPage = params.key ?: 1
|
|
|
|
|
val favouriteListContainer = accountService.getMyFavouriteNotice(
|
|
|
|
|
page = currentPage,
|
|
|
|
|
pageSize = 20,
|
|
|
|
|
)
|
|
|
|
|
LoadResult.Page(
|
|
|
|
|
data = favouriteListContainer.list.map {
|
|
|
|
|
it.toAccountFavouriteEntity()
|
|
|
|
|
},
|
|
|
|
|
prevKey = if (currentPage == 1) null else currentPage - 1,
|
|
|
|
|
nextKey = if (favouriteListContainer.list.isEmpty()) null else favouriteListContainer.page + 1
|
|
|
|
|
)
|
|
|
|
|
} catch (exception: IOException) {
|
|
|
|
|
return LoadResult.Error(exception)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun getRefreshKey(state: PagingState<Int, AccountFavouriteEntity>): Int? {
|
|
|
|
|
return state.anchorPosition
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class FollowItemPagingSource(
|
|
|
|
|
private val accountService: AccountService,
|
|
|
|
|
) : PagingSource<Int, AccountFollow>() {
|
|
|
|
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AccountFollow> {
|
|
|
|
|
return try {
|
|
|
|
|
val currentPage = params.key ?: 1
|
|
|
|
|
val followListContainer = accountService.getMyFollowNotice(
|
|
|
|
|
page = currentPage,
|
|
|
|
|
pageSize = 20,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
LoadResult.Page(
|
|
|
|
|
data = followListContainer.list.map {
|
|
|
|
|
it.copy(
|
|
|
|
|
avatar = ApiClient.BASE_SERVER + it.avatar + "?token=${AppStore.token}",
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
prevKey = if (currentPage == 1) null else currentPage - 1,
|
|
|
|
|
nextKey = if (followListContainer.list.isEmpty()) null else followListContainer.page + 1
|
|
|
|
|
)
|
|
|
|
|
} catch (exception: IOException) {
|
|
|
|
|
return LoadResult.Error(exception)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun getRefreshKey(state: PagingState<Int, AccountFollow>): Int? {
|
|
|
|
|
return state.anchorPosition
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-07-29 00:01:09 +08:00
|
|
|
interface AccountService {
|
2024-08-11 17:15:17 +08:00
|
|
|
suspend fun getMyAccountProfile(): AccountProfileEntity
|
|
|
|
|
suspend fun getAccountProfileById(id: Int): AccountProfileEntity
|
2024-07-31 14:50:55 +08:00
|
|
|
suspend fun getMyAccount(): UserAuth
|
|
|
|
|
suspend fun loginUserWithPassword(loginName: String, password: String): UserAuth
|
|
|
|
|
suspend fun logout()
|
|
|
|
|
suspend fun updateAvatar(uri: String)
|
2024-08-11 21:17:02 +08:00
|
|
|
suspend fun updateProfile(avatar: UploadImage?, nickName: String?, bio: String?)
|
2024-08-11 17:15:17 +08:00
|
|
|
suspend fun registerUserWithPassword(loginName: String, password: String)
|
2024-08-13 22:32:27 +08:00
|
|
|
suspend fun changeAccountPassword(oldPassword: String, newPassword: String)
|
2024-08-20 19:48:12 +08:00
|
|
|
suspend fun getMyLikeNotice(page: Int, pageSize: Int): ListContainer<AccountLike>
|
|
|
|
|
suspend fun getMyFollowNotice(page: Int, pageSize: Int): ListContainer<AccountFollow>
|
|
|
|
|
suspend fun getMyFavouriteNotice(page: Int, pageSize: Int): ListContainer<AccountFavourite>
|
|
|
|
|
suspend fun getMyNoticeInfo(): AccountNotice
|
|
|
|
|
suspend fun updateNotice(payload: UpdateNoticeRequestBody)
|
2024-07-29 00:01:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class TestAccountServiceImpl : AccountService {
|
2024-08-11 17:15:17 +08:00
|
|
|
override suspend fun getMyAccountProfile(): AccountProfileEntity {
|
|
|
|
|
val resp = ApiClient.api.getMyAccount()
|
|
|
|
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
|
|
|
|
return body.data.toAccountProfileEntity()
|
2024-07-29 16:50:07 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-11 17:15:17 +08:00
|
|
|
override suspend fun getAccountProfileById(id: Int): AccountProfileEntity {
|
|
|
|
|
val resp = ApiClient.api.getAccountProfileById(id)
|
|
|
|
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
|
|
|
|
return body.data.toAccountProfileEntity()
|
2024-07-29 00:01:09 +08:00
|
|
|
}
|
2024-07-31 14:50:55 +08:00
|
|
|
|
|
|
|
|
override suspend fun getMyAccount(): UserAuth {
|
2024-08-11 17:15:17 +08:00
|
|
|
val resp = ApiClient.api.checkToken()
|
|
|
|
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
|
|
|
|
return UserAuth(body.id)
|
2024-07-31 14:50:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override suspend fun loginUserWithPassword(loginName: String, password: String): UserAuth {
|
2024-08-11 17:15:17 +08:00
|
|
|
val resp = ApiClient.api.login(LoginUserRequestBody(loginName, password))
|
|
|
|
|
val body = resp.body() ?: throw ServiceException("Failed to login")
|
|
|
|
|
return UserAuth(0, body.token)
|
2024-07-31 14:50:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override suspend fun logout() {
|
|
|
|
|
// do nothing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override suspend fun updateAvatar(uri: String) {
|
|
|
|
|
TestDatabase.accountData = TestDatabase.accountData.map {
|
|
|
|
|
if (it.id == 1) {
|
|
|
|
|
it.copy(avatar = uri)
|
|
|
|
|
} else {
|
|
|
|
|
it
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-11 17:15:17 +08:00
|
|
|
|
2024-08-13 22:32:27 +08:00
|
|
|
fun createMultipartBody(file: File, filename: String, name: String): MultipartBody.Part {
|
2024-08-11 21:17:02 +08:00
|
|
|
val requestFile = file.asRequestBody("image/*".toMediaTypeOrNull())
|
|
|
|
|
return MultipartBody.Part.createFormData(name, filename, requestFile)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override suspend fun updateProfile(avatar: UploadImage?, nickName: String?, bio: String?) {
|
|
|
|
|
val nicknameField: RequestBody? = nickName?.toRequestBody("text/plain".toMediaTypeOrNull())
|
|
|
|
|
val avatarField: MultipartBody.Part? = avatar?.let {
|
2024-08-13 22:32:27 +08:00
|
|
|
createMultipartBody(it.file, it.filename, "avatar")
|
2024-07-31 14:50:55 +08:00
|
|
|
}
|
2024-08-11 21:17:02 +08:00
|
|
|
ApiClient.api.updateProfile(avatarField, nicknameField)
|
2024-07-31 14:50:55 +08:00
|
|
|
}
|
2024-08-11 17:15:17 +08:00
|
|
|
|
|
|
|
|
override suspend fun registerUserWithPassword(loginName: String, password: String) {
|
|
|
|
|
ApiClient.api.register(RegisterRequestBody(loginName, password))
|
|
|
|
|
}
|
2024-08-13 22:32:27 +08:00
|
|
|
|
|
|
|
|
override suspend fun changeAccountPassword(oldPassword: String, newPassword: String) {
|
|
|
|
|
ApiClient.api.changePassword(ChangePasswordRequestBody(oldPassword, newPassword))
|
|
|
|
|
}
|
2024-08-20 19:48:12 +08:00
|
|
|
|
|
|
|
|
override suspend fun getMyLikeNotice(page: Int, pageSize: Int): ListContainer<AccountLike> {
|
|
|
|
|
val resp = ApiClient.api.getMyLikeNotices(page, pageSize)
|
|
|
|
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
|
|
|
|
return body
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override suspend fun getMyFollowNotice(page: Int, pageSize: Int): ListContainer<AccountFollow> {
|
|
|
|
|
val resp = ApiClient.api.getMyFollowNotices(page, pageSize)
|
|
|
|
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
|
|
|
|
return body
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override suspend fun getMyFavouriteNotice(
|
|
|
|
|
page: Int,
|
|
|
|
|
pageSize: Int
|
|
|
|
|
): ListContainer<AccountFavourite> {
|
|
|
|
|
val resp = ApiClient.api.getMyFavouriteNotices(page, pageSize)
|
|
|
|
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
|
|
|
|
return body
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override suspend fun getMyNoticeInfo(): AccountNotice {
|
|
|
|
|
val resp = ApiClient.api.getMyNoticeInfo()
|
|
|
|
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
|
|
|
|
return body.data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override suspend fun updateNotice(payload: UpdateNoticeRequestBody) {
|
|
|
|
|
ApiClient.api.updateNoticeInfo(payload)
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-29 00:01:09 +08:00
|
|
|
}
|