This commit is contained in:
2024-08-17 17:40:21 +08:00
parent e8140579e0
commit 6137e1c3b5
18 changed files with 494 additions and 63 deletions

View File

@@ -1,10 +1,13 @@
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.ChangePasswordRequestBody
import com.aiosman.riderpro.data.api.LoginUserRequestBody
import com.aiosman.riderpro.data.api.RegisterRequestBody
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.test.TestDatabase
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
@@ -12,6 +15,7 @@ import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.IOException
data class AccountProfileEntity(
val id: Int,

View File

@@ -6,6 +6,7 @@ import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.api.ApiClient
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.model.MomentImageEntity
import com.aiosman.riderpro.test.TestDatabase
import com.google.gson.annotations.SerializedName
@@ -57,7 +58,13 @@ data class Moment(
commentCount = commentCount.toInt(),
shareCount = 0,
favoriteCount = favoriteCount.toInt(),
images = images.map { ApiClient.BASE_SERVER + it.url + "?token=${AppStore.token}" },
images = images.map {
MomentImageEntity(
url = ApiClient.BASE_SERVER + it.url + "?token=${AppStore.token}",
thumbnail = ApiClient.BASE_SERVER + it.thumbnail + "?token=${AppStore.token}",
id = it.id
)
},
authorId = user.id.toInt(),
liked = isLiked,
isFavorite = isFavorite
@@ -82,12 +89,14 @@ data class User(
@SerializedName("avatar")
val avatar: String
)
data class UploadImage(
val file: File,
val filename: String,
val url: String,
val ext: String
)
interface MomentService {
suspend fun getMomentById(id: Int): MomentEntity
suspend fun likeMoment(id: Int)
@@ -95,7 +104,8 @@ interface MomentService {
suspend fun getMoments(
pageNumber: Int,
author: Int? = null,
timelineId: Int? = null
timelineId: Int? = null,
contentSearch: String? = null
): ListContainer<MomentEntity>
suspend fun createMoment(
@@ -104,6 +114,7 @@ interface MomentService {
images: List<UploadImage>,
relPostId: Int? = null
): MomentEntity
suspend fun favoriteMoment(id: Int)
suspend fun unfavoriteMoment(id: Int)
}
@@ -112,7 +123,8 @@ interface MomentService {
class MomentPagingSource(
private val remoteDataSource: MomentRemoteDataSource,
private val author: Int? = null,
private val timelineId: 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 {
@@ -120,7 +132,8 @@ class MomentPagingSource(
val moments = remoteDataSource.getMoments(
pageNumber = currentPage,
author = author,
timelineId = timelineId
timelineId = timelineId,
contentSearch = contentSearch
)
LoadResult.Page(
@@ -145,9 +158,10 @@ class MomentRemoteDataSource(
suspend fun getMoments(
pageNumber: Int,
author: Int?,
timelineId: Int?
timelineId: Int?,
contentSearch: String?
): ListContainer<MomentEntity> {
return momentService.getMoments(pageNumber, author, timelineId)
return momentService.getMoments(pageNumber, author, timelineId, contentSearch)
}
}
@@ -158,9 +172,10 @@ class TestMomentServiceImpl() : MomentService {
override suspend fun getMoments(
pageNumber: Int,
author: Int?,
timelineId: Int?
timelineId: Int?,
contentSearch: String?
): ListContainer<MomentEntity> {
return testMomentBackend.fetchMomentItems(pageNumber, author, timelineId)
return testMomentBackend.fetchMomentItems(pageNumber, author, timelineId, contentSearch)
}
override suspend fun getMomentById(id: Int): MomentEntity {
@@ -202,13 +217,15 @@ class TestMomentBackend(
suspend fun fetchMomentItems(
pageNumber: Int,
author: Int? = null,
timelineId: Int?
timelineId: Int?,
contentSearch: String?
): ListContainer<MomentEntity> {
val resp = ApiClient.api.getPosts(
pageSize = DataBatchSize,
page = pageNumber,
timelineId = timelineId,
authorId = author
authorId = author,
contentSearch = contentSearch
)
val body = resp.body() ?: throw ServiceException("Failed to get moments")
return ListContainer(
@@ -258,6 +275,7 @@ class TestMomentBackend(
suspend fun favoriteMoment(id: Int) {
ApiClient.api.favoritePost(id)
}
suspend fun unfavoriteMoment(id: Int) {
ApiClient.api.unfavoritePost(id)
}

View File

@@ -1,17 +1,53 @@
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
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
}
}
interface UserService {
suspend fun getUserProfile(id: String): AccountProfileEntity
suspend fun followUser(id: String)
suspend fun unFollowUser(id: String)
suspend fun getUsers(
pageSize: Int = 20,
page: Int = 1,
nickname: String? = null
): ListContainer<AccountProfileEntity>
}
@@ -31,4 +67,19 @@ class TestUserServiceImpl : UserService {
val resp = ApiClient.api.unfollowUser(id.toInt())
return
}
override suspend fun getUsers(
pageSize: Int,
page: Int,
nickname: String?
): ListContainer<AccountProfileEntity> {
val resp = ApiClient.api.getUsers(page, pageSize, nickname)
val body = resp.body() ?: throw ServiceException("Failed to get account")
return ListContainer<AccountProfileEntity>(
list = body.list.map { it.toAccountProfileEntity() },
page = body.page,
total = body.total,
pageSize = body.pageSize
)
}
}

View File

@@ -75,6 +75,7 @@ interface RiderProAPI {
@Query("pageSize") pageSize: Int = 20,
@Query("timelineId") timelineId: Int? = null,
@Query("authorId") authorId: Int? = null,
@Query("contentSearch") contentSearch: String? = null,
): Response<ListContainer<Moment>>
@Multipart
@@ -163,4 +164,11 @@ interface RiderProAPI {
@Path("id") id: Int
): Response<Unit>
@GET("users")
suspend fun getUsers(
@Query("page") page: Int = 1,
@Query("pageSize") pageSize: Int = 20,
@Query("nickname") search: String? = null,
): Response<ListContainer<AccountProfile>>
}

View File

@@ -1,7 +1,11 @@
package com.aiosman.riderpro.model
import androidx.annotation.DrawableRes
data class MomentImageEntity(
val id: Long,
val url: String,
val thumbnail: String
)
data class MomentEntity(
val id: Int,
val avatar: String,
@@ -15,7 +19,7 @@ data class MomentEntity(
val commentCount: Int,
val shareCount: Int,
val favoriteCount: Int,
val images: List<String> = emptyList(),
val images: List<MomentImageEntity> = emptyList(),
val authorId: Int = 0,
var liked: Boolean = false,
var relPostId: Int? = null,

View File

@@ -4,6 +4,7 @@ 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
@@ -124,7 +125,13 @@ object TestDatabase {
commentCount = commentCount + 1,
shareCount = faker.random.nextInt(0, 100),
favoriteCount = faker.random.nextInt(0, 100),
images = imageList.shuffled().take(3),
images = imageList.shuffled().take(3).map {
MomentImageEntity(
id = faker.random.nextLong(),
url = it,
thumbnail = it
)
},
authorId = person.id
)
}

View File

@@ -30,7 +30,7 @@ fun RelPostCard(
image?.let {
CustomAsyncImage(
context,
image,
image.thumbnail,
contentDescription = null,
modifier = Modifier.size(100.dp),
contentScale = ContentScale.Crop

View File

@@ -1,9 +1,11 @@
package com.aiosman.riderpro.ui.imageviewer
import com.aiosman.riderpro.model.MomentImageEntity
object ImageViewerViewModel {
var imageList = mutableListOf<String>()
var imageList = mutableListOf<MomentImageEntity>()
var initialIndex = 0
fun asNew(images: List<String>, index: Int = 0) {
fun asNew(images: List<MomentImageEntity>, index: Int = 0) {
imageList.clear()
imageList.addAll(images)
initialIndex = index

View File

@@ -54,7 +54,7 @@ fun ImageViewer() {
with(sharedTransitionScope) {
CustomAsyncImage(
context,
images[page],
images[page].url,
contentDescription = null,
modifier = Modifier.sharedElement(
rememberSharedContentState(key = images[page]),

View File

@@ -28,6 +28,7 @@ import androidx.compose.ui.unit.dp
import com.aiosman.riderpro.ui.index.tabs.add.AddPage
import com.aiosman.riderpro.ui.index.tabs.moment.MomentsList
import com.aiosman.riderpro.ui.index.tabs.profile.ProfilePage
import com.aiosman.riderpro.ui.index.tabs.search.SearchScreen
import com.aiosman.riderpro.ui.index.tabs.shorts.ShortVideo
import com.aiosman.riderpro.ui.index.tabs.street.StreetPage
import com.google.accompanist.systemuicontroller.rememberSystemUiController
@@ -40,9 +41,10 @@ fun IndexScreen() {
}
val item = listOf(
NavigationItem.Home,
NavigationItem.Street,
NavigationItem.Search,
// NavigationItem.Street,
NavigationItem.Add,
NavigationItem.Message,
// NavigationItem.Message,
NavigationItem.Profile
)
val systemUiController = rememberSystemUiController()
@@ -99,17 +101,22 @@ fun IndexScreen() {
) {
Home()
}
1 -> Box(
modifier = Modifier.padding(innerPadding)
) {
SearchScreen()
}
1 -> Street()
// 1 -> Street()
2 -> Box(
modifier = Modifier.padding(innerPadding)
) { Add() }
3 -> Box(
modifier = Modifier.padding(innerPadding)
) { Video() }
// 3 -> Box(
// modifier = Modifier.padding(innerPadding)
// ) { Video() }
4 -> Box(
3 -> Box(
modifier = Modifier.padding(innerPadding)
) { Profile() }
}

View File

@@ -1,5 +1,8 @@
package com.aiosman.riderpro.ui.index
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
@@ -34,4 +37,9 @@ sealed class NavigationItem(
icon = { ImageVector.vectorResource(R.drawable.rider_pro_profile) },
selectedIcon = { ImageVector.vectorResource(R.drawable.rider_pro_profile_filed) }
)
data object Search : NavigationItem("Search",
icon = { Icons.Default.Search },
selectedIcon = { Icons.Default.Search }
)
}

View File

@@ -34,7 +34,7 @@ fun AddPage(){
NewPostViewModel.asNewPost()
navController.navigate("NewPost")
}
AddBtn(icon = R.drawable.rider_pro_location_create, text = "Location Create")
// AddBtn(icon = R.drawable.rider_pro_location_create, text = "Location Create")
}
}

View File

@@ -131,9 +131,10 @@ fun MomentsList() {
@Composable
fun MomentCard(
momentEntity: MomentEntity,
onLikeClick: () -> Unit,
onLikeClick: () -> Unit = {},
onFavoriteClick: () -> Unit = {},
onAddComment: () -> Unit = {}
onAddComment: () -> Unit = {},
hideAction: Boolean = false
) {
val navController = LocalNavController.current
Column(
@@ -153,18 +154,21 @@ fun MomentCard(
.fillMaxHeight()
.weight(1f)
// ModificationListHeader()
MomentBottomOperateRowGroup(
momentOperateBtnBoxModifier,
momentEntity = momentEntity,
onLikeClick = onLikeClick,
onAddComment = onAddComment,
onShareClick = {
NewPostViewModel.asNewPost()
NewPostViewModel.relPostId = momentEntity.id
navController.navigate(NavigationRoute.NewPost.route)
},
onFavoriteClick = onFavoriteClick
)
if (!hideAction){
MomentBottomOperateRowGroup(
momentOperateBtnBoxModifier,
momentEntity = momentEntity,
onLikeClick = onLikeClick,
onAddComment = onAddComment,
onShareClick = {
NewPostViewModel.asNewPost()
NewPostViewModel.relPostId = momentEntity.id
navController.navigate(NavigationRoute.NewPost.route)
},
onFavoriteClick = onFavoriteClick
)
}
}
}
@@ -342,7 +346,7 @@ fun MomentContentGroup(
with(sharedTransitionScope) {
CustomAsyncImage(
context,
it,
it.thumbnail,
modifier = Modifier
.sharedElement(
rememberSharedContentState(key = it),

View File

@@ -396,26 +396,26 @@ fun CommunicationOperatorGroup(
style = TextStyle(fontWeight = FontWeight.Bold)
)
}
Box(
modifier = Modifier
.size(width = 142.dp, height = 40.dp)
.clickable {
navController.navigate("ProfileTimeline")
},
contentAlignment = Alignment.Center
) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.rider_pro_profile_follow),
contentDescription = ""
)
Text(
text = "GALLERY",
fontSize = 16.sp,
color = Color.White,
style = TextStyle(fontWeight = FontWeight.Bold)
)
}
// Box(
// modifier = Modifier
// .size(width = 142.dp, height = 40.dp)
// .clickable {
// navController.navigate("ProfileTimeline")
// },
// contentAlignment = Alignment.Center
// ) {
// Image(
// modifier = Modifier.fillMaxSize(),
// painter = painterResource(id = R.drawable.rider_pro_profile_follow),
// contentDescription = ""
// )
// Text(
// text = "GALLERY",
// fontSize = 16.sp,
// color = Color.White,
// style = TextStyle(fontWeight = FontWeight.Bold)
// )
// }
}
}
@@ -504,7 +504,7 @@ fun MomentPostUnit(momentEntity: MomentEntity) {
TimeGroup(momentEntity.time)
ProfileMomentCard(
momentEntity.momentTextContent,
momentEntity.images[0],
momentEntity.images[0].thumbnail,
momentEntity.likeCount.toString(),
momentEntity.commentCount.toString(),
momentId = momentEntity.id

View File

@@ -0,0 +1,250 @@
package com.aiosman.riderpro.ui.index.tabs.search
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Icon
import androidx.compose.material.Tab
import androidx.compose.material.TabRow
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.tooling.preview.Preview
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.ui.composables.CustomAsyncImage
import com.aiosman.riderpro.ui.index.tabs.moment.MomentCard
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.launch
@OptIn(ExperimentalFoundationApi::class)
@Preview
@Composable
fun SearchScreen() {
val model = SearchViewModel
val categories = listOf("Moment", "User")
val coroutineScope = rememberCoroutineScope()
val pagerState = rememberPagerState(pageCount = { categories.size })
val selectedTabIndex = remember { derivedStateOf { pagerState.currentPage } }
val keyboardController = LocalSoftwareKeyboardController.current
val systemUiController = rememberSystemUiController()
LaunchedEffect(Unit) {
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = true)
}
Column(
modifier = Modifier
.background(Color.White)
.fillMaxSize()
.padding(start = 16.dp, end = 16.dp, top = 24.dp)
) {
SearchInput(
modifier = Modifier.fillMaxWidth(),
text = model.searchText,
onTextChange = {
model.searchText = it
},
onSearch = {
model.search()
// hide ime
keyboardController?.hide() // Hide the keyboard
}
)
if (model.showResult) {
Spacer(modifier = Modifier.padding(8.dp))
TabRow(
selectedTabIndex = selectedTabIndex.value,
backgroundColor = Color.White,
) {
categories.forEachIndexed { index, category ->
Tab(
selected = selectedTabIndex.value == index,
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
text = { Text(category) }
)
}
}
SearchPager(
pagerState = pagerState
)
}
}
}
@Composable
fun SearchInput(
modifier: Modifier = Modifier,
text: String = "",
onTextChange: (String) -> Unit = {},
onSearch: () -> Unit = {}
) {
Box(
modifier = modifier
.clip(shape = RoundedCornerShape(8.dp))
.background(Color(0xFFEEEEEE))
.padding(horizontal = 16.dp, vertical = 16.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
Icons.Default.Search,
contentDescription = null
)
Box {
if (text.isEmpty()) {
Text(
text = "Search",
modifier = Modifier.padding(start = 8.dp),
color = Color(0xFF9E9E9E),
fontSize = 18.sp
)
}
BasicTextField(
value = text,
onValueChange = {
onTextChange(it)
},
modifier = Modifier
.padding(start = 8.dp)
.fillMaxWidth(),
singleLine = true,
textStyle = TextStyle(
fontSize = 18.sp
),
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Search
),
keyboardActions = KeyboardActions(
onSearch = {
onSearch()
}
)
)
}
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun SearchPager(
pagerState: PagerState,
) {
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxSize(),
) { page ->
when (page) {
0 -> MomentResultTab()
1 -> UserResultTab()
}
}
}
@Composable
fun MomentResultTab() {
val model = SearchViewModel
var dataFlow = model.momentsFlow
var moments = dataFlow.collectAsLazyPagingItems()
Box(
modifier = Modifier.fillMaxSize()
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
) {
items(moments.itemCount) { idx ->
val momentItem = moments[idx] ?: return@items
Spacer(modifier = Modifier.padding(8.dp))
MomentCard(momentEntity = momentItem, hideAction = true)
}
}
}
}
@Composable
fun UserResultTab() {
val model = SearchViewModel
val users = model.usersFlow.collectAsLazyPagingItems()
Box(
modifier = Modifier.fillMaxSize()
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
) {
items(users.itemCount) { idx ->
val userItem = users[idx] ?: return@items
UserItem(userItem)
}
}
}
}
@Composable
fun UserItem(accountProfile: AccountProfileEntity) {
val context = LocalContext.current
val navController = LocalNavController.current
Row(
modifier = Modifier.fillMaxWidth().padding(16.dp).noRippleClickable {
navController.navigate("AccountProfile/${accountProfile.id}")
},
verticalAlignment = Alignment.CenterVertically
) {
CustomAsyncImage(
context,
imageUrl = accountProfile.avatar,
modifier = Modifier
.size(64.dp)
.clip(CircleShape),
contentDescription = null
)
Spacer(modifier = Modifier.padding(16.dp))
Text(text = accountProfile.nickName, fontSize = 18.sp, fontWeight = FontWeight.Bold)
}
}

View File

@@ -0,0 +1,66 @@
package com.aiosman.riderpro.ui.index.tabs.search
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
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.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 kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
object SearchViewModel : ViewModel() {
var searchText by mutableStateOf("")
private val momentService: MomentService = TestMomentServiceImpl()
private val _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
val momentsFlow = _momentsFlow.asStateFlow()
private val userService = TestUserServiceImpl()
private val _usersFlow = MutableStateFlow<PagingData<AccountProfileEntity>>(PagingData.empty())
val usersFlow = _usersFlow.asStateFlow()
var showResult by mutableStateOf(false)
fun search() {
viewModelScope.launch {
Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
MomentPagingSource(
MomentRemoteDataSource(momentService),
contentSearch = searchText
)
}
).flow.cachedIn(viewModelScope).collectLatest {
_momentsFlow.value = it
}
}
viewModelScope.launch {
Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
AccountPagingSource(
userService,
nickname = searchText
)
}
).flow.cachedIn(viewModelScope).collectLatest {
_usersFlow.value = it
}
}
showResult = true
}
}

View File

@@ -88,6 +88,7 @@ import com.aiosman.riderpro.data.TestMomentServiceImpl
import com.aiosman.riderpro.data.TestUserServiceImpl
import com.aiosman.riderpro.data.UserService
import com.aiosman.riderpro.model.MomentEntity
import com.aiosman.riderpro.model.MomentImageEntity
import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
@@ -426,7 +427,7 @@ fun Header(
@Composable
fun PostImageView(
postId: String,
images: List<String>,
images: List<MomentImageEntity>,
) {
val pagerState = rememberPagerState(pageCount = { images.size })
val navController = LocalNavController.current
@@ -445,7 +446,7 @@ fun PostImageView(
with(sharedTransitionScope) {
CustomAsyncImage(
context,
image,
image.thumbnail,
contentDescription = "Image",
contentScale = ContentScale.Fit,
modifier = Modifier

View File

@@ -18,6 +18,7 @@ object Utils {
.okHttpClient(okHttpClient)
.diskCachePolicy(CachePolicy.ENABLED)
.memoryCachePolicy(CachePolicy.ENABLED)
.components {
}