package com.aiosman.riderpro.data import com.aiosman.riderpro.data.api.ApiClient import com.aiosman.riderpro.data.api.ChangePasswordRequestBody import com.aiosman.riderpro.data.api.GoogleRegisterRequestBody import com.aiosman.riderpro.data.api.LoginUserRequestBody import com.aiosman.riderpro.data.api.RegisterMessageChannelRequestBody import com.aiosman.riderpro.data.api.RegisterRequestBody import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody import com.aiosman.riderpro.entity.AccountFavouriteEntity import com.aiosman.riderpro.entity.AccountLikeEntity import com.aiosman.riderpro.entity.AccountProfileEntity import com.aiosman.riderpro.entity.NoticePostEntity import com.aiosman.riderpro.entity.NoticeUserEntity import com.google.gson.annotations.SerializedName 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 /** * 用户资料 */ data class AccountProfile( // 用户ID val id: Int, // 用户名 val username: String, // 昵称 val nickname: String, // 头像 val avatar: String, // 关注数 val followingCount: Int, // 粉丝数 val followerCount: Int, // 是否关注 val isFollowing: Boolean, // 个人简介 val bio: String, // 主页背景图 val banner: String?, ) { /** * 转换为Entity */ fun toAccountProfileEntity(): AccountProfileEntity { return AccountProfileEntity( id = id, followerCount = followerCount, followingCount = followingCount, nickName = nickname, avatar = "${ApiClient.BASE_SERVER}$avatar", bio = bio, country = "Worldwide", isFollowing = isFollowing, banner = banner.let { if (!it.isNullOrEmpty()) { return@let "${ApiClient.BASE_SERVER}$it" } null } ) } } /** * 消息关联资料 */ data class NoticePost( // 动态ID @SerializedName("id") val id: Int, // 动态内容 @SerializedName("textContent") // 动态图片 val textContent: String, // 动态图片 @SerializedName("images") val images: List, // 动态时间 @SerializedName("time") val time: String, ) { /** * 转换为Entity */ fun toNoticePostEntity(): NoticePostEntity { return NoticePostEntity( id = id, textContent = textContent, images = images.map { it.copy( url = "${ApiClient.BASE_SERVER}${it.url}", thumbnail = "${ApiClient.BASE_SERVER}${it.thumbnail}", ) }, time = ApiClient.dateFromApiString(time) ) } } /** * 消息关联用户 */ data class NoticeUser( // 用户ID @SerializedName("id") val id: Int, // 昵称 @SerializedName("nickName") val nickName: String, // 头像 @SerializedName("avatar") val avatar: String, ) { /** * 转换为Entity */ fun toNoticeUserEntity(): NoticeUserEntity { return NoticeUserEntity( id = id, nickName = nickName, avatar = "${ApiClient.BASE_SERVER}$avatar", ) } } /** * 点赞消息通知 */ 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, ) interface AccountService { /** * 获取登录当前用户的资料 */ suspend fun getMyAccountProfile(): AccountProfileEntity /** * 获取登录的用户认证信息 */ suspend fun getMyAccount(): UserAuth /** * 使用用户名密码登录 * @param loginName 用户名 * @param password 密码 */ suspend fun loginUserWithPassword(loginName: String, password: String): UserAuth /** * 使用google登录 * @param googleId googleId */ suspend fun loginUserWithGoogle(googleId: String): UserAuth /** * 退出登录 */ suspend fun logout() /** * 更新用户资料 * @param avatar 头像 * @param nickName 昵称 * @param bio 简介 * @param banner 主页背景图 */ suspend fun updateProfile( avatar: UploadImage?, banner: UploadImage?, nickName: String?, bio: String? ) /** * 注册用户 * @param loginName 用户名 * @param password 密码 */ suspend fun registerUserWithPassword(loginName: String, password: String) /** * 使用google账号注册 * @param idToken googleIdToken */ suspend fun regiterUserWithGoogleAccount(idToken: String) /** * 修改密码 * @param oldPassword 旧密码 * @param newPassword 新密码 */ suspend fun changeAccountPassword(oldPassword: String, newPassword: String) /** * 获取我的点赞通知 * @param page 页码 * @param pageSize 每页数量 */ suspend fun getMyLikeNotice(page: Int, pageSize: Int): ListContainer /** * 获取我的关注通知 * @param page 页码 * @param pageSize 每页数量 */ suspend fun getMyFollowNotice(page: Int, pageSize: Int): ListContainer /** * 获取我的收藏通知 * @param page 页码 * @param pageSize 每页数量 */ suspend fun getMyFavouriteNotice(page: Int, pageSize: Int): ListContainer /** * 获取我的通知信息 */ suspend fun getMyNoticeInfo(): AccountNotice /** * 更新通知信息,更新最后一次查看时间 * @param payload 通知信息 */ suspend fun updateNotice(payload: UpdateNoticeRequestBody) suspend fun registerMessageChannel(client:String,identifier:String) } class AccountServiceImpl : AccountService { override suspend fun getMyAccountProfile(): AccountProfileEntity { val resp = ApiClient.api.getMyAccount() val body = resp.body() ?: throw ServiceException("Failed to get account") return body.data.toAccountProfileEntity() } override suspend fun getMyAccount(): UserAuth { val resp = ApiClient.api.checkToken() val body = resp.body() ?: throw ServiceException("Failed to get account") return UserAuth(body.id) } override suspend fun loginUserWithPassword(loginName: String, password: String): UserAuth { val resp = ApiClient.api.login(LoginUserRequestBody(loginName, password)) val body = resp.body() ?: throw ServiceException("Failed to login") return UserAuth(0, body.token) } override suspend fun loginUserWithGoogle(googleId: String): UserAuth { val resp = ApiClient.api.login(LoginUserRequestBody(googleId = googleId)) val body = resp.body() ?: throw ServiceException("Failed to login") return UserAuth(0, body.token) } override suspend fun regiterUserWithGoogleAccount(idToken: String) { val resp = ApiClient.api.registerWithGoogle(GoogleRegisterRequestBody(idToken)) if (resp.code() != 200) { throw ServiceException("Failed to register") } } override suspend fun logout() { // do nothing } fun createMultipartBody(file: File, filename: String, name: String): MultipartBody.Part { val requestFile = file.asRequestBody("image/*".toMediaTypeOrNull()) return MultipartBody.Part.createFormData(name, filename, requestFile) } override suspend fun updateProfile( avatar: UploadImage?, banner: UploadImage?, nickName: String?, bio: String? ) { val nicknameField: RequestBody? = nickName?.toRequestBody("text/plain".toMediaTypeOrNull()) val bioField: RequestBody? = bio?.toRequestBody("text/plain".toMediaTypeOrNull()) val avatarField: MultipartBody.Part? = avatar?.let { createMultipartBody(it.file, it.filename, "avatar") } val bannerField: MultipartBody.Part? = banner?.let { createMultipartBody(it.file, it.filename, "banner") } ApiClient.api.updateProfile(avatarField, bannerField, nicknameField, bioField) } override suspend fun registerUserWithPassword(loginName: String, password: String) { val resp = ApiClient.api.register(RegisterRequestBody(loginName, password)) if (!resp.isSuccessful) { parseErrorResponse(resp.errorBody())?.let { throw it.toServiceException() } throw ServiceException("Failed to register") } } override suspend fun changeAccountPassword(oldPassword: String, newPassword: String) { ApiClient.api.changePassword(ChangePasswordRequestBody(oldPassword, newPassword)) } override suspend fun getMyLikeNotice(page: Int, pageSize: Int): ListContainer { 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 { 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 { 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) } override suspend fun registerMessageChannel(client: String, identifier: String) { ApiClient.api.registerMessageChannel(RegisterMessageChannelRequestBody(client,identifier)) } }