feat: 用户资料界面 Pad 适配
This commit is contained in:
parent
bb80c7055d
commit
cfdfe9597b
|
|
@ -201,7 +201,7 @@ private fun ThreadList(
|
||||||
}
|
}
|
||||||
MyLazyColumn(
|
MyLazyColumn(
|
||||||
state = state,
|
state = state,
|
||||||
// horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
contentPadding = WindowInsets.navigationBars.asPaddingValues()
|
contentPadding = WindowInsets.navigationBars.asPaddingValues()
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
|
@ -68,6 +69,7 @@ import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.util.fastForEachIndexed
|
import androidx.compose.ui.util.fastForEachIndexed
|
||||||
import com.huanchengfly.tieba.post.R
|
import com.huanchengfly.tieba.post.R
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.User
|
import com.huanchengfly.tieba.post.api.models.protos.User
|
||||||
|
import com.huanchengfly.tieba.post.arch.BaseComposeActivity.Companion.LocalWindowSizeClass
|
||||||
import com.huanchengfly.tieba.post.arch.GlobalEvent
|
import com.huanchengfly.tieba.post.arch.GlobalEvent
|
||||||
import com.huanchengfly.tieba.post.arch.ImmutableHolder
|
import com.huanchengfly.tieba.post.arch.ImmutableHolder
|
||||||
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
||||||
|
|
@ -78,6 +80,7 @@ import com.huanchengfly.tieba.post.goToActivity
|
||||||
import com.huanchengfly.tieba.post.models.database.Block
|
import com.huanchengfly.tieba.post.models.database.Block
|
||||||
import com.huanchengfly.tieba.post.toastShort
|
import com.huanchengfly.tieba.post.toastShort
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||||
|
import com.huanchengfly.tieba.post.ui.common.windowsizeclass.WindowWidthSizeClass
|
||||||
import com.huanchengfly.tieba.post.ui.page.ProvideNavigator
|
import com.huanchengfly.tieba.post.ui.page.ProvideNavigator
|
||||||
import com.huanchengfly.tieba.post.ui.page.editprofile.view.EditProfileActivity
|
import com.huanchengfly.tieba.post.ui.page.editprofile.view.EditProfileActivity
|
||||||
import com.huanchengfly.tieba.post.ui.page.user.likeforum.UserLikeForumPage
|
import com.huanchengfly.tieba.post.ui.page.user.likeforum.UserLikeForumPage
|
||||||
|
|
@ -114,7 +117,6 @@ import kotlin.math.absoluteValue
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Destination
|
@Destination
|
||||||
@Composable
|
@Composable
|
||||||
fun UserProfilePage(
|
fun UserProfilePage(
|
||||||
|
|
@ -123,9 +125,6 @@ fun UserProfilePage(
|
||||||
viewModel: UserProfileViewModel = pageViewModel(),
|
viewModel: UserProfileViewModel = pageViewModel(),
|
||||||
) {
|
) {
|
||||||
val account = LocalAccount.current
|
val account = LocalAccount.current
|
||||||
val context = LocalContext.current
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val density = LocalDensity.current
|
|
||||||
|
|
||||||
val isSelf = remember(account, uid) {
|
val isSelf = remember(account, uid) {
|
||||||
account?.uid == uid.toString()
|
account?.uid == uid.toString()
|
||||||
|
|
@ -160,21 +159,6 @@ fun UserProfilePage(
|
||||||
derivedStateOf { user == null }
|
derivedStateOf { user == null }
|
||||||
}
|
}
|
||||||
|
|
||||||
var heightOffset by rememberSaveable { mutableFloatStateOf(0f) }
|
|
||||||
var headerHeight by rememberSaveable {
|
|
||||||
mutableFloatStateOf(
|
|
||||||
with(density) {
|
|
||||||
(96.dp + 16.dp).toPx()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val isShowHeaderArea by remember {
|
|
||||||
derivedStateOf {
|
|
||||||
heightOffset.absoluteValue < headerHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProvideNavigator(navigator = navigator) {
|
ProvideNavigator(navigator = navigator) {
|
||||||
StateScreen(
|
StateScreen(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
|
@ -184,24 +168,93 @@ fun UserProfilePage(
|
||||||
onReload = { viewModel.send(UserProfileUiIntent.Refresh(uid)) },
|
onReload = { viewModel.send(UserProfileUiIntent.Refresh(uid)) },
|
||||||
errorScreen = { ErrorScreen(error = error.getOrNull()) }
|
errorScreen = { ErrorScreen(error = error.getOrNull()) }
|
||||||
) {
|
) {
|
||||||
MyScaffold(
|
user?.let {
|
||||||
topBar = {
|
UserProfileContent(
|
||||||
|
user = it,
|
||||||
|
showActionBtn = account != null,
|
||||||
|
disableButton = disableButton,
|
||||||
|
isSelf = isSelf,
|
||||||
|
onBack = { navigator.navigateUp() },
|
||||||
|
onFollow = {
|
||||||
|
viewModel.send(
|
||||||
|
UserProfileUiIntent.Follow(
|
||||||
|
it.get { portrait },
|
||||||
|
account!!.tbs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onUnfollow = {
|
||||||
|
viewModel.send(
|
||||||
|
UserProfileUiIntent.Unfollow(
|
||||||
|
it.get { portrait },
|
||||||
|
account!!.tbs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun UserProfileContent(
|
||||||
|
user: ImmutableHolder<User>,
|
||||||
|
showActionBtn: Boolean,
|
||||||
|
disableButton: Boolean,
|
||||||
|
isSelf: Boolean,
|
||||||
|
onBack: () -> Unit,
|
||||||
|
onFollow: () -> Unit,
|
||||||
|
onUnfollow: () -> Unit,
|
||||||
|
) {
|
||||||
|
when (LocalWindowSizeClass.current.widthSizeClass) {
|
||||||
|
WindowWidthSizeClass.Expanded -> {
|
||||||
|
UserProfileContentExpanded(
|
||||||
|
user = user,
|
||||||
|
showActionBtn = showActionBtn,
|
||||||
|
disableButton = disableButton,
|
||||||
|
isSelf = isSelf,
|
||||||
|
onBack = onBack,
|
||||||
|
onFollow = onFollow,
|
||||||
|
onUnfollow = onUnfollow
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
UserProfileContentNormal(
|
||||||
|
user = user,
|
||||||
|
showActionBtn = showActionBtn,
|
||||||
|
disableButton = disableButton,
|
||||||
|
isSelf = isSelf,
|
||||||
|
onBack = onBack,
|
||||||
|
onFollow = onFollow,
|
||||||
|
onUnfollow = onUnfollow
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun UserProfileToolbar(
|
||||||
|
user: ImmutableHolder<User>,
|
||||||
|
isSelf: Boolean,
|
||||||
|
showTitle: Boolean,
|
||||||
|
onBack: () -> Unit,
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
Toolbar(
|
Toolbar(
|
||||||
title = {
|
title = {
|
||||||
user?.let {
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = !isShowHeaderArea,
|
visible = showTitle,
|
||||||
enter = fadeIn(),
|
enter = fadeIn(),
|
||||||
exit = fadeOut()
|
exit = fadeOut()
|
||||||
) {
|
) {
|
||||||
ToolbarUserTitle(user = it)
|
ToolbarUserTitle(user = user)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
BackNavigationIcon {
|
BackNavigationIcon(onBackPressed = onBack)
|
||||||
navigator.navigateUp()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
user.takeUnless { isSelf }?.let {
|
user.takeUnless { isSelf }?.let {
|
||||||
|
|
@ -256,6 +309,47 @@ fun UserProfilePage(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun UserProfileContentNormal(
|
||||||
|
user: ImmutableHolder<User>,
|
||||||
|
showActionBtn: Boolean,
|
||||||
|
disableButton: Boolean,
|
||||||
|
isSelf: Boolean,
|
||||||
|
onBack: () -> Unit,
|
||||||
|
onFollow: () -> Unit,
|
||||||
|
onUnfollow: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val density = LocalDensity.current
|
||||||
|
|
||||||
|
var heightOffset by rememberSaveable { mutableFloatStateOf(0f) }
|
||||||
|
var headerHeight by rememberSaveable {
|
||||||
|
mutableFloatStateOf(
|
||||||
|
with(density) {
|
||||||
|
(96.dp + 16.dp).toPx()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val isShowHeaderArea by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
heightOffset.absoluteValue < headerHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyScaffold(
|
||||||
|
topBar = {
|
||||||
|
UserProfileToolbar(
|
||||||
|
user = user,
|
||||||
|
isSelf = isSelf,
|
||||||
|
showTitle = !isShowHeaderArea,
|
||||||
|
onBack = onBack
|
||||||
|
)
|
||||||
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
var isFakeRefreshing by remember { mutableStateOf(false) }
|
var isFakeRefreshing by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
|
@ -316,7 +410,6 @@ fun UserProfilePage(
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
.nestedScroll(headerNestedScrollConnection)
|
.nestedScroll(headerNestedScrollConnection)
|
||||||
) {
|
) {
|
||||||
user?.let { holder ->
|
|
||||||
val pages = remember {
|
val pages = remember {
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
UserProfilePageData(
|
UserProfilePageData(
|
||||||
|
|
@ -327,10 +420,11 @@ fun UserProfilePage(
|
||||||
it.get { thread_num }.getShortNumString()
|
it.get { thread_num }.getShortNumString()
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = {
|
content = { user, fluid ->
|
||||||
UserPostPage(
|
UserPostPage(
|
||||||
uid = it.get { id },
|
uid = user.get { id },
|
||||||
isThread = true
|
isThread = true,
|
||||||
|
fluid = fluid,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
@ -342,10 +436,11 @@ fun UserProfilePage(
|
||||||
it.get { post_num }.getShortNumString()
|
it.get { post_num }.getShortNumString()
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = {
|
content = { user, fluid ->
|
||||||
UserPostPage(
|
UserPostPage(
|
||||||
uid = uid,
|
uid = user.get { id },
|
||||||
isThread = false
|
isThread = false,
|
||||||
|
fluid = fluid,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
).takeIf { isSelf },
|
).takeIf { isSelf },
|
||||||
|
|
@ -357,8 +452,11 @@ fun UserProfilePage(
|
||||||
it.get { my_like_num }.toString()
|
it.get { my_like_num }.toString()
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = {
|
content = { user, fluid ->
|
||||||
UserLikeForumPage(uid = it.get { id })
|
UserLikeForumPage(
|
||||||
|
uid = user.get { id },
|
||||||
|
fluid = fluid,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
).toImmutableList()
|
).toImmutableList()
|
||||||
|
|
@ -378,52 +476,47 @@ fun UserProfilePage(
|
||||||
.height(containerHeight)
|
.height(containerHeight)
|
||||||
.clipToBounds()
|
.clipToBounds()
|
||||||
) {
|
) {
|
||||||
UserProfileDetail(
|
Box(
|
||||||
user = holder,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp)
|
|
||||||
.wrapContentHeight(
|
.wrapContentHeight(
|
||||||
align = Alignment.Bottom,
|
align = Alignment.Bottom,
|
||||||
unbounded = true
|
unbounded = true
|
||||||
)
|
)
|
||||||
.onSizeChanged {
|
.onSizeChanged {
|
||||||
headerHeight = it.height.toFloat()
|
headerHeight = it.height.toFloat()
|
||||||
},
|
}
|
||||||
showBtn = account != null,
|
) {
|
||||||
|
UserProfileDetail(
|
||||||
|
user = user,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.padding(top = 8.dp),
|
||||||
|
showBtn = showActionBtn,
|
||||||
isSelf = isSelf,
|
isSelf = isSelf,
|
||||||
onBtnClick = {
|
onBtnClick = {
|
||||||
if (disableButton || account == null) {
|
if (disableButton || !showActionBtn) {
|
||||||
return@UserProfileDetail
|
return@UserProfileDetail
|
||||||
}
|
}
|
||||||
if (isSelf) {
|
if (isSelf) {
|
||||||
context.goToActivity<EditProfileActivity>()
|
context.goToActivity<EditProfileActivity>()
|
||||||
} else if (holder.get { has_concerned } == 0) {
|
} else if (user.get { has_concerned } == 0) {
|
||||||
viewModel.send(
|
onFollow()
|
||||||
UserProfileUiIntent.Follow(
|
|
||||||
holder.get { portrait },
|
|
||||||
account.tbs,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
viewModel.send(
|
onUnfollow()
|
||||||
UserProfileUiIntent.Unfollow(
|
|
||||||
holder.get { portrait },
|
|
||||||
account.tbs,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onCopyIdClick = {
|
onCopyIdClick = {
|
||||||
TiebaUtil.copyText(
|
TiebaUtil.copyText(
|
||||||
context,
|
context,
|
||||||
holder.get { id }.toString()
|
user.get { id }.toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UserProfileTabRow(
|
UserProfileTabRow(
|
||||||
user = holder,
|
user = user,
|
||||||
pages = pages,
|
pages = pages,
|
||||||
pagerState = pagerState,
|
pagerState = pagerState,
|
||||||
// modifier = Modifier.padding(horizontal = 16.dp)
|
// modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
|
@ -434,13 +527,152 @@ fun UserProfilePage(
|
||||||
key = { pages[it].id },
|
key = { pages[it].id },
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
pages[it].content(holder)
|
pages[it].content(user, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun UserProfileContentExpanded(
|
||||||
|
user: ImmutableHolder<User>,
|
||||||
|
showActionBtn: Boolean,
|
||||||
|
disableButton: Boolean,
|
||||||
|
isSelf: Boolean,
|
||||||
|
onBack: () -> Unit,
|
||||||
|
onFollow: () -> Unit,
|
||||||
|
onUnfollow: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
MyScaffold(
|
||||||
|
topBar = {
|
||||||
|
UserProfileToolbar(
|
||||||
|
user = user,
|
||||||
|
isSelf = isSelf,
|
||||||
|
showTitle = false,
|
||||||
|
onBack = onBack
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { paddingValues ->
|
||||||
|
ProvideContentColor(color = ExtendedTheme.colors.text) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(paddingValues)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.fillMaxWidth(0.75f)
|
||||||
|
.align(Alignment.TopCenter),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
val pages = remember {
|
||||||
|
listOfNotNull(
|
||||||
|
UserProfilePageData(
|
||||||
|
id = "threads",
|
||||||
|
title = {
|
||||||
|
stringResource(
|
||||||
|
id = R.string.title_profile_threads_tab,
|
||||||
|
it.get { thread_num }.getShortNumString()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
content = { user, expanded ->
|
||||||
|
UserPostPage(
|
||||||
|
uid = user.get { id },
|
||||||
|
isThread = true,
|
||||||
|
fluid = expanded,
|
||||||
|
enablePullRefresh = expanded,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
UserProfilePageData(
|
||||||
|
id = "posts",
|
||||||
|
title = {
|
||||||
|
stringResource(
|
||||||
|
id = R.string.title_profile_posts_tab,
|
||||||
|
it.get { post_num }.getShortNumString()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
content = { user, expanded ->
|
||||||
|
UserPostPage(
|
||||||
|
uid = user.get { id },
|
||||||
|
isThread = false,
|
||||||
|
fluid = expanded,
|
||||||
|
enablePullRefresh = expanded,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
).takeIf { isSelf },
|
||||||
|
UserProfilePageData(
|
||||||
|
id = "concern_forums",
|
||||||
|
title = {
|
||||||
|
stringResource(
|
||||||
|
id = R.string.title_profile_concern_forums_tab,
|
||||||
|
it.get { my_like_num }.toString()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
content = { user, expanded ->
|
||||||
|
UserLikeForumPage(
|
||||||
|
uid = user.get { id },
|
||||||
|
fluid = expanded,
|
||||||
|
enablePullRefresh = expanded,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
).toImmutableList()
|
||||||
|
}
|
||||||
|
val pagerState = rememberPagerState { pages.size }
|
||||||
|
|
||||||
|
UserProfileDetail(
|
||||||
|
user = user,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.align(Alignment.Top),
|
||||||
|
showBtn = showActionBtn,
|
||||||
|
isSelf = isSelf,
|
||||||
|
onBtnClick = {
|
||||||
|
if (disableButton || !showActionBtn) {
|
||||||
|
return@UserProfileDetail
|
||||||
|
}
|
||||||
|
if (isSelf) {
|
||||||
|
context.goToActivity<EditProfileActivity>()
|
||||||
|
} else if (user.get { has_concerned } == 0) {
|
||||||
|
onFollow()
|
||||||
|
} else {
|
||||||
|
onUnfollow()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCopyIdClick = {
|
||||||
|
TiebaUtil.copyText(
|
||||||
|
context,
|
||||||
|
user.get { id }.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(2f)
|
||||||
|
) {
|
||||||
|
UserProfileTabRow(
|
||||||
|
user = user,
|
||||||
|
pages = pages,
|
||||||
|
pagerState = pagerState,
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyLoadHorizontalPager(
|
||||||
|
state = pagerState,
|
||||||
|
key = { pages[it].id },
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
pages[it].content(user, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -449,7 +681,7 @@ fun UserProfilePage(
|
||||||
data class UserProfilePageData(
|
data class UserProfilePageData(
|
||||||
val id: String,
|
val id: String,
|
||||||
val title: @Composable (ImmutableHolder<User>) -> String,
|
val title: @Composable (ImmutableHolder<User>) -> String,
|
||||||
val content: @Composable (ImmutableHolder<User>) -> Unit,
|
val content: @Composable (ImmutableHolder<User>, Boolean) -> Unit,
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
|
@ -547,7 +779,6 @@ private fun UserProfileDetail(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
|
@ -736,7 +967,6 @@ private fun UserProfileDetail(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import androidx.compose.material.ExperimentalMaterialApi
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||||
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
|
@ -33,6 +34,7 @@ import com.huanchengfly.tieba.post.ui.common.theme.compose.pullRefreshIndicator
|
||||||
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
|
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
|
||||||
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
|
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Avatar
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Avatar
|
||||||
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Container
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
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.LoadMoreLayout
|
||||||
|
|
@ -46,6 +48,8 @@ import kotlinx.collections.immutable.persistentListOf
|
||||||
@Composable
|
@Composable
|
||||||
fun UserLikeForumPage(
|
fun UserLikeForumPage(
|
||||||
uid: Long,
|
uid: Long,
|
||||||
|
fluid: Boolean = false,
|
||||||
|
enablePullRefresh: Boolean = false,
|
||||||
viewModel: UserLikeForumViewModel = pageViewModel(),
|
viewModel: UserLikeForumViewModel = pageViewModel(),
|
||||||
) {
|
) {
|
||||||
val navigator = LocalNavigator.current
|
val navigator = LocalNavigator.current
|
||||||
|
|
@ -109,7 +113,10 @@ fun UserLikeForumPage(
|
||||||
|
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
|
|
||||||
Box {
|
val pullRefreshModifier =
|
||||||
|
if (enablePullRefresh) Modifier.pullRefresh(pullRefreshState) else Modifier
|
||||||
|
|
||||||
|
Box(modifier = pullRefreshModifier) {
|
||||||
LoadMoreLayout(
|
LoadMoreLayout(
|
||||||
isLoading = isLoadingMore,
|
isLoading = isLoadingMore,
|
||||||
onLoadMore = {
|
onLoadMore = {
|
||||||
|
|
@ -120,6 +127,7 @@ fun UserLikeForumPage(
|
||||||
) {
|
) {
|
||||||
UserLikeForumList(
|
UserLikeForumList(
|
||||||
data = forums,
|
data = forums,
|
||||||
|
fluid = fluid,
|
||||||
onClickForum = { forumBean ->
|
onClickForum = { forumBean ->
|
||||||
forumBean.name?.let {
|
forumBean.name?.let {
|
||||||
navigator.navigate(ForumPageDestination(it))
|
navigator.navigate(ForumPageDestination(it))
|
||||||
|
|
@ -144,6 +152,7 @@ fun UserLikeForumPage(
|
||||||
private fun UserLikeForumList(
|
private fun UserLikeForumList(
|
||||||
data: ImmutableList<UserLikeForumBean.ForumBean>,
|
data: ImmutableList<UserLikeForumBean.ForumBean>,
|
||||||
onClickForum: (UserLikeForumBean.ForumBean) -> Unit,
|
onClickForum: (UserLikeForumBean.ForumBean) -> Unit,
|
||||||
|
fluid: Boolean = false,
|
||||||
lazyListState: LazyListState = rememberLazyListState(),
|
lazyListState: LazyListState = rememberLazyListState(),
|
||||||
) {
|
) {
|
||||||
MyLazyColumn(state = lazyListState) {
|
MyLazyColumn(state = lazyListState) {
|
||||||
|
|
@ -151,6 +160,7 @@ private fun UserLikeForumList(
|
||||||
items = data,
|
items = data,
|
||||||
key = { it.id }
|
key = { it.id }
|
||||||
) {
|
) {
|
||||||
|
Container(fluid = fluid) {
|
||||||
UserLikeForumItem(
|
UserLikeForumItem(
|
||||||
item = it,
|
item = it,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
@ -163,6 +173,7 @@ private fun UserLikeForumList(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun UserLikeForumItem(
|
private fun UserLikeForumItem(
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.compose.material.ExperimentalMaterialApi
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||||
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
|
@ -52,6 +53,7 @@ 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.destinations.UserProfilePageDestination
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Card
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Card
|
||||||
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Container
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCard
|
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCard
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCardPlaceholder
|
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCardPlaceholder
|
||||||
|
|
@ -70,6 +72,8 @@ import kotlinx.collections.immutable.persistentListOf
|
||||||
fun UserPostPage(
|
fun UserPostPage(
|
||||||
uid: Long,
|
uid: Long,
|
||||||
isThread: Boolean = true,
|
isThread: Boolean = true,
|
||||||
|
fluid: Boolean = false,
|
||||||
|
enablePullRefresh: Boolean = false,
|
||||||
viewModel: UserPostViewModel = pageViewModel(key = if (isThread) "user_thread_$uid" else "user_post_$uid"),
|
viewModel: UserPostViewModel = pageViewModel(key = if (isThread) "user_thread_$uid" else "user_post_$uid"),
|
||||||
) {
|
) {
|
||||||
val navigator = LocalNavigator.current
|
val navigator = LocalNavigator.current
|
||||||
|
|
@ -207,7 +211,10 @@ fun UserPostPage(
|
||||||
|
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
|
|
||||||
Box {
|
val pullRefreshModifier =
|
||||||
|
if (enablePullRefresh) Modifier.pullRefresh(pullRefreshState) else Modifier
|
||||||
|
|
||||||
|
Box(modifier = pullRefreshModifier) {
|
||||||
LoadMoreLayout(
|
LoadMoreLayout(
|
||||||
isLoading = isLoadingMore,
|
isLoading = isLoadingMore,
|
||||||
onLoadMore = {
|
onLoadMore = {
|
||||||
|
|
@ -218,6 +225,7 @@ fun UserPostPage(
|
||||||
) {
|
) {
|
||||||
UserPostList(
|
UserPostList(
|
||||||
data = posts,
|
data = posts,
|
||||||
|
fluid = fluid,
|
||||||
lazyListState = lazyListState,
|
lazyListState = lazyListState,
|
||||||
onClickItem = { threadId, postId, isSubPost ->
|
onClickItem = { threadId, postId, isSubPost ->
|
||||||
if (postId == null) {
|
if (postId == null) {
|
||||||
|
|
@ -286,6 +294,7 @@ fun UserPostPage(
|
||||||
@Composable
|
@Composable
|
||||||
private fun UserPostList(
|
private fun UserPostList(
|
||||||
data: ImmutableList<PostListItemData>,
|
data: ImmutableList<PostListItemData>,
|
||||||
|
fluid: Boolean = false,
|
||||||
lazyListState: LazyListState = rememberLazyListState(),
|
lazyListState: LazyListState = rememberLazyListState(),
|
||||||
onClickItem: (threadId: Long, postId: Long?, isSubPost: Boolean) -> Unit = { _, _, _ -> },
|
onClickItem: (threadId: Long, postId: Long?, isSubPost: Boolean) -> Unit = { _, _, _ -> },
|
||||||
onAgreeItem: (PostInfoList) -> Unit = {},
|
onAgreeItem: (PostInfoList) -> Unit = {},
|
||||||
|
|
@ -301,6 +310,7 @@ private fun UserPostList(
|
||||||
"${it.data.get { thread_id }}_${it.data.get { post_id }}"
|
"${it.data.get { thread_id }}_${it.data.get { post_id }}"
|
||||||
}
|
}
|
||||||
) { itemData ->
|
) { itemData ->
|
||||||
|
Container(fluid = fluid) {
|
||||||
UserPostItem(
|
UserPostItem(
|
||||||
post = itemData,
|
post = itemData,
|
||||||
onClick = onClickItem,
|
onClick = onClickItem,
|
||||||
|
|
@ -313,6 +323,7 @@ private fun UserPostList(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UserPostItem(
|
fun UserPostItem(
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,21 @@ import com.huanchengfly.tieba.post.ui.common.windowsizeclass.WindowWidthSizeClas
|
||||||
@Composable
|
@Composable
|
||||||
fun Container(
|
fun Container(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
fluid: Boolean = false,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
val windowWidthSizeClass = LocalWindowSizeClass.current.widthSizeClass
|
val windowWidthSizeClass = LocalWindowSizeClass.current.widthSizeClass
|
||||||
val widthFraction = remember(windowWidthSizeClass) {
|
val widthFraction = remember(windowWidthSizeClass) {
|
||||||
|
if (fluid) {
|
||||||
|
1f
|
||||||
|
} else {
|
||||||
when (windowWidthSizeClass) {
|
when (windowWidthSizeClass) {
|
||||||
WindowWidthSizeClass.Medium -> 0.87f
|
WindowWidthSizeClass.Medium -> 0.87f
|
||||||
WindowWidthSizeClass.Expanded -> 0.75f
|
WindowWidthSizeClass.Expanded -> 0.75f
|
||||||
else -> 1f
|
else -> 1f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.TipScreen
|
||||||
|
|
||||||
val DefaultLoadingScreen: @Composable StateScreenScope.() -> Unit = {
|
val DefaultLoadingScreen: @Composable StateScreenScope.() -> Unit = {
|
||||||
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.lottie_loading_paperplane))
|
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.lottie_loading_paperplane))
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
Box(modifier = Modifier.requiredWidthIn(max = 500.dp)) {
|
Box(modifier = Modifier.requiredWidthIn(max = 500.dp)) {
|
||||||
LottieAnimation(
|
LottieAnimation(
|
||||||
composition = composition,
|
composition = composition,
|
||||||
|
|
@ -34,6 +38,7 @@ val DefaultLoadingScreen: @Composable StateScreenScope.() -> Unit = {
|
||||||
.aspectRatio(2f)
|
.aspectRatio(2f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// CircularProgressIndicator(modifier = Modifier.size(48.dp), color = MaterialTheme.colors.primary)
|
// CircularProgressIndicator(modifier = Modifier.size(48.dp), color = MaterialTheme.colors.primary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,7 +61,8 @@ val DefaultEmptyScreen: @Composable StateScreenScope.() -> Unit = {
|
||||||
Text(text = stringResource(id = R.string.btn_refresh))
|
Text(text = stringResource(id = R.string.btn_refresh))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue