pref: 首页未登录 & 空状态优化

This commit is contained in:
HuanCheng65 2023-03-11 01:18:19 +08:00
parent 3a897cd4d1
commit afe5d19e44
No known key found for this signature in database
GPG Key ID: E9031EF91A805148
4 changed files with 190 additions and 69 deletions

View File

@ -107,6 +107,9 @@ fun MainPage(
}
}
val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()
val themeColors = ExtendedTheme.colors
val windowSizeClass = LocalWindowSizeClass.current
val foldingDevicePosture by devicePostureFlow.collectAsState()
val navigationItems = listOfNotNull(
@ -114,7 +117,14 @@ fun MainPage(
icon = { if (it) Icons.Rounded.Inventory2 else Icons.Outlined.Inventory2 },
title = stringResource(id = R.string.title_main),
content = {
HomePage()
HomePage(
canOpenExplore = !LocalContext.current.appPreferences.hideExplore,
onOpenExplore = {
coroutineScope.launch {
pagerState.scrollToPage(1)
}
}
)
}
),
if (LocalContext.current.appPreferences.hideExplore) null
@ -149,9 +159,6 @@ fun MainPage(
}
),
)
val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()
val themeColors = ExtendedTheme.colors
val navigationType = when (windowSizeClass.widthSizeClass) {
WindowWidthSizeClass.Compact -> {

View File

@ -6,11 +6,13 @@ import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@ -26,6 +28,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
@ -54,12 +57,18 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.LottieConstants
import com.airbnb.lottie.compose.rememberLottieComposition
import com.google.accompanist.drawablepainter.rememberDrawablePainter
import com.google.accompanist.placeholder.placeholder
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.activities.LoginActivity
import com.huanchengfly.tieba.post.activities.NewSearchActivity
import com.huanchengfly.tieba.post.arch.collectPartialAsState
import com.huanchengfly.tieba.post.arch.pageViewModel
@ -70,12 +79,14 @@ import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
import com.huanchengfly.tieba.post.ui.widgets.Chip
import com.huanchengfly.tieba.post.ui.widgets.compose.ActionItem
import com.huanchengfly.tieba.post.ui.widgets.compose.Avatar
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
import com.huanchengfly.tieba.post.ui.widgets.compose.ConfirmDialog
import com.huanchengfly.tieba.post.ui.widgets.compose.LongClickMenu
import com.huanchengfly.tieba.post.ui.widgets.compose.Toolbar
import com.huanchengfly.tieba.post.ui.widgets.compose.accountNavIconIfCompact
import com.huanchengfly.tieba.post.ui.widgets.compose.rememberDialogState
import com.huanchengfly.tieba.post.ui.widgets.compose.rememberMenuState
import com.huanchengfly.tieba.post.ui.widgets.compose.states.StateScreen
import com.huanchengfly.tieba.post.utils.AccountUtil.LocalAccount
import com.huanchengfly.tieba.post.utils.ImageUtil
import com.huanchengfly.tieba.post.utils.TiebaUtil
@ -362,8 +373,10 @@ fun HomePage(
HomeUiIntent.Refresh
)
),
canOpenExplore: Boolean = false,
onOpenExplore: () -> Unit = {},
) {
LocalAccount.current
val account = LocalAccount.current
val context = LocalContext.current
val isLoading by viewModel.uiState.collectPartialAsState(
prop1 = HomeUiState::isLoading,
@ -379,6 +392,7 @@ fun HomePage(
)
var listSingle by remember { mutableStateOf(context.appPreferences.listSingle) }
val gridCells by remember { derivedStateOf { getGridCells(context, listSingle) } }
Scaffold(
backgroundColor = Color.Transparent,
topBar = {
@ -404,26 +418,42 @@ fun HomePage(
},
modifier = Modifier.fillMaxSize(),
) { contentPaddings ->
val pullRefreshState = rememberPullRefreshState(
refreshing = isLoading,
onRefresh = { viewModel.send(HomeUiIntent.Refresh) })
Box(modifier = Modifier
.padding(contentPaddings)
.pullRefresh(pullRefreshState)) {
val gridState = rememberLazyGridState()
LazyVerticalGrid(
state = gridState,
columns = gridCells,
contentPadding = PaddingValues(bottom = 12.dp),
StateScreen(
isEmpty = forums.isEmpty(),
isError = false,
isLoading = isLoading,
modifier = Modifier.padding(contentPaddings),
emptyScreen = {
EmptyScreen(
loggedIn = account != null,
canOpenExplore = canOpenExplore,
onOpenExplore = onOpenExplore
)
},
loadingScreen = {
HomePageSkeletonScreen(listSingle = listSingle, gridCells = gridCells)
}
) {
val pullRefreshState = rememberPullRefreshState(
refreshing = isLoading,
onRefresh = { viewModel.send(HomeUiIntent.Refresh) })
Box(
modifier = Modifier
.fillMaxSize(),
.pullRefresh(pullRefreshState)
) {
item(key = "SearchBox", span = { GridItemSpan(maxLineSpan) }) {
SearchBox(modifier = Modifier.padding(bottom = 12.dp)) {
context.goToActivity<NewSearchActivity>()
val gridState = rememberLazyGridState()
LazyVerticalGrid(
state = gridState,
columns = gridCells,
contentPadding = PaddingValues(bottom = 12.dp),
modifier = Modifier
.fillMaxSize(),
) {
item(key = "SearchBox", span = { GridItemSpan(maxLineSpan) }) {
SearchBox(modifier = Modifier.padding(bottom = 12.dp)) {
context.goToActivity<NewSearchActivity>()
}
}
}
if (!isLoading || forums.isNotEmpty()) {
if (topForums.isNotEmpty()) {
item(key = "TopForumHeader", span = { GridItemSpan(maxLineSpan) }) {
Column {
@ -458,53 +488,126 @@ fun HomePage(
val item = forums[it]
ForumItem(viewModel, item, listSingle)
}
} else {
item(key = "TopForumHeaderPlaceholder", span = { GridItemSpan(maxLineSpan) }) {
Column {
Header(
text = stringResource(id = R.string.title_top_forum),
invert = true,
modifier = Modifier.placeholder(visible = true, color = ExtendedTheme.colors.chip)
)
Spacer(modifier = Modifier.height(8.dp))
}
}
items(6, key = { "TopPlaceholder$it" }) {
ForumItemPlaceholder(listSingle)
}
item(
key = "Spacer",
span = { GridItemSpan(maxLineSpan) }) {
Spacer(
modifier = Modifier.height(
16.dp
)
)
}
item(key = "ForumHeaderPlaceholder", span = { GridItemSpan(maxLineSpan) }) {
Column {
Header(
text = stringResource(id = R.string.forum_list_title),
invert = true,
modifier = Modifier.placeholder(
visible = true,
color = ExtendedTheme.colors.chip
)
)
Spacer(modifier = Modifier.height(8.dp))
}
}
items(12, key = { "Placeholder$it" }) {
ForumItemPlaceholder(listSingle)
}
}
}
PullRefreshIndicator(
refreshing = isLoading,
state = pullRefreshState,
modifier = Modifier.align(Alignment.TopCenter)
)
PullRefreshIndicator(
refreshing = isLoading,
state = pullRefreshState,
modifier = Modifier.align(Alignment.TopCenter)
)
}
}
}
}
@Composable
private fun HomePageSkeletonScreen(
listSingle: Boolean,
gridCells: GridCells
) {
LazyVerticalGrid(
columns = gridCells,
contentPadding = PaddingValues(bottom = 12.dp),
modifier = Modifier
.fillMaxSize(),
) {
item(key = "TopForumHeaderPlaceholder", span = { GridItemSpan(maxLineSpan) }) {
Column {
Header(
text = stringResource(id = R.string.title_top_forum),
invert = true,
modifier = Modifier.placeholder(
visible = true,
color = ExtendedTheme.colors.chip
)
)
Spacer(modifier = Modifier.height(8.dp))
}
}
items(6, key = { "TopPlaceholder$it" }) {
ForumItemPlaceholder(listSingle)
}
item(
key = "Spacer",
span = { GridItemSpan(maxLineSpan) }) {
Spacer(
modifier = Modifier.height(
16.dp
)
)
}
item(key = "ForumHeaderPlaceholder", span = { GridItemSpan(maxLineSpan) }) {
Column {
Header(
text = stringResource(id = R.string.forum_list_title),
invert = true,
modifier = Modifier.placeholder(
visible = true,
color = ExtendedTheme.colors.chip
)
)
Spacer(modifier = Modifier.height(8.dp))
}
}
items(12, key = { "Placeholder$it" }) {
ForumItemPlaceholder(listSingle)
}
}
}
@Composable
fun EmptyScreen(
loggedIn: Boolean,
canOpenExplore: Boolean,
onOpenExplore: () -> Unit
) {
val context = LocalContext.current
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp, alignment = CenterVertically)
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.lottie_astronaut))
LottieAnimation(
composition = composition,
iterations = LottieConstants.IterateForever,
modifier = Modifier
.fillMaxWidth()
.aspectRatio(2f)
)
Text(
text = stringResource(id = R.string.title_empty),
style = MaterialTheme.typography.h6,
color = ExtendedTheme.colors.text,
textAlign = TextAlign.Center,
)
if (!loggedIn) {
Text(
text = stringResource(id = R.string.title_empty_login),
style = MaterialTheme.typography.body1,
color = ExtendedTheme.colors.textSecondary,
textAlign = TextAlign.Center
)
Button(
onClick = {
context.goToActivity<LoginActivity>()
},
modifier = Modifier
.fillMaxWidth()
) {
Text(text = stringResource(id = R.string.button_login))
}
}
if (canOpenExplore) {
Button(
onClick = onOpenExplore,
modifier = Modifier
.fillMaxWidth()
) {
Text(text = stringResource(id = R.string.button_go_to_explore))
}
}
}
}

View File

@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ButtonColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.ButtonElevation
@ -23,6 +24,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.dp
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
@OptIn(ExperimentalMaterialApi::class)
@Composable
@ -31,10 +33,13 @@ fun Button(
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
elevation: ButtonElevation? = ButtonDefaults.elevation(),
shape: Shape = MaterialTheme.shapes.small,
elevation: ButtonElevation? = ButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp, 0.dp),
shape: Shape = RoundedCornerShape(100),
border: BorderStroke? = null,
colors: ButtonColors = ButtonDefaults.buttonColors(),
colors: ButtonColors = ButtonDefaults.buttonColors(
backgroundColor = ExtendedTheme.colors.accent,
contentColor = ExtendedTheme.colors.onAccent
),
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
content: @Composable RowScope.() -> Unit
) {

View File

@ -642,4 +642,10 @@
<string name="message_dialog_oksign_battery_optimization">在 Android 12 及以上版本中,后台启动前台服务被严格限制。为了避免一键签到无法正常启动,请忽略本应用的“电池优化”。</string>
<string name="button_go_to_ignore_battery_optimization">好的,去忽略</string>
<string name="button_dont_remind_again">不再提示</string>
<string name="link">链接</string>
<string name="user">用户</string>
<string name="title_empty">这里什么都没有</string>
<string name="title_empty_login">请登录之后查看你的关注。\n或者你也可以先去逛逛发现</string>
<string name="button_login">去登录</string>
<string name="button_go_to_explore">随便看看</string>
</resources>