diff --git a/app/src/main/java/me/ash/reader/ui/component/Banner.kt b/app/src/main/java/me/ash/reader/ui/component/Banner.kt index 2c3583a..99b362e 100644 --- a/app/src/main/java/me/ash/reader/ui/component/Banner.kt +++ b/app/src/main/java/me/ash/reader/ui/component/Banner.kt @@ -1,3 +1,11 @@ +/** + * Copyright (C) 2021 Kyant0 + * + * @link https://github.com/Kyant0/MusicYou + * @author Kyant0 + * @modifier Ashinch + */ + package me.ash.reader.ui.component import androidx.compose.animation.Crossfade @@ -12,6 +20,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -29,12 +38,12 @@ fun Banner( val lightOnSurface = lightThemeColors.onSurface Surface( - modifier = modifier.fillMaxWidth(), + modifier = modifier.fillMaxWidth().height(88.dp), color = MaterialTheme.colorScheme.surface, ) { Row( modifier = Modifier - .fillMaxWidth() + .fillMaxSize() .padding(horizontal = 16.dp) .clip(RoundedCornerShape(32.dp)) .background(lightPrimaryContainer) @@ -52,19 +61,24 @@ fun Banner( ) } } - Column(modifier = Modifier.weight(1f)) { + Column( + modifier = Modifier.weight(1f).fillMaxHeight(), + verticalArrangement = Arrangement.SpaceBetween, + ) { Text( text = title, maxLines = if (desc == null) 2 else 1, style = MaterialTheme.typography.titleLarge.copy(fontSize = 20.sp), color = lightOnSurface, + overflow = TextOverflow.Ellipsis, ) desc?.let { Text( text = it, - maxLines = 1, style = MaterialTheme.typography.bodyMedium, color = lightOnSurface.copy(alpha = 0.7f), + maxLines = 1, + overflow = TextOverflow.Ellipsis, ) } } diff --git a/app/src/main/java/me/ash/reader/ui/component/SelectableSettingGroupItem.kt b/app/src/main/java/me/ash/reader/ui/component/SelectableSettingGroupItem.kt new file mode 100644 index 0000000..ac440c5 --- /dev/null +++ b/app/src/main/java/me/ash/reader/ui/component/SelectableSettingGroupItem.kt @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2021 Kyant0 + * + * @link https://github.com/Kyant0/MusicYou + * @author Kyant0 + * @modifier Ashinch + */ + +package me.ash.reader.ui.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun SelectableSettingGroupItem( + modifier: Modifier = Modifier, + selected: Boolean = false, + title: String, + desc: String? = null, + icon: ImageVector? = null, + onClick: () -> Unit, +) { + Surface( + modifier = modifier.clickable { onClick() }, + color = Color.Unspecified, + contentColor = if (selected) MaterialTheme.colorScheme.surface else MaterialTheme.colorScheme.onSurface + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .background( + if (selected) MaterialTheme.colorScheme.onSurface else Color.Unspecified, + RoundedCornerShape(24.dp) + ) + .padding(8.dp, 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + icon?.let { + Icon( + imageVector = it, + contentDescription = null, + modifier = Modifier.padding(start = 8.dp, end = 16.dp), + tint = if (selected) MaterialTheme.colorScheme.surface.copy(alpha = 0.8f) else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f), + ) + } + Column(modifier = Modifier.weight(1f)) { + Text( + text = title, + maxLines = if (desc == null) 2 else 1, + style = MaterialTheme.typography.titleLarge.copy(fontSize = 20.sp), + ) + desc?.let { + Text( + text = it, + color = if (selected) MaterialTheme.colorScheme.surface.copy(alpha = 0.7f) + else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f), + maxLines = 1, + style = MaterialTheme.typography.bodyMedium, + ) + } + } + } + } +} diff --git a/app/src/main/java/me/ash/reader/ui/ext/Navigation.kt b/app/src/main/java/me/ash/reader/ui/ext/Navigation.kt new file mode 100644 index 0000000..12e1775 --- /dev/null +++ b/app/src/main/java/me/ash/reader/ui/ext/Navigation.kt @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2021 Kyant0 + * + * @link https://github.com/Kyant0/MusicYou + * @author Kyant0 + * @modifier Ashinch + */ + +package me.ash.reader.ui.ext + +import androidx.compose.animation.* +import androidx.compose.animation.core.tween +import androidx.compose.runtime.Composable +import androidx.navigation.NamedNavArgument +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavDeepLink +import androidx.navigation.NavGraphBuilder +import com.google.accompanist.navigation.animation.composable + +@OptIn(ExperimentalAnimationApi::class) +fun NavGraphBuilder.animatedComposable( + route: String, + arguments: List = emptyList(), + deepLinks: List = emptyList(), + content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit +) = composable( + route = route, + arguments = arguments, + deepLinks = deepLinks, + enterTransition = { + fadeIn(animationSpec = tween(220, delayMillis = 90)) + + scaleIn( + initialScale = 0.92f, + animationSpec = tween(220, delayMillis = 90) + ) + }, + exitTransition = { + fadeOut(animationSpec = tween(90)) + }, + popEnterTransition = { + fadeIn(animationSpec = tween(220, delayMillis = 90)) + + scaleIn( + initialScale = 0.92f, + animationSpec = tween(220, delayMillis = 90) + ) + }, + popExitTransition = { + fadeOut(animationSpec = tween(90)) + }, + content = content +) diff --git a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt index 47781b6..1e4bceb 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt @@ -1,9 +1,6 @@ package me.ash.reader.ui.page.common -import androidx.compose.animation.* -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.spring -import androidx.compose.animation.core.tween +import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column @@ -18,9 +15,9 @@ import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsHeight import com.google.accompanist.insets.statusBarsPadding import com.google.accompanist.navigation.animation.AnimatedNavHost -import com.google.accompanist.navigation.animation.composable import com.google.accompanist.navigation.animation.rememberAnimatedNavController import com.google.accompanist.systemuicontroller.rememberSystemUiController +import me.ash.reader.ui.ext.animatedComposable import me.ash.reader.ui.page.home.HomePage import me.ash.reader.ui.page.settings.SettingsPage import me.ash.reader.ui.theme.AppTheme @@ -47,86 +44,10 @@ fun HomeEntry() { navController = navController, startDestination = RouteName.HOME, ) { - composable( - route = RouteName.HOME, - enterTransition = { - slideInHorizontally( - animationSpec = spring( - stiffness = Spring.StiffnessLow, - dampingRatio = Spring.DampingRatioNoBouncy - ), - initialOffsetX = { -it } - ) + fadeIn(animationSpec = tween(220, delayMillis = 90)) - }, - exitTransition = { - slideOutHorizontally( - animationSpec = spring( - stiffness = Spring.StiffnessLow, - dampingRatio = Spring.DampingRatioNoBouncy - ), - targetOffsetX = { it } - ) + fadeOut(animationSpec = tween(220, delayMillis = 90)) - }, - popEnterTransition = { - slideInHorizontally( - animationSpec = spring( - stiffness = Spring.StiffnessLow, - dampingRatio = Spring.DampingRatioNoBouncy - ), - initialOffsetX = { -it } - ) + fadeIn(animationSpec = tween(220, delayMillis = 90)) - }, - popExitTransition = { - slideOutHorizontally( - animationSpec = spring( - stiffness = Spring.StiffnessLow, - dampingRatio = Spring.DampingRatioNoBouncy - ), - targetOffsetX = { it } - ) + fadeOut(animationSpec = tween(220, delayMillis = 90)) - }, - ) { + animatedComposable(route = RouteName.HOME) { HomePage(navController) } - composable( - route = RouteName.SETTINGS, - enterTransition = { - slideInHorizontally( - animationSpec = spring( - stiffness = Spring.StiffnessLow, - dampingRatio = Spring.DampingRatioNoBouncy - ), - initialOffsetX = { -it } - ) + fadeIn(animationSpec = tween(220, delayMillis = 90)) - }, - exitTransition = { - slideOutHorizontally( - animationSpec = spring( - stiffness = Spring.StiffnessLow, - dampingRatio = Spring.DampingRatioNoBouncy - ), - targetOffsetX = { -it } - ) + fadeOut(animationSpec = tween(220, delayMillis = 90)) - }, - popEnterTransition = { - slideInHorizontally( - animationSpec = spring( - stiffness = Spring.StiffnessLow, - dampingRatio = Spring.DampingRatioNoBouncy - ), - initialOffsetX = { -it } - ) + fadeIn(animationSpec = tween(220, delayMillis = 90)) - }, - popExitTransition = { - slideOutHorizontally( - animationSpec = spring( - stiffness = Spring.StiffnessLow, - dampingRatio = Spring.DampingRatioNoBouncy - ), - targetOffsetX = { -it } - ) + fadeOut(animationSpec = tween(220, delayMillis = 90)) - }, - ) { + animatedComposable(route = RouteName.SETTINGS) { SettingsPage(navController) } } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt index 06a1a06..1019d76 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt @@ -72,7 +72,7 @@ data class FilterState( @OptIn(ExperimentalPagerApi::class) data class HomeViewState( - val pagerState: PagerState = PagerState(1), + val pagerState: PagerState = PagerState(0), ) sealed class HomeViewAction { diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt index 5b2e2ed..6b76605 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt @@ -35,6 +35,7 @@ import me.ash.reader.ui.component.Subtitle import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.getDesc import me.ash.reader.ui.ext.getName +import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeDialog @@ -91,7 +92,6 @@ fun FeedsPage( feedsViewModel.dispatch(FeedsViewAction.FetchAccount) } - LaunchedEffect(filterState) { feedsViewModel.dispatch( FeedsViewAction.FetchData(filterState) @@ -111,7 +111,7 @@ fun FeedsPage( contentDescription = stringResource(R.string.settings), tint = MaterialTheme.colorScheme.onSurface, ) { - onScrollToPage(0) + navController.navigate(RouteName.SETTINGS) } }, actions = { diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/ResultView.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/ResultView.kt index 7dfccbe..8714c4b 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/ResultView.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/ResultView.kt @@ -52,7 +52,7 @@ fun ResultView( onAddNewGroup: () -> Unit = {}, ) { LaunchedEffect(Unit) { - if (groups.isNotEmpty()) onGroupClick(groups.first().id) + if (groups.isNotEmpty() && selectedGroupId.isEmpty()) onGroupClick(groups.first().id) } Column( diff --git a/app/src/main/java/me/ash/reader/ui/page/home/read/ReadPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/read/ReadPage.kt index 590acd3..36040d7 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/read/ReadPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/read/ReadPage.kt @@ -147,7 +147,7 @@ private fun TopBar( FeedbackIconButton( isHaptic = false, imageVector = Icons.Rounded.Close, - contentDescription = stringResource(R.string.back), + contentDescription = stringResource(R.string.close), tint = MaterialTheme.colorScheme.onSurface ) { onScrollToPage(1) { diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/SettingsPage.kt b/app/src/main/java/me/ash/reader/ui/page/settings/SettingsPage.kt index 5e42dc4..724947a 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/SettingsPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/SettingsPage.kt @@ -3,10 +3,10 @@ package me.ash.reader.ui.page.settings import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.* -import androidx.compose.material.icons.rounded.ArrowBackIosNew +import androidx.compose.material.icons.rounded.ArrowBack +import androidx.compose.material.icons.rounded.Close import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -19,90 +19,98 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavHostController import me.ash.reader.R +import me.ash.reader.ui.component.Banner +import me.ash.reader.ui.component.DisplayText +import me.ash.reader.ui.component.FeedbackIconButton +import me.ash.reader.ui.component.SelectableSettingGroupItem import me.ash.reader.ui.ext.paddingFixedHorizontal import me.ash.reader.ui.ext.roundClick +import me.ash.reader.ui.page.common.RouteName +@OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsPage( navController: NavHostController, ) { - val listState = rememberLazyListState() - Box(modifier = Modifier.fillMaxSize()) { -// LargeTopAppBar( -// title = { Text(text = "Settings") } -// ) - Column { + Scaffold( + modifier = Modifier.background(MaterialTheme.colorScheme.surface), + topBar = { SmallTopAppBar( title = {}, navigationIcon = { - IconButton(onClick = { navController.popBackStack() }) { - Icon( - imageVector = Icons.Rounded.ArrowBackIosNew, - contentDescription = stringResource(R.string.back), - tint = MaterialTheme.colorScheme.primary - ) + FeedbackIconButton( + isHaptic = false, + imageVector = Icons.Rounded.ArrowBack, + contentDescription = stringResource(R.string.back), + tint = MaterialTheme.colorScheme.onSurface + ) { + navController.navigate(RouteName.HOME) } }, + actions = {} ) - LazyColumn( - modifier = Modifier - .weight(1f) - .paddingFixedHorizontal(), - state = listState - ) { + }, + content = { + LazyColumn { item { - Spacer(modifier = Modifier.height(112.dp)) + DisplayText(text = stringResource(R.string.settings), desc = "") } item { - Item( - title = "通用", - description = "应用的基本设置", - imageVector = Icons.Outlined.Apps, + Banner( + title = stringResource(R.string.get_new_updates), + desc = stringResource(R.string.get_new_updates_desc), + icon = Icons.Outlined.Lightbulb, + action = { + Icon( + imageVector = Icons.Rounded.Close, + contentDescription = stringResource(R.string.close), + ) + }, ) + Spacer(modifier = Modifier.height(16.dp)) } item { - Item( - title = "外观", - description = "字体、颜色、背景", - imageVector = Icons.Outlined.ColorLens, - ) + SelectableSettingGroupItem( + title = stringResource(R.string.accounts), + desc = stringResource(R.string.accounts_desc), + icon = Icons.Outlined.AccountCircle, + ) {} } item { - Item( - title = "阅读", - description = "渲染阅读视图的设置", - imageVector = Icons.Outlined.LocalLibrary, - ) + SelectableSettingGroupItem( + title = stringResource(R.string.color_and_style), + desc = stringResource(R.string.color_and_style_desc), + icon = Icons.Outlined.Palette, + ) {} } item { - Item( - title = "Ash", - description = "本地账户", - imageVector = Icons.Outlined.Storage, - ) + SelectableSettingGroupItem( + title = stringResource(R.string.interaction), + desc = stringResource(R.string.interaction_desc), + icon = Icons.Outlined.TouchApp, + ) {} } item { - Item( - title = "添加账户", - description = "FreshRSS、Inoreader、Feedly", - imageVector = Icons.Outlined.AccountCircle, - ) + SelectableSettingGroupItem( + title = stringResource(R.string.languages), + desc = stringResource(R.string.languages_desc), + icon = Icons.Outlined.Language, + ) {} } item { - Spacer(modifier = Modifier.height(500.dp)) - Item( - title = "添加账户", - description = "FreshRSS、Inoreader、Feedly", - imageVector = Icons.Outlined.AccountCircle, - ) + SelectableSettingGroupItem( + title = stringResource(R.string.tips_and_support), + desc = stringResource(R.string.tips_and_support_desc), + icon = Icons.Outlined.TipsAndUpdates, + ) {} } } } - } + ) } @Composable -fun Item( +fun SettingsItem( title: String = "", description: String = "", imageVector: ImageVector, diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index ab3ae8d..6c37e7f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -53,4 +53,17 @@ 1天 3天 7天 + 关闭 + 获取新的更新 + 版本 0.6.1 现已发布 + 账户 + 本地、Fresh + 颜色和样式 + 主题、色彩系统、字体大小 + 交互 + 布局、触觉反馈 + 语言 + 英语、中文 + 提示和支持 + 关于、开源 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 736a7c7..558cfc2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -53,4 +53,17 @@ 1d 3d 7d + Close + Get New updates + Version 0.6.1 has been released + Accounts + Local, Fresh + Color & style + Theme, color system, font size + Interaction + Layout, haptic feedback + Languages + English, Chinese + Tips & support + About, open source \ No newline at end of file