更新
This commit is contained in:
@@ -30,7 +30,7 @@ fun RelPostCard(
|
||||
image?.let {
|
||||
CustomAsyncImage(
|
||||
context,
|
||||
image,
|
||||
image.thumbnail,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(100.dp),
|
||||
contentScale = ContentScale.Crop
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -54,7 +54,7 @@ fun ImageViewer() {
|
||||
with(sharedTransitionScope) {
|
||||
CustomAsyncImage(
|
||||
context,
|
||||
images[page],
|
||||
images[page].url,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.sharedElement(
|
||||
rememberSharedContentState(key = images[page]),
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
)
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user