refactor(Search): 封装搜索框、结果列表等组件
This commit is contained in:
parent
d99f723cbc
commit
0207f830f7
|
|
@ -1,6 +1,5 @@
|
|||
package com.huanchengfly.tieba.post.ui.page.search
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
|
|
@ -14,7 +13,6 @@ import androidx.compose.foundation.layout.ColumnScope
|
|||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
|
|
@ -27,20 +25,16 @@ import androidx.compose.foundation.pager.PagerState
|
|||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.ProvideTextStyle
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Tab
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.Clear
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.ExpandLess
|
||||
import androidx.compose.material.icons.rounded.ExpandMore
|
||||
import androidx.compose.material.icons.rounded.Search
|
||||
|
|
@ -59,13 +53,11 @@ import androidx.compose.runtime.snapshotFlow
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.onFocusEvent
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
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
|
||||
|
|
@ -87,13 +79,13 @@ import com.huanchengfly.tieba.post.ui.page.search.thread.SearchThreadPage
|
|||
import com.huanchengfly.tieba.post.ui.page.search.thread.SearchThreadSortType
|
||||
import com.huanchengfly.tieba.post.ui.page.search.thread.SearchThreadUiEvent
|
||||
import com.huanchengfly.tieba.post.ui.page.search.user.SearchUserPage
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.BaseTextField
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Container
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoadHorizontalPager
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyBackHandler
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyScaffold
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.PagerTabIndicator
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.SearchBox
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.TabClickMenu
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.TabRow
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.TopAppBarContainer
|
||||
|
|
@ -269,8 +261,10 @@ fun SearchPage(
|
|||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
) { paddingValues ->
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)) {
|
||||
if (!isKeywordEmpty) {
|
||||
ProvideNavigator(navigator = navigator) {
|
||||
LazyLoadHorizontalPager(
|
||||
|
|
@ -562,20 +556,18 @@ private fun SearchTopBar(
|
|||
onKeywordSubmit: (String) -> Unit = {},
|
||||
onBack: () -> Unit = {},
|
||||
) {
|
||||
val isKeywordNotEmpty = remember(keyword) { keyword.isNotEmpty() }
|
||||
var isFocused by remember { mutableStateOf(false) }
|
||||
Surface(
|
||||
SearchBox(
|
||||
keyword = keyword,
|
||||
onKeywordChange = onKeywordChange,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
shape = RoundedCornerShape(6.dp),
|
||||
color = ExtendedTheme.colors.topBarSurface,
|
||||
contentColor = ExtendedTheme.colors.onTopBarSurface,
|
||||
elevation = 0.dp
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
onKeywordSubmit = onKeywordSubmit,
|
||||
placeholder = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.hint_search),
|
||||
color = ExtendedTheme.colors.onTopBarSurface.copy(alpha = ContentAlpha.medium)
|
||||
)
|
||||
},
|
||||
prependIcon = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(100))
|
||||
|
|
@ -588,76 +580,13 @@ private fun SearchTopBar(
|
|||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(id = R.string.button_back)
|
||||
)
|
||||
}
|
||||
BaseTextField(
|
||||
value = keyword,
|
||||
onValueChange = {
|
||||
onKeywordChange(it)
|
||||
},
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Search,
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onSearch = {
|
||||
onKeywordSubmit(keyword)
|
||||
}
|
||||
),
|
||||
placeholder = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.hint_search),
|
||||
color = ExtendedTheme.colors.onTopBarSurface.copy(alpha = ContentAlpha.medium)
|
||||
)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.onFocusEvent { isFocused = it.isFocused }
|
||||
)
|
||||
AnimatedVisibility(visible = isKeywordNotEmpty && isFocused) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(100))
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(bounded = false, 24.dp),
|
||||
role = Role.Button
|
||||
) { onKeywordChange("") },
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Clear,
|
||||
contentDescription = stringResource(id = R.string.button_clear)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(visible = isKeywordNotEmpty) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(100))
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(bounded = false, 24.dp),
|
||||
role = Role.Button
|
||||
) { onKeywordSubmit(keyword) },
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Search,
|
||||
contentDescription = stringResource(id = R.string.button_search)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
shape = RoundedCornerShape(6.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@Preview("SearchBox")
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
package com.huanchengfly.tieba.post.ui.page.search.thread
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.LocalContentColor
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
|
|
@ -20,8 +14,6 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.huanchengfly.tieba.post.api.models.SearchThreadBean
|
||||
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
||||
import com.huanchengfly.tieba.post.arch.onGlobalEvent
|
||||
import com.huanchengfly.tieba.post.arch.pageViewModel
|
||||
|
|
@ -32,24 +24,12 @@ import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
|
|||
import com.huanchengfly.tieba.post.ui.page.destinations.ThreadPageDestination
|
||||
import com.huanchengfly.tieba.post.ui.page.destinations.UserProfilePageDestination
|
||||
import com.huanchengfly.tieba.post.ui.page.search.SearchUiEvent
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Avatar
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Card
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ForumInfoChip
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LoadMoreLayout
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LocalShouldLoad
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyLazyColumn
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Sizes
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ThreadAgreeBtn
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ThreadContent
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ThreadReplyBtn
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ThreadShareBtn
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.UserHeader
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.SearchThreadList
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.states.StateScreen
|
||||
import com.huanchengfly.tieba.post.utils.DateTimeUtils
|
||||
import com.huanchengfly.tieba.post.utils.StringUtil
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
|
|
@ -59,7 +39,6 @@ fun SearchThreadPage(
|
|||
initialSortType: Int = SearchThreadSortType.SORT_TYPE_NEWEST,
|
||||
viewModel: SearchThreadViewModel = pageViewModel(),
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val navigator = LocalNavigator.current
|
||||
LazyLoad(loaded = viewModel.initialized) {
|
||||
viewModel.send(SearchThreadUiIntent.Refresh(keyword, initialSortType))
|
||||
|
|
@ -187,121 +166,3 @@ fun SearchThreadPage(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SearchThreadList(
|
||||
data: ImmutableList<SearchThreadBean.ThreadInfoBean>,
|
||||
lazyListState: LazyListState,
|
||||
onItemClick: (SearchThreadBean.ThreadInfoBean) -> Unit,
|
||||
onItemUserClick: (SearchThreadBean.UserInfoBean) -> Unit,
|
||||
onItemForumClick: (SearchThreadBean.ForumInfo) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
MyLazyColumn(
|
||||
state = lazyListState,
|
||||
modifier = modifier
|
||||
) {
|
||||
items(data) {
|
||||
SearchThreadItem(
|
||||
item = it,
|
||||
onClick = onItemClick,
|
||||
onUserClick = onItemUserClick,
|
||||
onForumClick = onItemForumClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SearchThreadUserHeader(
|
||||
user: SearchThreadBean.UserInfoBean,
|
||||
time: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
UserHeader(
|
||||
avatar = {
|
||||
Avatar(
|
||||
data = StringUtil.getAvatarUrl(user.portrait),
|
||||
size = Sizes.Small,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
name = {
|
||||
Text(
|
||||
text = StringUtil.getUsernameAnnotatedString(
|
||||
LocalContext.current,
|
||||
user.userName.orEmpty(),
|
||||
user.showNickname,
|
||||
color = LocalContentColor.current
|
||||
)
|
||||
)
|
||||
},
|
||||
desc = {
|
||||
Text(
|
||||
text = DateTimeUtils.getRelativeTimeString(LocalContext.current, time)
|
||||
)
|
||||
},
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SearchThreadItem(
|
||||
item: SearchThreadBean.ThreadInfoBean,
|
||||
onClick: (SearchThreadBean.ThreadInfoBean) -> Unit,
|
||||
onUserClick: (SearchThreadBean.UserInfoBean) -> Unit,
|
||||
onForumClick: (SearchThreadBean.ForumInfo) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier,
|
||||
header = {
|
||||
SearchThreadUserHeader(
|
||||
user = item.user,
|
||||
time = item.time,
|
||||
onClick = { onUserClick(item.user) }
|
||||
)
|
||||
},
|
||||
content = {
|
||||
ThreadContent(
|
||||
title = item.title,
|
||||
abstractText = item.content,
|
||||
showTitle = item.title.isNotBlank(),
|
||||
showAbstract = item.content.isNotBlank(),
|
||||
)
|
||||
if (item.forumName.isNotEmpty()) {
|
||||
ForumInfoChip(
|
||||
imageUriProvider = { item.forumInfo.avatar },
|
||||
nameProvider = { item.forumName }
|
||||
) {
|
||||
onForumClick(item.forumInfo)
|
||||
}
|
||||
}
|
||||
},
|
||||
action = {
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
ThreadReplyBtn(
|
||||
replyNum = item.postNum.toInt(),
|
||||
onClick = {},
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
ThreadAgreeBtn(
|
||||
hasAgree = false,
|
||||
agreeNum = item.likeNum.toInt(),
|
||||
onClick = {},
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
ThreadShareBtn(
|
||||
shareNum = item.shareNum.toLong(),
|
||||
onClick = {},
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = { onClick(item) },
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,274 @@
|
|||
package com.huanchengfly.tieba.post.ui.widgets.compose
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.LocalContentColor
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Clear
|
||||
import androidx.compose.material.icons.rounded.Search
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusEvent
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.huanchengfly.tieba.post.R
|
||||
import com.huanchengfly.tieba.post.api.models.SearchThreadBean
|
||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||
import com.huanchengfly.tieba.post.utils.DateTimeUtils
|
||||
import com.huanchengfly.tieba.post.utils.StringUtil
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
fun SearchThreadList(
|
||||
data: ImmutableList<SearchThreadBean.ThreadInfoBean>,
|
||||
lazyListState: LazyListState,
|
||||
onItemClick: (SearchThreadBean.ThreadInfoBean) -> Unit,
|
||||
onItemUserClick: (SearchThreadBean.UserInfoBean) -> Unit,
|
||||
onItemForumClick: (SearchThreadBean.ForumInfo) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
hideForum: Boolean = false,
|
||||
header: LazyListScope.() -> Unit = {},
|
||||
) {
|
||||
MyLazyColumn(
|
||||
state = lazyListState,
|
||||
modifier = modifier
|
||||
) {
|
||||
header()
|
||||
itemsIndexed(data) { index, item ->
|
||||
if (index > 0) {
|
||||
VerticalDivider(modifier = Modifier.padding(horizontal = 16.dp))
|
||||
}
|
||||
SearchThreadItem(
|
||||
item = item,
|
||||
onClick = onItemClick,
|
||||
onUserClick = onItemUserClick,
|
||||
onForumClick = onItemForumClick,
|
||||
hideForum = hideForum,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchThreadUserHeader(
|
||||
user: SearchThreadBean.UserInfoBean,
|
||||
time: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
UserHeader(
|
||||
avatar = {
|
||||
Avatar(
|
||||
data = StringUtil.getAvatarUrl(user.portrait),
|
||||
size = Sizes.Small,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
name = {
|
||||
Text(
|
||||
text = StringUtil.getUsernameAnnotatedString(
|
||||
LocalContext.current,
|
||||
user.userName.orEmpty(),
|
||||
user.showNickname,
|
||||
color = LocalContentColor.current
|
||||
)
|
||||
)
|
||||
},
|
||||
desc = {
|
||||
Text(
|
||||
text = DateTimeUtils.getRelativeTimeString(LocalContext.current, time)
|
||||
)
|
||||
},
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchThreadItem(
|
||||
item: SearchThreadBean.ThreadInfoBean,
|
||||
onClick: (SearchThreadBean.ThreadInfoBean) -> Unit,
|
||||
onUserClick: (SearchThreadBean.UserInfoBean) -> Unit,
|
||||
onForumClick: (SearchThreadBean.ForumInfo) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
hideForum: Boolean = false,
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier,
|
||||
header = {
|
||||
SearchThreadUserHeader(
|
||||
user = item.user,
|
||||
time = item.time,
|
||||
onClick = { onUserClick(item.user) }
|
||||
)
|
||||
},
|
||||
content = {
|
||||
ThreadContent(
|
||||
title = item.title,
|
||||
abstractText = item.content,
|
||||
showTitle = item.title.isNotBlank(),
|
||||
showAbstract = item.content.isNotBlank(),
|
||||
)
|
||||
if (!hideForum && item.forumName.isNotEmpty()) {
|
||||
ForumInfoChip(
|
||||
imageUriProvider = { item.forumInfo.avatar },
|
||||
nameProvider = { item.forumName }
|
||||
) {
|
||||
onForumClick(item.forumInfo)
|
||||
}
|
||||
}
|
||||
},
|
||||
action = {
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
ThreadReplyBtn(
|
||||
replyNum = item.postNum.toInt(),
|
||||
onClick = {},
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
ThreadAgreeBtn(
|
||||
hasAgree = false,
|
||||
agreeNum = item.likeNum.toInt(),
|
||||
onClick = {},
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
ThreadShareBtn(
|
||||
shareNum = item.shareNum.toLong(),
|
||||
onClick = {},
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = { onClick(item) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchBox(
|
||||
keyword: String,
|
||||
onKeywordChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onKeywordSubmit: (String) -> Unit = {},
|
||||
placeholder: @Composable () -> Unit = {},
|
||||
prependIcon: @Composable () -> Unit = {},
|
||||
appendIcon: @Composable () -> Unit = {},
|
||||
focusRequester: FocusRequester = remember { FocusRequester() },
|
||||
shape: Shape = RectangleShape,
|
||||
color: Color = ExtendedTheme.colors.topBarSurface,
|
||||
contentColor: Color = ExtendedTheme.colors.onTopBarSurface,
|
||||
elevation: Dp = 0.dp,
|
||||
) {
|
||||
val isKeywordNotEmpty = remember(keyword) { keyword.isNotEmpty() }
|
||||
var isFocused by remember { mutableStateOf(false) }
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
shape = shape,
|
||||
color = color,
|
||||
contentColor = contentColor,
|
||||
elevation = 0.dp
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
prependIcon()
|
||||
BaseTextField(
|
||||
value = keyword,
|
||||
onValueChange = {
|
||||
onKeywordChange(it)
|
||||
},
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Search,
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onSearch = {
|
||||
onKeywordSubmit(keyword)
|
||||
}
|
||||
),
|
||||
placeholder = placeholder,
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.focusRequester(focusRequester)
|
||||
.onFocusEvent {
|
||||
isFocused = it.isFocused
|
||||
}
|
||||
)
|
||||
appendIcon()
|
||||
AnimatedVisibility(visible = isKeywordNotEmpty && isFocused) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(100))
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(bounded = false, 24.dp),
|
||||
role = Role.Button
|
||||
) { onKeywordChange("") },
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Clear,
|
||||
contentDescription = stringResource(id = R.string.button_clear)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(visible = isKeywordNotEmpty) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(100))
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(bounded = false, 24.dp),
|
||||
role = Role.Button
|
||||
) { onKeywordSubmit(keyword) },
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Search,
|
||||
contentDescription = stringResource(id = R.string.button_search)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue