整理代码
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
package com.aiosman.riderpro.data
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
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.RegisterRequestBody
|
||||
import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody
|
||||
import com.aiosman.riderpro.test.TestDatabase
|
||||
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
|
||||
@@ -16,41 +18,29 @@ import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.Date
|
||||
|
||||
data class AccountLikeEntity(
|
||||
val post: NoticePostEntity,
|
||||
val user: NoticeUserEntity,
|
||||
val likeTime: Date,
|
||||
)
|
||||
|
||||
data class AccountFavouriteEntity(
|
||||
val post: NoticePostEntity,
|
||||
val user: NoticeUserEntity,
|
||||
val favoriteTime: Date,
|
||||
)
|
||||
|
||||
data class AccountProfileEntity(
|
||||
val id: Int,
|
||||
val followerCount: Int,
|
||||
val followingCount: Int,
|
||||
val nickName: String,
|
||||
val avatar: String,
|
||||
val bio: String,
|
||||
val country: String,
|
||||
val isFollowing: Boolean
|
||||
)
|
||||
|
||||
/**
|
||||
* 用户资料
|
||||
*/
|
||||
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
|
||||
) {
|
||||
/**
|
||||
* 转换为Entity
|
||||
*/
|
||||
fun toAccountProfileEntity(): AccountProfileEntity {
|
||||
return AccountProfileEntity(
|
||||
id = id,
|
||||
@@ -65,23 +55,27 @@ data class AccountProfile(
|
||||
}
|
||||
}
|
||||
|
||||
data class NoticePostEntity(
|
||||
val id: Int,
|
||||
val textContent: String,
|
||||
val images: List<Image>,
|
||||
val time: Date,
|
||||
)
|
||||
|
||||
/**
|
||||
* 消息关联资料
|
||||
*/
|
||||
data class NoticePost(
|
||||
// 动态ID
|
||||
@SerializedName("id")
|
||||
val id: Int,
|
||||
// 动态内容
|
||||
@SerializedName("textContent")
|
||||
// 动态图片
|
||||
val textContent: String,
|
||||
// 动态图片
|
||||
@SerializedName("images")
|
||||
val images: List<Image>,
|
||||
// 动态时间
|
||||
@SerializedName("time")
|
||||
val time: String,
|
||||
) {
|
||||
/**
|
||||
* 转换为Entity
|
||||
*/
|
||||
fun toNoticePostEntity(): NoticePostEntity {
|
||||
return NoticePostEntity(
|
||||
id = id,
|
||||
@@ -97,20 +91,23 @@ data class NoticePost(
|
||||
}
|
||||
}
|
||||
|
||||
data class NoticeUserEntity(
|
||||
val id: Int,
|
||||
val nickName: String,
|
||||
val avatar: String,
|
||||
)
|
||||
|
||||
/**
|
||||
* 消息关联用户
|
||||
*/
|
||||
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,
|
||||
@@ -120,13 +117,20 @@ data class NoticeUser(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 点赞消息通知
|
||||
*/
|
||||
data class AccountLike(
|
||||
// 是否未读
|
||||
@SerializedName("isUnread")
|
||||
val isUnread: Boolean,
|
||||
// 动态
|
||||
@SerializedName("post")
|
||||
val post: NoticePost,
|
||||
// 点赞用户
|
||||
@SerializedName("user")
|
||||
val user: NoticeUser,
|
||||
// 点赞时间
|
||||
@SerializedName("likeTime")
|
||||
val likeTime: String,
|
||||
) {
|
||||
@@ -192,108 +196,93 @@ data class AccountNotice(
|
||||
)
|
||||
|
||||
|
||||
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}",
|
||||
)
|
||||
},
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface AccountService {
|
||||
/**
|
||||
* 获取登录当前用户的资料
|
||||
*/
|
||||
suspend fun getMyAccountProfile(): AccountProfileEntity
|
||||
suspend fun getAccountProfileById(id: Int): 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()
|
||||
suspend fun updateAvatar(uri: String)
|
||||
|
||||
/**
|
||||
* 更新用户资料
|
||||
* @param avatar 头像
|
||||
* @param nickName 昵称
|
||||
* @param bio 简介
|
||||
*/
|
||||
suspend fun updateProfile(avatar: 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<AccountLike>
|
||||
|
||||
/**
|
||||
* 获取我的关注通知
|
||||
* @param page 页码
|
||||
* @param pageSize 每页数量
|
||||
*/
|
||||
suspend fun getMyFollowNotice(page: Int, pageSize: Int): ListContainer<AccountFollow>
|
||||
|
||||
/**
|
||||
* 获取我的收藏通知
|
||||
* @param page 页码
|
||||
* @param pageSize 每页数量
|
||||
*/
|
||||
suspend fun getMyFavouriteNotice(page: Int, pageSize: Int): ListContainer<AccountFavourite>
|
||||
|
||||
/**
|
||||
* 获取我的通知信息
|
||||
*/
|
||||
suspend fun getMyNoticeInfo(): AccountNotice
|
||||
|
||||
/**
|
||||
* 更新通知信息,更新最后一次查看时间
|
||||
* @param payload 通知信息
|
||||
*/
|
||||
suspend fun updateNotice(payload: UpdateNoticeRequestBody)
|
||||
}
|
||||
|
||||
@@ -304,12 +293,6 @@ class AccountServiceImpl : AccountService {
|
||||
return body.data.toAccountProfileEntity()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
override suspend fun getMyAccount(): UserAuth {
|
||||
val resp = ApiClient.api.checkToken()
|
||||
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
||||
@@ -323,7 +306,7 @@ class AccountServiceImpl : AccountService {
|
||||
}
|
||||
|
||||
override suspend fun loginUserWithGoogle(googleId: String): UserAuth {
|
||||
val resp = ApiClient.api.login(LoginUserRequestBody(googleId=googleId))
|
||||
val resp = ApiClient.api.login(LoginUserRequestBody(googleId = googleId))
|
||||
val body = resp.body() ?: throw ServiceException("Failed to login")
|
||||
return UserAuth(0, body.token)
|
||||
}
|
||||
@@ -339,15 +322,6 @@ class AccountServiceImpl : AccountService {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override suspend fun updateAvatar(uri: String) {
|
||||
TestDatabase.accountData = TestDatabase.accountData.map {
|
||||
if (it.id == 1) {
|
||||
it.copy(avatar = uri)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createMultipartBody(file: File, filename: String, name: String): MultipartBody.Part {
|
||||
val requestFile = file.asRequestBody("image/*".toMediaTypeOrNull())
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package com.aiosman.riderpro.data
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.aiosman.riderpro.AppStore
|
||||
import com.aiosman.riderpro.data.api.ApiClient
|
||||
import com.aiosman.riderpro.data.api.CommentRequestBody
|
||||
import com.aiosman.riderpro.test.TestDatabase
|
||||
import com.aiosman.riderpro.entity.CommentEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.io.IOException
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* 评论相关 Service
|
||||
*/
|
||||
interface CommentService {
|
||||
/**
|
||||
* 获取动态
|
||||
* @param pageNumber 页码
|
||||
* @param postId 动态ID,过滤条件
|
||||
* @param postUser 动态作者ID,获取某个用户所有动态下的评论
|
||||
* @param selfNotice 是否是自己的通知
|
||||
* @return 评论列表
|
||||
*/
|
||||
suspend fun getComments(
|
||||
pageNumber: Int,
|
||||
postId: Int? = null,
|
||||
@@ -20,32 +24,67 @@ interface CommentService {
|
||||
selfNotice: Boolean? = null
|
||||
): ListContainer<CommentEntity>
|
||||
|
||||
/**
|
||||
* 创建评论
|
||||
* @param postId 动态ID
|
||||
* @param content 评论内容
|
||||
*/
|
||||
suspend fun createComment(postId: Int, content: String)
|
||||
|
||||
/**
|
||||
* 点赞评论
|
||||
* @param commentId 评论ID
|
||||
*/
|
||||
suspend fun likeComment(commentId: Int)
|
||||
|
||||
/**
|
||||
* 取消点赞评论
|
||||
* @param commentId 评论ID
|
||||
*/
|
||||
suspend fun dislikeComment(commentId: Int)
|
||||
|
||||
/**
|
||||
* 更新评论已读状态
|
||||
* @param commentId 评论ID
|
||||
*/
|
||||
suspend fun updateReadStatus(commentId: Int)
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论
|
||||
*/
|
||||
data class Comment(
|
||||
// 评论ID
|
||||
@SerializedName("id")
|
||||
val id: Int,
|
||||
// 评论内容
|
||||
@SerializedName("content")
|
||||
val content: String,
|
||||
// 评论用户
|
||||
@SerializedName("user")
|
||||
val user: User,
|
||||
// 点赞数
|
||||
@SerializedName("likeCount")
|
||||
val likeCount: Int,
|
||||
// 是否点赞
|
||||
@SerializedName("isLiked")
|
||||
val isLiked: Boolean,
|
||||
// 创建时间
|
||||
@SerializedName("createdAt")
|
||||
val createdAt: String,
|
||||
// 动态ID
|
||||
@SerializedName("postId")
|
||||
val postId: Int,
|
||||
// 动态
|
||||
@SerializedName("post")
|
||||
val post: NoticePost?,
|
||||
// 是否未读
|
||||
@SerializedName("isUnread")
|
||||
val isUnread: Boolean
|
||||
) {
|
||||
/**
|
||||
* 转换为Entity
|
||||
*/
|
||||
fun toCommentEntity(): CommentEntity {
|
||||
return CommentEntity(
|
||||
id = id,
|
||||
@@ -73,52 +112,6 @@ data class Comment(
|
||||
}
|
||||
}
|
||||
|
||||
data class CommentEntity(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
val comment: String,
|
||||
val date: Date,
|
||||
val likes: Int,
|
||||
val replies: List<CommentEntity>,
|
||||
val postId: Int = 0,
|
||||
val avatar: String,
|
||||
val author: Long,
|
||||
var liked: Boolean,
|
||||
var unread: Boolean = false,
|
||||
var post: NoticePost?
|
||||
)
|
||||
|
||||
class CommentPagingSource(
|
||||
private val remoteDataSource: CommentRemoteDataSource,
|
||||
private val postId: Int? = null,
|
||||
private val postUser: Int? = null,
|
||||
private val selfNotice: Boolean? = null
|
||||
) : PagingSource<Int, CommentEntity>() {
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, CommentEntity> {
|
||||
return try {
|
||||
val currentPage = params.key ?: 1
|
||||
val comments = remoteDataSource.getComments(
|
||||
pageNumber = currentPage,
|
||||
postId = postId,
|
||||
postUser = postUser,
|
||||
selfNotice = selfNotice
|
||||
)
|
||||
LoadResult.Page(
|
||||
data = comments.list,
|
||||
prevKey = if (currentPage == 1) null else currentPage - 1,
|
||||
nextKey = if (comments.list.isEmpty()) null else comments.page + 1
|
||||
)
|
||||
} catch (exception: IOException) {
|
||||
return LoadResult.Error(exception)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, CommentEntity>): Int? {
|
||||
return state.anchorPosition
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CommentRemoteDataSource(
|
||||
private val commentService: CommentService,
|
||||
) {
|
||||
@@ -138,7 +131,7 @@ class CommentRemoteDataSource(
|
||||
}
|
||||
|
||||
|
||||
class TestCommentServiceImpl : CommentService {
|
||||
class CommentServiceImpl : CommentService {
|
||||
override suspend fun getComments(
|
||||
pageNumber: Int,
|
||||
postId: Int?,
|
||||
@@ -182,7 +175,4 @@ class TestCommentServiceImpl : CommentService {
|
||||
return
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DataBatchSize = 5
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.aiosman.riderpro.data
|
||||
|
||||
/**
|
||||
* 通用接口返回数据
|
||||
*/
|
||||
data class DataContainer<T>(
|
||||
val data: T
|
||||
)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.aiosman.riderpro.data
|
||||
|
||||
/**
|
||||
* 错误返回
|
||||
*/
|
||||
class ServiceException(
|
||||
override val message: String,
|
||||
val code: Int = 0,
|
||||
|
||||
@@ -3,13 +3,20 @@ package com.aiosman.riderpro.data
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
|
||||
/**
|
||||
* 通用列表接口返回
|
||||
*/
|
||||
data class ListContainer<T>(
|
||||
// 总数
|
||||
@SerializedName("total")
|
||||
val total: Int,
|
||||
// 当前页
|
||||
@SerializedName("page")
|
||||
val page: Int,
|
||||
// 每页数量
|
||||
@SerializedName("pageSize")
|
||||
val pageSize: Int,
|
||||
// 列表
|
||||
@SerializedName("list")
|
||||
val list: List<T>
|
||||
)
|
||||
@@ -1,23 +1,11 @@
|
||||
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.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentImageEntity
|
||||
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")
|
||||
@@ -100,9 +88,32 @@ data class UploadImage(
|
||||
)
|
||||
|
||||
interface MomentService {
|
||||
/**
|
||||
* 获取动态详情
|
||||
* @param id 动态ID
|
||||
*/
|
||||
suspend fun getMomentById(id: Int): MomentEntity
|
||||
|
||||
/**
|
||||
* 点赞动态
|
||||
* @param id 动态ID
|
||||
*/
|
||||
suspend fun likeMoment(id: Int)
|
||||
|
||||
/**
|
||||
* 取消点赞动态
|
||||
* @param id 动态ID
|
||||
*/
|
||||
suspend fun dislikeMoment(id: Int)
|
||||
|
||||
/**
|
||||
* 获取动态列表
|
||||
* @param pageNumber 页码
|
||||
* @param author 作者ID,过滤条件
|
||||
* @param timelineId 用户时间线ID,指定用户 ID 的时间线
|
||||
* @param contentSearch 内容搜索,过滤条件
|
||||
* @return 动态列表
|
||||
*/
|
||||
suspend fun getMoments(
|
||||
pageNumber: Int,
|
||||
author: Int? = null,
|
||||
@@ -110,6 +121,13 @@ interface MomentService {
|
||||
contentSearch: String? = null
|
||||
): ListContainer<MomentEntity>
|
||||
|
||||
/**
|
||||
* 创建动态
|
||||
* @param content 动态内容
|
||||
* @param authorId 作者ID
|
||||
* @param images 图片列表
|
||||
* @param relPostId 关联动态ID
|
||||
*/
|
||||
suspend fun createMoment(
|
||||
content: String,
|
||||
authorId: Int,
|
||||
@@ -117,169 +135,17 @@ interface MomentService {
|
||||
relPostId: Int? = null
|
||||
): MomentEntity
|
||||
|
||||
/**
|
||||
* 收藏动态
|
||||
* @param id 动态ID
|
||||
*/
|
||||
suspend fun favoriteMoment(id: Int)
|
||||
|
||||
/**
|
||||
* 取消收藏动态
|
||||
* @param id 动态ID
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +1,43 @@
|
||||
package com.aiosman.riderpro.data
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.aiosman.riderpro.data.api.ApiClient
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.test.TestDatabase
|
||||
import java.io.IOException
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
|
||||
data class UserAuth(
|
||||
val id: Int,
|
||||
val token: String? = null
|
||||
)
|
||||
|
||||
class AccountPagingSource(
|
||||
private val userService: UserService,
|
||||
private val nickname: String? = null
|
||||
) : PagingSource<Int, AccountProfileEntity>() {
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AccountProfileEntity> {
|
||||
return try {
|
||||
val currentPage = params.key ?: 1
|
||||
val users = userService.getUsers(
|
||||
page = currentPage,
|
||||
nickname = nickname
|
||||
)
|
||||
LoadResult.Page(
|
||||
data = users.list,
|
||||
prevKey = if (currentPage == 1) null else currentPage - 1,
|
||||
nextKey = if (users.list.isEmpty()) null else users.page + 1
|
||||
)
|
||||
} catch (exception: IOException) {
|
||||
return LoadResult.Error(exception)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, AccountProfileEntity>): Int? {
|
||||
return state.anchorPosition
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户相关 Service
|
||||
*/
|
||||
interface UserService {
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param id 用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
suspend fun getUserProfile(id: String): AccountProfileEntity
|
||||
|
||||
/**
|
||||
* 关注用户
|
||||
* @param id 用户ID
|
||||
*/
|
||||
suspend fun followUser(id: String)
|
||||
|
||||
/**
|
||||
* 取消关注用户
|
||||
* @param id 用户ID
|
||||
*/
|
||||
suspend fun unFollowUser(id: String)
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
* @param pageSize 分页大小
|
||||
* @param page 页码
|
||||
* @param nickname 昵称搜索
|
||||
* @return 用户列表
|
||||
*/
|
||||
suspend fun getUsers(
|
||||
pageSize: Int = 20,
|
||||
page: Int = 1,
|
||||
@@ -51,7 +46,7 @@ interface UserService {
|
||||
|
||||
}
|
||||
|
||||
class TestUserServiceImpl : UserService {
|
||||
class UserServiceImpl : UserService {
|
||||
override suspend fun getUserProfile(id: String): AccountProfileEntity {
|
||||
val resp = ApiClient.api.getAccountProfileById(id.toInt())
|
||||
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.aiosman.riderpro.data.AccountFollow
|
||||
import com.aiosman.riderpro.data.AccountLike
|
||||
import com.aiosman.riderpro.data.AccountNotice
|
||||
import com.aiosman.riderpro.data.AccountProfile
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.data.Comment
|
||||
import com.aiosman.riderpro.data.DataContainer
|
||||
import com.aiosman.riderpro.data.ListContainer
|
||||
|
||||
176
app/src/main/java/com/aiosman/riderpro/entity/Account.kt
Normal file
176
app/src/main/java/com/aiosman/riderpro/entity/Account.kt
Normal file
@@ -0,0 +1,176 @@
|
||||
package com.aiosman.riderpro.entity
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.aiosman.riderpro.data.AccountFollow
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.Image
|
||||
import com.aiosman.riderpro.data.api.ApiClient
|
||||
import java.io.IOException
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* 用户点赞
|
||||
*/
|
||||
data class AccountLikeEntity(
|
||||
// 动态
|
||||
val post: NoticePostEntity,
|
||||
// 点赞用户
|
||||
val user: NoticeUserEntity,
|
||||
// 点赞时间
|
||||
val likeTime: Date,
|
||||
)
|
||||
|
||||
/**
|
||||
* 用户收藏
|
||||
*/
|
||||
data class AccountFavouriteEntity(
|
||||
// 动态
|
||||
val post: NoticePostEntity,
|
||||
// 收藏用户
|
||||
val user: NoticeUserEntity,
|
||||
// 收藏时间
|
||||
val favoriteTime: Date,
|
||||
)
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
data class AccountProfileEntity(
|
||||
// 用户ID
|
||||
val id: Int,
|
||||
// 粉丝数
|
||||
val followerCount: Int,
|
||||
// 关注数
|
||||
val followingCount: Int,
|
||||
// 昵称
|
||||
val nickName: String,
|
||||
// 头像
|
||||
val avatar: String,
|
||||
// 个人简介
|
||||
val bio: String,
|
||||
// 国家
|
||||
val country: String,
|
||||
// 是否关注,针对当前登录用户
|
||||
val isFollowing: Boolean
|
||||
)
|
||||
|
||||
/**
|
||||
* 消息关联的动态
|
||||
*/
|
||||
data class NoticePostEntity(
|
||||
// 动态ID
|
||||
val id: Int,
|
||||
// 动态内容
|
||||
val textContent: String,
|
||||
// 动态图片
|
||||
val images: List<Image>,
|
||||
// 时间
|
||||
val time: Date,
|
||||
)
|
||||
|
||||
/**
|
||||
* 消息关联的用户
|
||||
*/
|
||||
data class NoticeUserEntity(
|
||||
// 用户ID
|
||||
val id: Int,
|
||||
// 昵称
|
||||
val nickName: String,
|
||||
// 头像
|
||||
val avatar: String,
|
||||
)
|
||||
|
||||
/**
|
||||
* 用户点赞消息分页数据加载器
|
||||
*/
|
||||
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}",
|
||||
)
|
||||
},
|
||||
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
|
||||
}
|
||||
}
|
||||
54
app/src/main/java/com/aiosman/riderpro/entity/Comment.kt
Normal file
54
app/src/main/java/com/aiosman/riderpro/entity/Comment.kt
Normal file
@@ -0,0 +1,54 @@
|
||||
package com.aiosman.riderpro.entity
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.NoticePost
|
||||
import java.io.IOException
|
||||
import java.util.Date
|
||||
|
||||
data class CommentEntity(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
val comment: String,
|
||||
val date: Date,
|
||||
val likes: Int,
|
||||
val replies: List<CommentEntity>,
|
||||
val postId: Int = 0,
|
||||
val avatar: String,
|
||||
val author: Long,
|
||||
var liked: Boolean,
|
||||
var unread: Boolean = false,
|
||||
var post: NoticePost?
|
||||
)
|
||||
|
||||
class CommentPagingSource(
|
||||
private val remoteDataSource: CommentRemoteDataSource,
|
||||
private val postId: Int? = null,
|
||||
private val postUser: Int? = null,
|
||||
private val selfNotice: Boolean? = null
|
||||
) : PagingSource<Int, CommentEntity>() {
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, CommentEntity> {
|
||||
return try {
|
||||
val currentPage = params.key ?: 1
|
||||
val comments = remoteDataSource.getComments(
|
||||
pageNumber = currentPage,
|
||||
postId = postId,
|
||||
postUser = postUser,
|
||||
selfNotice = selfNotice
|
||||
)
|
||||
LoadResult.Page(
|
||||
data = comments.list,
|
||||
prevKey = if (currentPage == 1) null else currentPage - 1,
|
||||
nextKey = if (comments.list.isEmpty()) null else comments.page + 1
|
||||
)
|
||||
} catch (exception: IOException) {
|
||||
return LoadResult.Error(exception)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, CommentEntity>): Int? {
|
||||
return state.anchorPosition
|
||||
}
|
||||
|
||||
}
|
||||
236
app/src/main/java/com/aiosman/riderpro/entity/Moment.kt
Normal file
236
app/src/main/java/com/aiosman/riderpro/entity/Moment.kt
Normal file
@@ -0,0 +1,236 @@
|
||||
package com.aiosman.riderpro.entity
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.aiosman.riderpro.data.ListContainer
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.ServiceException
|
||||
import com.aiosman.riderpro.data.UploadImage
|
||||
import com.aiosman.riderpro.data.api.ApiClient
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* 动态分页加载器
|
||||
*/
|
||||
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 MomentServiceImpl() : MomentService {
|
||||
val momentBackend = MomentBackend()
|
||||
|
||||
override suspend fun getMoments(
|
||||
pageNumber: Int,
|
||||
author: Int?,
|
||||
timelineId: Int?,
|
||||
contentSearch: String?
|
||||
): ListContainer<MomentEntity> {
|
||||
return momentBackend.fetchMomentItems(pageNumber, author, timelineId, contentSearch)
|
||||
}
|
||||
|
||||
override suspend fun getMomentById(id: Int): MomentEntity {
|
||||
return momentBackend.getMomentById(id)
|
||||
}
|
||||
|
||||
|
||||
override suspend fun likeMoment(id: Int) {
|
||||
momentBackend.likeMoment(id)
|
||||
}
|
||||
|
||||
override suspend fun dislikeMoment(id: Int) {
|
||||
momentBackend.dislikeMoment(id)
|
||||
}
|
||||
|
||||
override suspend fun createMoment(
|
||||
content: String,
|
||||
authorId: Int,
|
||||
images: List<UploadImage>,
|
||||
relPostId: Int?
|
||||
): MomentEntity {
|
||||
return momentBackend.createMoment(content, authorId, images, relPostId)
|
||||
}
|
||||
|
||||
override suspend fun favoriteMoment(id: Int) {
|
||||
momentBackend.favoriteMoment(id)
|
||||
}
|
||||
|
||||
override suspend fun unfavoriteMoment(id: Int) {
|
||||
momentBackend.unfavoriteMoment(id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MomentBackend {
|
||||
val DataBatchSize = 20
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态图片
|
||||
*/
|
||||
data class MomentImageEntity(
|
||||
// 图片ID
|
||||
val id: Long,
|
||||
// 图片URL
|
||||
val url: String,
|
||||
// 缩略图URL
|
||||
val thumbnail: String,
|
||||
// 图片BlurHash
|
||||
val blurHash: String? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* 动态
|
||||
*/
|
||||
data class MomentEntity(
|
||||
// 动态ID
|
||||
val id: Int,
|
||||
// 作者头像
|
||||
val avatar: String,
|
||||
// 作者昵称
|
||||
val nickname: String,
|
||||
// 区域
|
||||
val location: String,
|
||||
// 动态时间
|
||||
val time: Date,
|
||||
// 是否关注
|
||||
val followStatus: Boolean,
|
||||
// 动态内容
|
||||
val momentTextContent: String,
|
||||
// 动态图片
|
||||
@DrawableRes val momentPicture: Int,
|
||||
// 点赞数
|
||||
val likeCount: Int,
|
||||
// 评论数
|
||||
val commentCount: Int,
|
||||
// 分享数
|
||||
val shareCount: Int,
|
||||
// 收藏数
|
||||
val favoriteCount: Int,
|
||||
// 动态图片列表
|
||||
val images: List<MomentImageEntity> = emptyList(),
|
||||
// 作者ID
|
||||
val authorId: Int = 0,
|
||||
// 是否点赞
|
||||
var liked: Boolean = false,
|
||||
// 关联动态ID
|
||||
var relPostId: Int? = null,
|
||||
// 关联动态
|
||||
var relMoment: MomentEntity? = null,
|
||||
// 是否收藏
|
||||
var isFavorite: Boolean = false
|
||||
)
|
||||
36
app/src/main/java/com/aiosman/riderpro/entity/User.kt
Normal file
36
app/src/main/java/com/aiosman/riderpro/entity/User.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.aiosman.riderpro.entity
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* 用户信息分页加载器
|
||||
*/
|
||||
class AccountPagingSource(
|
||||
private val userService: UserService,
|
||||
private val nickname: String? = null
|
||||
) : PagingSource<Int, AccountProfileEntity>() {
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AccountProfileEntity> {
|
||||
return try {
|
||||
val currentPage = params.key ?: 1
|
||||
val users = userService.getUsers(
|
||||
page = currentPage,
|
||||
nickname = nickname
|
||||
)
|
||||
LoadResult.Page(
|
||||
data = users.list,
|
||||
prevKey = if (currentPage == 1) null else currentPage - 1,
|
||||
nextKey = if (users.list.isEmpty()) null else users.page + 1
|
||||
)
|
||||
} catch (exception: IOException) {
|
||||
return LoadResult.Error(exception)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, AccountProfileEntity>): Int? {
|
||||
return state.anchorPosition
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,9 @@ import com.aiosman.riderpro.data.api.ApiClient
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 格式化时间为 xx 前
|
||||
*/
|
||||
fun Date.timeAgo(): String {
|
||||
val now = Date()
|
||||
val diffInMillis = now.time - this.time
|
||||
@@ -25,6 +28,9 @@ fun Date.timeAgo(): String {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间为 xx-xx
|
||||
*/
|
||||
fun Date.formatPostTime(): String {
|
||||
val now = Calendar.getInstance()
|
||||
val calendar = Calendar.getInstance()
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.aiosman.riderpro.model
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import java.util.Date
|
||||
|
||||
data class MomentImageEntity(
|
||||
val id: Long,
|
||||
val url: String,
|
||||
val thumbnail: String,
|
||||
val blurHash: String? = null
|
||||
)
|
||||
|
||||
data class MomentEntity(
|
||||
val id: Int,
|
||||
val avatar: String,
|
||||
val nickname: String,
|
||||
val location: String,
|
||||
val time: Date,
|
||||
val followStatus: Boolean,
|
||||
val momentTextContent: String,
|
||||
@DrawableRes val momentPicture: Int,
|
||||
val likeCount: Int,
|
||||
val commentCount: Int,
|
||||
val shareCount: Int,
|
||||
val favoriteCount: Int,
|
||||
val images: List<MomentImageEntity> = emptyList(),
|
||||
val authorId: Int = 0,
|
||||
var liked: Boolean = false,
|
||||
var relPostId: Int? = null,
|
||||
var relMoment: MomentEntity? = null,
|
||||
var isFavorite: Boolean = false
|
||||
)
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.aiosman.riderpro.test
|
||||
|
||||
import kotlin.math.min
|
||||
|
||||
class MockDataContainer<T>(
|
||||
val success: Boolean,
|
||||
val data: T?
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
class MockListContainer<T>(
|
||||
val total: Int,
|
||||
val page: Int,
|
||||
val pageSize: Int,
|
||||
val list: List<T>
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
abstract class MockDataSource<T> {
|
||||
var list = mutableListOf<T>()
|
||||
suspend fun fetchData(page: Int, pageSize: Int): MockDataContainer<MockListContainer<T>> {
|
||||
// over page return empty
|
||||
if (page * pageSize > list.size) {
|
||||
return MockDataContainer(false, MockListContainer(0, page, pageSize, emptyList()))
|
||||
}
|
||||
val backData = list.subList((page - 1) * pageSize, min(page * pageSize, list.size))
|
||||
return MockDataContainer(true, MockListContainer(list.size, page, pageSize, backData))
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.aiosman.riderpro.test
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.math.ceil
|
||||
|
||||
class TestBackend(
|
||||
private val backendDataList: List<MomentEntity>,
|
||||
private val loadDelay: Long = 500,
|
||||
) {
|
||||
val DataBatchSize = 5
|
||||
class DesiredLoadResultPageResponse(val data: List<MomentEntity>)
|
||||
/** Returns [DataBatchSize] items for a key */
|
||||
fun searchItemsByKey(key: Int): DesiredLoadResultPageResponse {
|
||||
val maxKey = ceil(backendDataList.size.toFloat() / DataBatchSize).toInt()
|
||||
if (key >= maxKey) {
|
||||
return DesiredLoadResultPageResponse(emptyList())
|
||||
}
|
||||
val from = key * DataBatchSize
|
||||
val to = minOf((key + 1) * DataBatchSize, backendDataList.size)
|
||||
val currentSublist = backendDataList.subList(from, to)
|
||||
return DesiredLoadResultPageResponse(currentSublist)
|
||||
}
|
||||
fun getAllData() = TestPagingSource(this, loadDelay)
|
||||
}
|
||||
class TestPagingSource(
|
||||
private val backend: TestBackend,
|
||||
private val loadDelay: Long,
|
||||
) : PagingSource<Int, MomentEntity>() {
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MomentEntity> {
|
||||
// Simulate latency
|
||||
delay(loadDelay)
|
||||
val pageNumber = params.key ?: 0
|
||||
val response = backend.searchItemsByKey(pageNumber)
|
||||
// Since 0 is the lowest page number, return null to signify no more pages should
|
||||
// be loaded before it.
|
||||
val prevKey = if (pageNumber > 0) pageNumber - 1 else null
|
||||
// This API defines that it's out of data when a page returns empty. When out of
|
||||
// data, we return `null` to signify no more pages should be loaded
|
||||
val nextKey = if (response.data.isNotEmpty()) pageNumber + 1 else null
|
||||
return LoadResult.Page(data = response.data, prevKey = prevKey, nextKey = nextKey)
|
||||
}
|
||||
override fun getRefreshKey(state: PagingState<Int, MomentEntity>): Int? {
|
||||
return state.anchorPosition?.let {
|
||||
state.closestPageToPosition(it)?.prevKey?.plus(1)
|
||||
?: state.closestPageToPosition(it)?.nextKey?.minus(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
package com.aiosman.riderpro.test
|
||||
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.data.CommentEntity
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.model.MomentImageEntity
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import io.github.serpro69.kfaker.faker
|
||||
import java.io.File
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
object TestDatabase {
|
||||
var momentData = emptyList<MomentEntity>()
|
||||
var accountData = emptyList<AccountProfileEntity>()
|
||||
var commentEntity = emptyList<CommentEntity>()
|
||||
var commentIdCounter = 0
|
||||
var momentIdCounter = 0
|
||||
var selfId = 1
|
||||
var imageList = listOf(
|
||||
"https://img.freepik.com/free-photo/white-billboard-template_23-2147726635.jpg?t=st=1722150015~exp=1722153615~hmac=5540620196d7898215d822be26353c87a63d51bbfb2b814e032626e1948a1583&w=740",
|
||||
"https://img.freepik.com/free-photo/minimal-clothing-label-fashion-brands_53876-111053.jpg?w=1060&t=st=1722150122~exp=1722150722~hmac=67f8a2b6abfe3d08714cf0cc0085485c3221e1ba00dda14378b03753dce39153",
|
||||
"https://img.freepik.com/free-photo/marketing-strategy-planning-strategy-concept_53876-42950.jpg",
|
||||
"https://t4.ftcdn.net/jpg/02/27/00/89/240_F_227008949_5O7yXuEqTwUgs3BGqdcvrNutM5MSxs1t.jpg",
|
||||
"https://t4.ftcdn.net/jpg/01/86/86/49/240_F_186864971_NixcoDg1zBjjN7soUNhpEVraI4vdzOFD.jpg",
|
||||
"https://t3.ftcdn.net/jpg/00/84/01/30/240_F_84013057_fsOdzBgskSFUyWyD6YKjIAdtKdBPiKRD.jpg",
|
||||
"https://t4.ftcdn.net/jpg/00/93/89/23/240_F_93892312_SNyGGruVaWKpJQiVG314gIQmS4EAghdy.jpg",
|
||||
"https://t3.ftcdn.net/jpg/02/94/56/58/240_F_294565895_IOqZC2OpcHGEibWF04MPEP09KZaewEl5.jpg",
|
||||
"https://t3.ftcdn.net/jpg/01/01/66/84/240_F_101668484_FopHBSMBq4t6BlvwI9awPMzUdi501sJ7.jpg",
|
||||
"https://t3.ftcdn.net/jpg/05/65/11/60/240_F_565116019_oHbZ6Hc8VYCMcZWpexXF7Z5lOWeNNYtD.jpg",
|
||||
"https://t3.ftcdn.net/jpg/03/52/21/48/240_F_352214843_dQ3JtTJrKyqrh2yd1emYCDPSrzrwqaNK.jpg",
|
||||
"https://t3.ftcdn.net/jpg/07/22/47/16/240_F_722471661_T25r329RFRxgK88S6oBJ9dUksOC2arLl.jpg",
|
||||
"https://t3.ftcdn.net/jpg/02/18/11/26/240_F_218112603_jBChzLJGuz8smPZsdFsy17wB0O0QF3Xo.jpg",
|
||||
"https://t4.ftcdn.net/jpg/04/11/49/07/240_F_411490703_KRvV0aRyxHWYVUO8bGXxuQGo2mHblYnv.jpg",
|
||||
"https://img.freepik.com/premium-photo/man-wearing-orange-helmet-white-background_466494-5539.jpg?ga=GA1.1.1334458544.1722150011&semt=sph",
|
||||
"https://img.freepik.com/premium-photo/motorcycle-vehicle-3d-modelling_274824-502.jpg?ga=GA1.1.1334458544.1722150011&semt=sph",
|
||||
"https://t3.ftcdn.net/jpg/01/68/26/06/240_F_168260687_UfaDjjs6TxcIB6BdsquSeCmYWEFmN1Sh.jpg",
|
||||
"https://t3.ftcdn.net/jpg/03/48/50/34/240_F_348503435_On7Tt5Eqn7IP9QWYTQL0H1smubU8gvLv.jpg",
|
||||
"https://t3.ftcdn.net/jpg/02/76/70/70/240_F_276707060_WpP9bwHWv0Wdqqn0pEgtSuIgXUvgkbs7.jpg",
|
||||
"https://t3.ftcdn.net/jpg/02/65/43/04/240_F_265430460_DIHqnrziar7WL2rmW0qbDO07TbxjlPQo.jpg"
|
||||
)
|
||||
var followList = emptyList<Pair<Int, Int>>()
|
||||
var likeCommentList = emptyList<Pair<Int, Int>>()
|
||||
var likeMomentList = emptyList<Pair<Int, Int>>()
|
||||
|
||||
init {
|
||||
val faker = faker {
|
||||
this.fakerConfig {
|
||||
locale = "en"
|
||||
}
|
||||
}
|
||||
accountData = (0..20).toList().mapIndexed { idx, _ ->
|
||||
AccountProfileEntity(
|
||||
id = idx,
|
||||
followerCount = 0,
|
||||
followingCount = 0,
|
||||
nickName = faker.name.name(),
|
||||
avatar = imageList.random(),
|
||||
bio = "I am a software engineer",
|
||||
country = faker.address.country(),
|
||||
isFollowing = false
|
||||
|
||||
)
|
||||
}
|
||||
// make a random follow rel
|
||||
for (i in 0..100) {
|
||||
var person1 = accountData.random()
|
||||
var persion2 = accountData.random()
|
||||
followList += Pair(person1.id, persion2.id)
|
||||
// update followerCount and followingCount
|
||||
accountData = accountData.map {
|
||||
if (it.id == person1.id) {
|
||||
it.copy(followingCount = it.followingCount + 1)
|
||||
} else if (it.id == persion2.id) {
|
||||
it.copy(followerCount = it.followerCount + 1)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
momentData = (0..60).toList().mapIndexed { idx, _ ->
|
||||
momentIdCounter += 1
|
||||
val person = accountData.random()
|
||||
// make fake comment
|
||||
val commentCount = faker.random.nextInt(0, 50)
|
||||
for (i in 0..commentCount) {
|
||||
commentIdCounter += 1
|
||||
val commentPerson = accountData.random()
|
||||
var newCommentEntity = CommentEntity(
|
||||
name = commentPerson.nickName,
|
||||
comment = "this is comment ${commentIdCounter}",
|
||||
date = Calendar.getInstance().time,
|
||||
likes = 0,
|
||||
replies = emptyList(),
|
||||
postId = momentIdCounter,
|
||||
avatar = commentPerson.avatar,
|
||||
author = commentPerson.id.toLong(),
|
||||
id = commentIdCounter,
|
||||
liked = false,
|
||||
unread = false,
|
||||
post = null
|
||||
)
|
||||
// generate like comment list
|
||||
for (likeIdx in 0..faker.random.nextInt(0, 5)) {
|
||||
val likePerson = accountData.random()
|
||||
likeCommentList += Pair(commentIdCounter, likePerson.id)
|
||||
newCommentEntity = newCommentEntity.copy(likes = newCommentEntity.likes + 1)
|
||||
}
|
||||
commentEntity += newCommentEntity
|
||||
}
|
||||
val likeCount = faker.random.nextInt(0, 5)
|
||||
for (i in 0..likeCount) {
|
||||
val likePerson = accountData.random()
|
||||
likeMomentList += Pair(momentIdCounter, likePerson.id)
|
||||
}
|
||||
MomentEntity(
|
||||
id = momentIdCounter,
|
||||
avatar = person.avatar,
|
||||
nickname = person.nickName,
|
||||
location = person.country,
|
||||
time = Date(),
|
||||
followStatus = false,
|
||||
momentTextContent = "By strongarming Ducati into giving him the factory seat.Marquez effectively …",
|
||||
momentPicture = R.drawable.default_moment_img,
|
||||
likeCount = likeCount,
|
||||
commentCount = commentCount + 1,
|
||||
shareCount = faker.random.nextInt(0, 100),
|
||||
favoriteCount = faker.random.nextInt(0, 100),
|
||||
images = imageList.shuffled().take(3).map {
|
||||
MomentImageEntity(
|
||||
id = faker.random.nextLong(),
|
||||
url = it,
|
||||
thumbnail = it
|
||||
)
|
||||
},
|
||||
authorId = person.id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun updateMomentById(id: Int, momentEntity: MomentEntity) {
|
||||
momentData = momentData.map {
|
||||
if (it.id == id) {
|
||||
momentEntity
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun saveResultToJsonFile() {
|
||||
val gson: Gson = GsonBuilder().setPrettyPrinting().create()
|
||||
|
||||
// save accountData to json file
|
||||
File("accountData.json").writeText(accountData.toString())
|
||||
// save momentData to json file
|
||||
// save comment to json file
|
||||
}
|
||||
}
|
||||
@@ -9,16 +9,27 @@ import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 修改密码页面的 ViewModel
|
||||
*/
|
||||
class ChangePasswordViewModel {
|
||||
val accountService :AccountService = AccountServiceImpl()
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
* @param currentPassword 当前密码
|
||||
* @param newPassword 新密码
|
||||
*/
|
||||
suspend fun changePassword(currentPassword: String, newPassword: String) {
|
||||
accountService.changeAccountPassword(currentPassword, newPassword)
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
fun ChangePasswordScreen(
|
||||
|
||||
) {
|
||||
/**
|
||||
* 修改密码页面
|
||||
*/
|
||||
@Composable
|
||||
fun ChangePasswordScreen() {
|
||||
val viewModel = remember { ChangePasswordViewModel() }
|
||||
var currentPassword by remember { mutableStateOf("") }
|
||||
var newPassword by remember { mutableStateOf("") }
|
||||
|
||||
@@ -33,10 +33,10 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.data.UploadImage
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||
@@ -44,10 +44,12 @@ import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.riderpro.ui.post.NewPostViewModel.uriToFile
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 编辑用户资料界面
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AccountEditScreen() {
|
||||
val userService: UserService = TestUserServiceImpl()
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
var name by remember { mutableStateOf("") }
|
||||
var bio by remember { mutableStateOf("") }
|
||||
@@ -59,8 +61,11 @@ fun AccountEditScreen() {
|
||||
}
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
suspend fun reloadProfile() {
|
||||
|
||||
/**
|
||||
* 加载用户资料
|
||||
*/
|
||||
suspend fun reloadProfile() {
|
||||
accountService.getMyAccountProfile().let {
|
||||
profile = it
|
||||
name = it.nickName
|
||||
@@ -70,19 +75,12 @@ fun AccountEditScreen() {
|
||||
|
||||
}
|
||||
|
||||
fun updateUserAvatar(uri: String) {
|
||||
scope.launch {
|
||||
accountService.updateAvatar(uri)
|
||||
reloadProfile()
|
||||
}
|
||||
|
||||
}
|
||||
fun updateUserProfile() {
|
||||
scope.launch {
|
||||
val newAvatar = imageUrl?.let {
|
||||
val cursor = context.contentResolver.query(it, null, null, null, null)
|
||||
var newAvatar: UploadImage? = null
|
||||
cursor?.use {cur ->
|
||||
cursor?.use { cur ->
|
||||
if (cur.moveToFirst()) {
|
||||
val displayName = cur.getString(cur.getColumnIndex("_display_name"))
|
||||
val extension = displayName.substringAfterLast(".")
|
||||
@@ -135,13 +133,13 @@ fun AccountEditScreen() {
|
||||
)
|
||||
}
|
||||
}
|
||||
) {
|
||||
padding ->
|
||||
) { padding ->
|
||||
profile?.let {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding).padding(horizontal = 24.dp),
|
||||
.padding(padding)
|
||||
.padding(horizontal = 24.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
CustomAsyncImage(
|
||||
|
||||
@@ -49,19 +49,22 @@ import androidx.paging.cachedIn
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.aiosman.riderpro.ui.post.CommentsSection
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.data.CommentEntity
|
||||
import com.aiosman.riderpro.data.CommentPagingSource
|
||||
import com.aiosman.riderpro.entity.CommentEntity
|
||||
import com.aiosman.riderpro.entity.CommentPagingSource
|
||||
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.CommentService
|
||||
import com.aiosman.riderpro.data.TestCommentServiceImpl
|
||||
import com.aiosman.riderpro.data.CommentServiceImpl
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 评论弹窗的 ViewModel
|
||||
*/
|
||||
class CommentModalViewModel(
|
||||
val postId: Int?
|
||||
) : ViewModel() {
|
||||
val commentService: CommentService = TestCommentServiceImpl()
|
||||
val commentService: CommentService = CommentServiceImpl()
|
||||
val commentsFlow: Flow<PagingData<CommentEntity>> = Pager(
|
||||
config = PagingConfig(pageSize = 20, enablePlaceholders = false),
|
||||
pagingSourceFactory = {
|
||||
@@ -72,6 +75,9 @@ class CommentModalViewModel(
|
||||
}
|
||||
).flow.cachedIn(viewModelScope)
|
||||
|
||||
/**
|
||||
* 创建评论
|
||||
*/
|
||||
suspend fun createComment(content: String) {
|
||||
postId?.let {
|
||||
commentService.createComment(postId, content)
|
||||
@@ -79,7 +85,13 @@ class CommentModalViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
|
||||
/**
|
||||
* 评论弹窗
|
||||
* @param postId 帖子ID
|
||||
* @param onCommentAdded 评论添加回调
|
||||
* @param onDismiss 关闭回调
|
||||
*/
|
||||
@Composable
|
||||
fun CommentModalContent(
|
||||
postId: Int? = null,
|
||||
|
||||
@@ -10,7 +10,7 @@ import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.ui.index.tabs.moment.MomentTopRowGroup
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -7,9 +7,9 @@ import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import com.aiosman.riderpro.data.AccountFavouriteEntity
|
||||
import com.aiosman.riderpro.entity.AccountFavouriteEntity
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.FavoriteItemPagingSource
|
||||
import com.aiosman.riderpro.entity.FavoriteItemPagingSource
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.api.ApiClient
|
||||
import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody
|
||||
@@ -18,6 +18,9 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 收藏消息列表的 ViewModel
|
||||
*/
|
||||
object FavouritePageViewModel : ViewModel() {
|
||||
private val accountService: AccountService = AccountServiceImpl()
|
||||
private val _favouriteItemsFlow =
|
||||
@@ -38,6 +41,7 @@ object FavouritePageViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更新收藏消息的查看时间
|
||||
suspend fun updateNotice() {
|
||||
var now = Calendar.getInstance().time
|
||||
accountService.updateNotice(
|
||||
|
||||
@@ -37,11 +37,12 @@ import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
||||
import com.aiosman.riderpro.ui.like.ActionNoticeItem
|
||||
import com.aiosman.riderpro.ui.like.LikePageViewModel
|
||||
|
||||
@Preview
|
||||
/**
|
||||
* 收藏消息界面
|
||||
*/
|
||||
@Composable
|
||||
fun FavouriteScreen() {
|
||||
val model = FavouritePageViewModel
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val listState = rememberLazyListState()
|
||||
var dataFlow = model.favouriteItemsFlow
|
||||
var favourites = dataFlow.collectAsLazyPagingItems()
|
||||
@@ -59,7 +60,9 @@ fun FavouriteScreen() {
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 16.dp)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp)
|
||||
) {
|
||||
NoticeScreenHeader(
|
||||
"FAVOURITE",
|
||||
|
||||
@@ -35,7 +35,9 @@ import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Preview
|
||||
/**
|
||||
* 关注消息列表
|
||||
*/
|
||||
@Composable
|
||||
fun FollowerScreen() {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
@@ -10,9 +10,9 @@ import androidx.paging.cachedIn
|
||||
import androidx.paging.map
|
||||
import com.aiosman.riderpro.data.AccountFollow
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.FollowItemPagingSource
|
||||
import com.aiosman.riderpro.entity.FollowItemPagingSource
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.data.api.ApiClient
|
||||
import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody
|
||||
@@ -21,9 +21,12 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 关注消息列表的 ViewModel
|
||||
*/
|
||||
object FollowerViewModel : ViewModel() {
|
||||
private val accountService: AccountService = AccountServiceImpl()
|
||||
private val userService: UserService = TestUserServiceImpl()
|
||||
private val userService: UserService = UserServiceImpl()
|
||||
private val _followerItemsFlow =
|
||||
MutableStateFlow<PagingData<AccountFollow>>(PagingData.empty())
|
||||
val followerItemsFlow = _followerItemsFlow.asStateFlow()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.aiosman.riderpro.ui.imageviewer
|
||||
|
||||
import com.aiosman.riderpro.model.MomentImageEntity
|
||||
import com.aiosman.riderpro.entity.MomentImageEntity
|
||||
|
||||
object ImageViewerViewModel {
|
||||
var imageList = mutableListOf<MomentImageEntity>()
|
||||
|
||||
@@ -60,7 +60,7 @@ fun IndexScreen() {
|
||||
val systemUiController = rememberSystemUiController()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
// systemUiController.setNavigationBarColor(Color.Transparent)
|
||||
systemUiController.setNavigationBarColor(Color.Transparent)
|
||||
}
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
|
||||
@@ -32,17 +32,18 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.data.CommentEntity
|
||||
import com.aiosman.riderpro.entity.CommentEntity
|
||||
import com.aiosman.riderpro.exp.timeAgo
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
|
||||
|
||||
@Preview(showBackground = true)
|
||||
/**
|
||||
* 消息列表界面
|
||||
*/
|
||||
@Composable
|
||||
fun NotificationsScreen() {
|
||||
val model = MessageListViewModel
|
||||
|
||||
@@ -12,12 +12,12 @@ import androidx.paging.cachedIn
|
||||
import androidx.paging.map
|
||||
import com.aiosman.riderpro.data.AccountNotice
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.CommentEntity
|
||||
import com.aiosman.riderpro.data.CommentPagingSource
|
||||
import com.aiosman.riderpro.entity.CommentEntity
|
||||
import com.aiosman.riderpro.entity.CommentPagingSource
|
||||
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.CommentService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.TestCommentServiceImpl
|
||||
import com.aiosman.riderpro.data.CommentServiceImpl
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
@@ -27,7 +27,7 @@ object MessageListViewModel : ViewModel() {
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
var noticeInfo by mutableStateOf<AccountNotice?>(null)
|
||||
|
||||
private val commentService: CommentService = TestCommentServiceImpl()
|
||||
private val commentService: CommentService = CommentServiceImpl()
|
||||
private val _commentItemsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
||||
val commentItemsFlow = _commentItemsFlow.asStateFlow()
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@@ -65,9 +64,9 @@ import com.aiosman.riderpro.LocalAnimatedContentScope
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.LocalSharedTransitionScope
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentImageEntity
|
||||
import com.aiosman.riderpro.exp.timeAgo
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.model.MomentImageEntity
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.comment.CommentModalContent
|
||||
import com.aiosman.riderpro.ui.composables.AnimatedCounter
|
||||
@@ -78,9 +77,11 @@ import com.aiosman.riderpro.ui.composables.RelPostCard
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
||||
import com.aiosman.riderpro.ui.post.PostViewModel
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 动态列表
|
||||
*/
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun MomentsList() {
|
||||
|
||||
@@ -8,12 +8,12 @@ import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.map
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.MomentPagingSource
|
||||
import com.aiosman.riderpro.data.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
||||
import com.aiosman.riderpro.entity.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentServiceImpl
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
@@ -21,7 +21,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
object MomentViewModel : ViewModel() {
|
||||
private val momentService: MomentService = TestMomentServiceImpl()
|
||||
private val momentService: MomentService = MomentServiceImpl()
|
||||
private val _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
||||
val momentsFlow = _momentsFlow.asStateFlow()
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
|
||||
@@ -7,19 +7,19 @@ import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import com.aiosman.riderpro.AppStore
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.MomentPagingSource
|
||||
import com.aiosman.riderpro.data.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
||||
import com.aiosman.riderpro.entity.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.entity.MomentServiceImpl
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
object MyProfileViewModel {
|
||||
val service: AccountService = AccountServiceImpl()
|
||||
val userService = TestUserServiceImpl()
|
||||
val userService = UserServiceImpl()
|
||||
var profile by mutableStateOf<AccountProfileEntity?>(null)
|
||||
var momentsFlow by mutableStateOf<Flow<PagingData<MomentEntity>>?>(null)
|
||||
suspend fun loadProfile() {
|
||||
@@ -28,7 +28,7 @@ object MyProfileViewModel {
|
||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||
pagingSourceFactory = {
|
||||
MomentPagingSource(
|
||||
MomentRemoteDataSource(TestMomentServiceImpl()),
|
||||
MomentRemoteDataSource(MomentServiceImpl()),
|
||||
author = profile?.id ?: 0,
|
||||
|
||||
)
|
||||
|
||||
@@ -4,7 +4,6 @@ import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -47,14 +46,13 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import coil.compose.AsyncImage
|
||||
import com.aiosman.riderpro.LocalAnimatedContentScope
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.LocalSharedTransitionScope
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.exp.formatPostTime
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
|
||||
@@ -44,7 +44,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.riderpro.ui.index.tabs.moment.MomentCard
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
|
||||
@@ -9,16 +9,14 @@ import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import com.aiosman.riderpro.data.AccountPagingSource
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.data.MomentPagingSource
|
||||
import com.aiosman.riderpro.data.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.entity.AccountPagingSource
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
||||
import com.aiosman.riderpro.entity.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel
|
||||
import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel.accountService
|
||||
import com.aiosman.riderpro.entity.MomentServiceImpl
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
@@ -26,11 +24,11 @@ import kotlinx.coroutines.launch
|
||||
|
||||
object SearchViewModel : ViewModel() {
|
||||
var searchText by mutableStateOf("")
|
||||
private val momentService: MomentService = TestMomentServiceImpl()
|
||||
private val momentService: MomentService = MomentServiceImpl()
|
||||
private val _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
||||
val momentsFlow = _momentsFlow.asStateFlow()
|
||||
|
||||
private val userService = TestUserServiceImpl()
|
||||
private val userService = UserServiceImpl()
|
||||
private val _usersFlow = MutableStateFlow<PagingData<AccountProfileEntity>>(PagingData.empty())
|
||||
val usersFlow = _usersFlow.asStateFlow()
|
||||
var showResult by mutableStateOf(false)
|
||||
|
||||
@@ -7,9 +7,9 @@ import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import com.aiosman.riderpro.data.AccountLikeEntity
|
||||
import com.aiosman.riderpro.entity.AccountLikeEntity
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.LikeItemPagingSource
|
||||
import com.aiosman.riderpro.entity.LikeItemPagingSource
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.api.ApiClient
|
||||
import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody
|
||||
|
||||
@@ -8,9 +8,9 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||
import com.aiosman.riderpro.entity.MomentServiceImpl
|
||||
import com.aiosman.riderpro.data.UploadImage
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.ui.modification.Modification
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -20,7 +20,7 @@ import java.io.InputStream
|
||||
|
||||
|
||||
object NewPostViewModel : ViewModel() {
|
||||
var momentService: MomentService = TestMomentServiceImpl()
|
||||
var momentService: MomentService = MomentServiceImpl()
|
||||
var textContent by mutableStateOf("")
|
||||
var searchPlaceAddressResult by mutableStateOf<SearchPlaceAddressResult?>(null)
|
||||
var modificationList by mutableStateOf<List<Modification>>(listOf())
|
||||
|
||||
@@ -61,9 +61,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
@@ -75,22 +73,22 @@ import com.aiosman.riderpro.LocalAnimatedContentScope
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.LocalSharedTransitionScope
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.CommentEntity
|
||||
import com.aiosman.riderpro.data.CommentPagingSource
|
||||
import com.aiosman.riderpro.entity.CommentEntity
|
||||
import com.aiosman.riderpro.entity.CommentPagingSource
|
||||
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.CommentService
|
||||
import com.aiosman.riderpro.data.TestCommentServiceImpl
|
||||
import com.aiosman.riderpro.data.CommentServiceImpl
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||
import com.aiosman.riderpro.entity.MomentServiceImpl
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.exp.formatPostTime
|
||||
import com.aiosman.riderpro.exp.timeAgo
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.model.MomentImageEntity
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentImageEntity
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
||||
@@ -106,9 +104,9 @@ import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object PostViewModel : ViewModel() {
|
||||
var service: MomentService = TestMomentServiceImpl()
|
||||
var commentService: CommentService = TestCommentServiceImpl()
|
||||
var userService: UserService = TestUserServiceImpl()
|
||||
var service: MomentService = MomentServiceImpl()
|
||||
var commentService: CommentService = CommentServiceImpl()
|
||||
var userService: UserService = UserServiceImpl()
|
||||
private var _commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
||||
val commentsFlow = _commentsFlow.asStateFlow()
|
||||
var postId: String = ""
|
||||
@@ -146,7 +144,7 @@ object PostViewModel : ViewModel() {
|
||||
suspend fun initData() {
|
||||
moment = service.getMomentById(postId.toInt())
|
||||
moment?.let {
|
||||
accountProfileEntity = accountService.getAccountProfileById(it.authorId)
|
||||
accountProfileEntity = userService.getUserProfile(it.authorId.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.aiosman.riderpro.data.AccountProfileEntity
|
||||
import com.aiosman.riderpro.data.MomentPagingSource
|
||||
import com.aiosman.riderpro.data.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
||||
import com.aiosman.riderpro.entity.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.entity.MomentServiceImpl
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.model.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.riderpro.ui.index.tabs.profile.CarGroup
|
||||
import com.aiosman.riderpro.ui.index.tabs.profile.MomentPostUnit
|
||||
@@ -36,9 +36,9 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun AccountProfile(id:String) {
|
||||
val userService: UserService = TestUserServiceImpl()
|
||||
val userService: UserService = UserServiceImpl()
|
||||
var userProfile by remember { mutableStateOf<AccountProfileEntity?>(null) }
|
||||
val momentService = TestMomentServiceImpl()
|
||||
val momentService = MomentServiceImpl()
|
||||
var momentsFlow by remember { mutableStateOf<Flow<PagingData<MomentEntity>>?>(null) }
|
||||
val scope = rememberCoroutineScope()
|
||||
LaunchedEffect(Unit) {
|
||||
|
||||
Reference in New Issue
Block a user