Skip to content

Commit

Permalink
feat(ui): elevated style reader toolbars (#894)
Browse files Browse the repository at this point in the history
* feat(ui): toolbar animation

* feat(ui): elevated variant for reader toolbars
  • Loading branch information
JunkFood02 authored Nov 22, 2024
1 parent 629f489 commit 6e55c12
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,30 @@ val LocalReadingPageTonalElevation =
compositionLocalOf<ReadingPageTonalElevationPreference> { ReadingPageTonalElevationPreference.default }

sealed class ReadingPageTonalElevationPreference(val value: Int) : Preference() {
object Level0 : ReadingPageTonalElevationPreference(ElevationTokens.Level0)
object Level1 : ReadingPageTonalElevationPreference(ElevationTokens.Level1)
object Level2 : ReadingPageTonalElevationPreference(ElevationTokens.Level2)
object Level3 : ReadingPageTonalElevationPreference(ElevationTokens.Level3)
object Level4 : ReadingPageTonalElevationPreference(ElevationTokens.Level4)
object Level5 : ReadingPageTonalElevationPreference(ElevationTokens.Level5)
data object Outlined : ReadingPageTonalElevationPreference(ElevationTokens.Level0)
data object Elevated : ReadingPageTonalElevationPreference(ElevationTokens.Level2)

override fun put(context: Context, scope: CoroutineScope) {
scope.launch {
context.dataStore.put(DataStoreKey.readingPageTonalElevation, value)
context.dataStore.put(readingPageTonalElevation, value)
}
}

fun toDesc(context: Context): String =
when (this) {
Level0 -> "Level 0 (${ElevationTokens.Level0}dp)"
Level1 -> "Level 1 (${ElevationTokens.Level1}dp)"
Level2 -> "Level 2 (${ElevationTokens.Level2}dp)"
Level3 -> "Level 3 (${ElevationTokens.Level3}dp)"
Level4 -> "Level 4 (${ElevationTokens.Level4}dp)"
Level5 -> "Level 5 (${ElevationTokens.Level5}dp)"
Outlined -> "${ElevationTokens.Level0}dp"
Elevated -> "${ElevationTokens.Level2}dp"
}

companion object {

val default = Level0
val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5)
val default = Outlined
val values = listOf(Outlined, Elevated)

fun fromPreferences(preferences: Preferences) =
when (preferences[DataStoreKey.keys[readingPageTonalElevation]?.key as Preferences.Key<Int>]) {
ElevationTokens.Level0 -> Level0
ElevationTokens.Level1 -> Level1
ElevationTokens.Level2 -> Level2
ElevationTokens.Level3 -> Level3
ElevationTokens.Level4 -> Level4
ElevationTokens.Level5 -> Level5
ElevationTokens.Level0 -> Outlined
ElevationTokens.Level2 -> Elevated
else -> default
}
}
Expand Down
25 changes: 13 additions & 12 deletions app/src/main/java/me/ash/reader/ui/page/home/reading/BottomBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package me.ash.reader.ui.page.home.reading

import android.view.HapticFeedbackConstants
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
Expand Down Expand Up @@ -33,15 +30,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import me.ash.reader.R
import me.ash.reader.infrastructure.preference.LocalReadingPageTonalElevation
import me.ash.reader.infrastructure.preference.LocalReadingRenderer
import me.ash.reader.infrastructure.preference.ReadingPageTonalElevationPreference
import me.ash.reader.infrastructure.preference.ReadingRendererPreference
import me.ash.reader.ui.component.base.CanBeDisabledIconButton
import me.ash.reader.ui.component.base.RYExtensibleVisibility
import me.ash.reader.ui.component.webview.BionicReadingIcon

@Composable
Expand All @@ -60,6 +56,7 @@ fun BottomBar(
onReadAloud: () -> Unit = {},
) {
val tonalElevation = LocalReadingPageTonalElevation.current
val isOutlined = tonalElevation == ReadingPageTonalElevationPreference.Outlined
val renderer = LocalReadingRenderer.current

Box(
Expand All @@ -70,16 +67,20 @@ fun BottomBar(
) {
AnimatedVisibility(
visible = isShow,
enter = expandVertically(),
exit = shrinkVertically()
enter = expandVertically(expandFrom = Alignment.Top),
exit = shrinkVertically(shrinkTowards = Alignment.Top)
) {
val view = LocalView.current
Column {
HorizontalDivider(
color = MaterialTheme.colorScheme.surfaceContainerHighest,
thickness = 0.5f.dp
)
Surface() {
if (isOutlined) {
HorizontalDivider(
color = MaterialTheme.colorScheme.surfaceContainerHighest,
thickness = 0.5f.dp
)
}
Surface(
color = MaterialTheme.colorScheme.run { if (isOutlined) surface else surfaceContainer }
) {
// TODO: Component styles await refactoring
Row(
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.LocalOverscrollConfiguration
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.ExperimentalMaterialApi
Expand All @@ -16,9 +14,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -28,19 +24,16 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.isSpecified
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import me.ash.reader.R
import me.ash.reader.infrastructure.preference.LocalPullToSwitchArticle
Expand Down Expand Up @@ -123,7 +116,7 @@ fun ReadingPage(
TopBar(
navController = navController,
isShow = isShowToolBar,
showDivider = showTopDivider,
isScrolled = showTopDivider,
title = readerState.title,
link = readerState.link,
onClick = { bringToTop = true },
Expand Down Expand Up @@ -194,7 +187,7 @@ fun ReadingPage(


showTopDivider = snapshotFlow {
scrollState.value != 0 || listState.firstVisibleItemIndex != 0
scrollState.value >= 120 || listState.firstVisibleItemIndex != 0
}.collectAsStateValue(initial = false)

CompositionLocalProvider(
Expand Down
50 changes: 32 additions & 18 deletions app/src/main/java/me/ash/reader/ui/page/home/reading/TopBar.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package me.ash.reader.ui.page.home.reading

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
Expand All @@ -15,7 +18,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Palette
import androidx.compose.material.icons.outlined.Share
Expand All @@ -27,65 +29,75 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.navigation.NavHostController
import me.ash.reader.R
import me.ash.reader.infrastructure.preference.LocalReadingPageTonalElevation
import me.ash.reader.infrastructure.preference.LocalSharedContent
import me.ash.reader.infrastructure.preference.ReadingPageTonalElevationPreference
import me.ash.reader.ui.component.base.FeedbackIconButton
import me.ash.reader.ui.ext.surfaceColorAtElevation
import me.ash.reader.ui.page.common.RouteName

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TopBar(
navController: NavHostController,
isShow: Boolean,
showDivider: Boolean = false,
isScrolled: Boolean = false,
title: String? = "",
link: String? = "",
onClick: (() -> Unit)? = null,
onClose: () -> Unit = {},
) {
val context = LocalContext.current
val sharedContent = LocalSharedContent.current
val isOutlined =
LocalReadingPageTonalElevation.current == ReadingPageTonalElevationPreference.Outlined

val containerColor by animateColorAsState(with(MaterialTheme.colorScheme) {
if (isOutlined || !isScrolled) surface else surfaceContainer
}, label = "", animationSpec = spring(stiffness = Spring.StiffnessMediumLow))


Box(
modifier = Modifier
.fillMaxSize()
.zIndex(1f),
contentAlignment = Alignment.TopCenter
) {
Column(modifier = if (onClick == null) Modifier else Modifier.clickable(
onClick = onClick,
indication = null,
interactionSource = remember { MutableInteractionSource() }
)
Column(
modifier = Modifier.drawBehind { drawRect(containerColor) }
) {
Surface(
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(
WindowInsets.statusBars
.asPaddingValues()
.calculateTopPadding()
)
) {}
),
)
AnimatedVisibility(
visible = isShow,
enter = expandVertically(expandFrom = Alignment.Top),
exit = shrinkVertically(shrinkTowards = Alignment.Top)
enter = expandVertically(expandFrom = Alignment.Bottom),
exit = shrinkVertically(shrinkTowards = Alignment.Bottom)
) {
TopAppBar(
title = {},
modifier = Modifier,
modifier = if (onClick == null) Modifier else Modifier.clickable(
onClick = onClick,
indication = null,
interactionSource = remember { MutableInteractionSource() }
),
windowInsets = WindowInsets(0.dp),
navigationIcon = {
FeedbackIconButton(
Expand All @@ -95,7 +107,8 @@ fun TopBar(
) {
onClose()
}
}, actions = {
},
actions = {
FeedbackIconButton(
modifier = Modifier.size(22.dp),
imageVector = Icons.Outlined.Palette,
Expand All @@ -114,10 +127,11 @@ fun TopBar(
) {
sharedContent.share(context, title, link)
}
}, colors = TopAppBarDefaults.topAppBarColors()
},
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
)
}
if (showDivider) {
if (isOutlined && isScrolled) {
HorizontalDivider(
color = MaterialTheme.colorScheme.surfaceContainerHighest,
thickness = 0.5f.dp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,19 @@ fun ReadingStylePage(
onClick = { pullToSwitchArticle.toggle(context, scope) }) {
RYSwitch(activated = pullToSwitchArticle.value)
}
/* SettingItem(
Subtitle(
modifier = Modifier.padding(horizontal = 24.dp),
text = stringResource(R.string.toolbars)
)
SettingItem(
title = stringResource(R.string.tonal_elevation),
desc = "${tonalElevation.value}dp",
onClick = {
tonalElevationDialogVisible = true
},
) {}
Spacer(modifier = Modifier.height(24.dp))*/

Spacer(modifier = Modifier.height(24.dp))
}

// Advanced
Expand Down Expand Up @@ -271,7 +276,7 @@ fun ReadingStylePage(
}
)

/* RadioDialog(
RadioDialog(
visible = tonalElevationDialogVisible,
title = stringResource(R.string.tonal_elevation),
options = ReadingPageTonalElevationPreference.values.map {
Expand All @@ -284,7 +289,7 @@ fun ReadingStylePage(
}
) {
tonalElevationDialogVisible = false
}*/
}

RadioDialog(
visible = rendererDialogVisible,
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -460,4 +460,5 @@
<string name="mark_as_read_on_scroll">Mark as read on scroll</string>
<string name="become_a_sponsor">Become a sponsor</string>
<string name="sponsor_desc">We build and upkeep this free, open-source app in our off-hours. If you enjoy it, please consider supporting us with a small donation! ☕️</string>
<string name="toolbars">Toolbars</string>
</resources>

0 comments on commit 6e55c12

Please sign in to comment.