Reuse baseline-aligned headers with source subtitle typography
This commit is contained in:
parent
b1b15b384b
commit
4e62aad638
6 changed files with 18 additions and 20 deletions
|
|
@ -357,6 +357,7 @@
|
||||||
"badgeIcon": {"$type":"dimension","px":28,"dp":14,"source":"index.html:142"},
|
"badgeIcon": {"$type":"dimension","px":28,"dp":14,"source":"index.html:142"},
|
||||||
"seeAllGap": {"$type":"dimension","px":8,"dp":4,"source":"index.html:146"},
|
"seeAllGap": {"$type":"dimension","px":8,"dp":4,"source":"index.html:146"},
|
||||||
"tailDescription": {"$type":"typography","px":24,"sp":12,"weight":500,"$value":{"fontWeight":500},"source":"index.html:301"},
|
"tailDescription": {"$type":"typography","px":24,"sp":12,"weight":500,"$value":{"fontWeight":500},"source":"index.html:301"},
|
||||||
|
"headerSubtitle": {"$type":"typography","px":30,"sp":15,"weight":400,"$value":{"fontWeight":400},"source":"index.html:201"},
|
||||||
"imageReads": {"$type":"number","$value":4,"source":"spec 4.9, tokens.json image.concurrentReads"},
|
"imageReads": {"$type":"number","$value":4,"source":"spec 4.9, tokens.json image.concurrentReads"},
|
||||||
"unknownCriticOpacity": {"$type":"number","$value":0.55,"source":"spec 4.7, index.html:161"},
|
"unknownCriticOpacity": {"$type":"number","$value":0.55,"source":"spec 4.7, index.html:161"},
|
||||||
"fallbackPadding": {"$type":"dimension","px":22,"dp":11,"source":"index.html:130"},
|
"fallbackPadding": {"$type":"dimension","px":22,"dp":11,"source":"index.html:130"},
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ fun DiscoverScreen(state: DiscoverState, modifier: Modifier = Modifier) {
|
||||||
if (state.hasHero && state.service == null && list.firstVisibleItemIndex == 0) state.hero?.let { DiscoverBackdrop(it, modifier = Modifier.graphicsLayer { translationY = -list.firstVisibleItemScrollOffset.toFloat() }) }
|
if (state.hasHero && state.service == null && list.firstVisibleItemIndex == 0) state.hero?.let { DiscoverBackdrop(it, modifier = Modifier.graphicsLayer { translationY = -list.firstVisibleItemScrollOffset.toFloat() }) }
|
||||||
LazyColumn(state = list, contentPadding = PaddingValues(bottom = (WolfskinTokens.Shell.stageHeight - L.pinnedLine - heights.last()).coerceAtLeast(D.frameBottomMin)), modifier = Modifier.fillMaxSize()) {
|
LazyColumn(state = list, contentPadding = PaddingValues(bottom = (WolfskinTokens.Shell.stageHeight - L.pinnedLine - heights.last()).coerceAtLeast(D.frameBottomMin)), modifier = Modifier.fillMaxSize()) {
|
||||||
item(key = "discover-header", contentType = if (state.hasHero && state.service == null) "hero" else "header") {
|
item(key = "discover-header", contentType = if (state.hasHero && state.service == null) "hero" else "header") {
|
||||||
if (state.hasHero && state.service == null) DiscoverHero(state) else DiscoverHeader(state.shell.person, state.service?.name ?: "Discover", if (state.service != null) "General interest" else "")
|
if (state.hasHero && state.service == null) DiscoverHero(state) else LibraryHeader(state.shell.person, state.service?.name ?: "Discover", if (state.service != null) "General interest" else "")
|
||||||
}
|
}
|
||||||
item(key = "discover-chips", contentType = "chips") {
|
item(key = "discover-chips", contentType = "chips") {
|
||||||
if (state.snapshot.status !in setOf(DiscoverStatus.NeedsSignIn, DiscoverStatus.Unavailable, DiscoverStatus.Loading)) DiscoverChips(state)
|
if (state.snapshot.status !in setOf(DiscoverStatus.NeedsSignIn, DiscoverStatus.Unavailable, DiscoverStatus.Loading)) DiscoverChips(state)
|
||||||
|
|
@ -116,16 +116,6 @@ fun DiscoverScreen(state: DiscoverState, modifier: Modifier = Modifier) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Header and type chips use the same safe area as the shell. */
|
|
||||||
@Composable
|
|
||||||
private fun DiscoverHeader(person: ShellPerson, title: String, subtitle: String) {
|
|
||||||
Row(Modifier.fillMaxWidth().height(L.row_lhead).padding(start = L.safeSide, top = D.headerTop), horizontalArrangement = Arrangement.spacedBy(D.headerGap), verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
Avatar(person, WolfskinTokens.Shell.settingsHeaderAvatar, WolfskinTokens.Type.avatarLetterLibHeader, letterColor = C.muted)
|
|
||||||
Text(title, color = C.fg, style = WolfskinTokens.Type.screenTitle)
|
|
||||||
if (subtitle.isNotEmpty()) Text(subtitle, color = C.muted, style = WolfskinTokens.Type.nav)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DiscoverHero(state: DiscoverState) {
|
private fun DiscoverHero(state: DiscoverState) {
|
||||||
val title = state.hero ?: return
|
val title = state.hero ?: return
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ fun LibraryScreen(
|
||||||
val active = !shell.navFocused && !shell.pickerVisible
|
val active = !shell.navFocused && !shell.pickerVisible
|
||||||
val items = grid.items
|
val items = grid.items
|
||||||
val focused = grid.focusedTitle
|
val focused = grid.focusedTitle
|
||||||
|
val count = if (grid.catalogue) items.size else grid.source.size
|
||||||
var plateKey by remember { mutableStateOf<String?>(null) }
|
var plateKey by remember { mutableStateOf<String?>(null) }
|
||||||
DisposableEffect(shell, grid, registerFocus) {
|
DisposableEffect(shell, grid, registerFocus) {
|
||||||
if (registerFocus) shell.contentFocus = grid
|
if (registerFocus) shell.contentFocus = grid
|
||||||
|
|
@ -104,7 +105,11 @@ fun LibraryScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, contentPadding = PaddingValues(bottom = WolfskinTokens.Shell.stageHeight - L.pinnedLine - rowHeight)) {
|
}, contentPadding = PaddingValues(bottom = WolfskinTokens.Shell.stageHeight - L.pinnedLine - rowHeight)) {
|
||||||
item(key = "header", contentType = "header") { LibraryHeader(grid, shell.person) }
|
item(key = "header", contentType = "header") {
|
||||||
|
LibraryHeader(shell.person, grid.title,
|
||||||
|
if (grid.status != LibraryStatus.Ready) "" else "$count ${if (grid.catalogue) "titles" else if (grid.title == "Movies") if (count == 1) "film" else "films" else "series"}",
|
||||||
|
grid.savedAt)
|
||||||
|
}
|
||||||
if (headerCount == 2) item(key = "toolbar", contentType = "chips") { LibraryToolbar(grid, active) }
|
if (headerCount == 2) item(key = "toolbar", contentType = "chips") { LibraryToolbar(grid, active) }
|
||||||
when (grid.status) {
|
when (grid.status) {
|
||||||
LibraryStatus.Loading -> items(3, key = { "skeleton-$it" }, contentType = { "grid" }) {
|
LibraryStatus.Loading -> items(3, key = { "skeleton-$it" }, contentType = { "grid" }) {
|
||||||
|
|
@ -157,15 +162,15 @@ fun LibraryScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Library, catalogue and service headers share one baseline and person treatment. */
|
||||||
@Composable
|
@Composable
|
||||||
private fun LibraryHeader(grid: LibraryGridState, person: ShellPerson) {
|
fun LibraryHeader(person: ShellPerson, title: String, subtitle: String = "", savedAt: String? = null) {
|
||||||
val count = if (grid.catalogue) grid.items.size else grid.source.size
|
|
||||||
Box(Modifier.fillMaxWidth().height(L.row_lhead)) {
|
Box(Modifier.fillMaxWidth().height(L.row_lhead)) {
|
||||||
Row(Modifier.offset(L.safeSide, L.navBand), horizontalArrangement = Arrangement.spacedBy(WolfskinTokens.Shell.settingsHeaderGap), verticalAlignment = Alignment.CenterVertically) {
|
Row(Modifier.offset(L.safeSide, L.navBand), horizontalArrangement = Arrangement.spacedBy(WolfskinTokens.Shell.settingsHeaderGap), verticalAlignment = Alignment.CenterVertically) {
|
||||||
Avatar(person, WolfskinTokens.Shell.settingsHeaderAvatar, WolfskinTokens.Type.avatarLetterLibHeader, letterColor = C.muted)
|
Avatar(person, WolfskinTokens.Shell.settingsHeaderAvatar, WolfskinTokens.Type.avatarLetterLibHeader, letterColor = C.muted)
|
||||||
Text(grid.title, modifier = Modifier.alignByBaseline(), color = C.fg, style = WolfskinTokens.Type.screenTitle)
|
Text(title, modifier = Modifier.alignByBaseline(), color = C.fg, style = WolfskinTokens.Type.screenTitle)
|
||||||
Text(if (grid.status != LibraryStatus.Ready) "" else "$count ${if (grid.catalogue) "titles" else if (grid.title == "Movies") if (count == 1) "film" else "films" else "series"}", modifier = Modifier.alignByBaseline(), color = C.muted, style = WolfskinTokens.Type.nav.copy(fontWeight = FontWeight.Normal))
|
if (subtitle.isNotEmpty()) Text(subtitle, modifier = Modifier.alignByBaseline(), color = C.muted, style = G.headerSubtitle)
|
||||||
grid.savedAt?.let { Text("Saved $it", color = C.warn, style = WolfskinTokens.Type.caption) }
|
savedAt?.let { Text("Saved $it", color = C.warn, style = WolfskinTokens.Type.caption) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -325,6 +325,7 @@ object WolfskinTokens {
|
||||||
val badgeIcon = 14.0.dp
|
val badgeIcon = 14.0.dp
|
||||||
val seeAllGap = 4.0.dp
|
val seeAllGap = 4.0.dp
|
||||||
val tailDescription = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight(500), lineHeight = 15.600000000000001.sp, letterSpacing = 0.0.em)
|
val tailDescription = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight(500), lineHeight = 15.600000000000001.sp, letterSpacing = 0.0.em)
|
||||||
|
val headerSubtitle = TextStyle(fontSize = 15.0.sp, fontWeight = FontWeight(400), lineHeight = 19.5.sp, letterSpacing = 0.0.em)
|
||||||
const val imageReads = 4.0f
|
const val imageReads = 4.0f
|
||||||
const val unknownCriticOpacity = 0.55f
|
const val unknownCriticOpacity = 0.55f
|
||||||
val fallbackPadding = 11.0.dp
|
val fallbackPadding = 11.0.dp
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,7 @@
|
||||||
--library-badgeIcon: 28.0px;
|
--library-badgeIcon: 28.0px;
|
||||||
--library-seeAllGap: 8.0px;
|
--library-seeAllGap: 8.0px;
|
||||||
--library-tailDescription: 24.0px;
|
--library-tailDescription: 24.0px;
|
||||||
|
--library-headerSubtitle: 30.0px;
|
||||||
--library-fallbackPadding: 22.0px;
|
--library-fallbackPadding: 22.0px;
|
||||||
--library-fallbackIcon: 44.0px;
|
--library-fallbackIcon: 44.0px;
|
||||||
--discover-sheetPaddingX: 64.0px;
|
--discover-sheetPaddingX: 64.0px;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
ffc070ec958ece59f2e8eecd1144f43cdaf7fdb53fe51b178f1b17457ea4151a discover-tokens.json
|
ffc070ec958ece59f2e8eecd1144f43cdaf7fdb53fe51b178f1b17457ea4151a discover-tokens.json
|
||||||
fcff646d59fb39e859c34c05037e05a7fb7583de2fe07315ec0176cf4d597980 generate_tokens.py
|
fcff646d59fb39e859c34c05037e05a7fb7583de2fe07315ec0176cf4d597980 generate_tokens.py
|
||||||
17c45415eb8e334a31a8b187ad2e2c960c35b58e565b19fbbcc9cb5e10717a3a shell-tokens.json
|
050823bdd2bb71181a7b7c849e412129f312a150a27c2e5b9b3fbc1f5ccece0f shell-tokens.json
|
||||||
9359aaa6f81650ccfa46c3f0a76d128ea229ff16d79573b342804cc4cb12330e src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt
|
ab20caec74fcbedadfbc59449b227a11a62cf79e8bc862d5f95ec95d1b8574db src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt
|
||||||
b230411658c4b82e7f9e1677842c60bbf61939567958075fff277bc0561e00ec tokens.css
|
4b741830cda8b905d71f97bf88ee8d6cca3e1cf0f881bc06c5525cbf05378808 tokens.css
|
||||||
5b939f1f3eb90b428008fda75720f6e3a4e844c486668931db3d52bffb987b53 tokens.json
|
5b939f1f3eb90b428008fda75720f6e3a4e844c486668931db3d52bffb987b53 tokens.json
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue