Open reading settings in the left-hand panel on large screens

On a tablet or an unfolded foldable the gear now opens reading settings
as a panel on the left, where the dictionary opens, instead of a bottom
sheet. The page stays in view beside it, so a change of theme, font,
weight or size shows on the poem as it is made. The sheet and the panel
share one ReadingSettingsContent; phones keep the sheet.

Adds wireframe 8 and notes in the design docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhmDdrN5hgWrgRcFLAMsV6
This commit is contained in:
Claude 2026-10-07 14:51:12 +00:00
parent f0c1dd5541
commit 8451cc45fb
No known key found for this signature in database
7 changed files with 85 additions and 6 deletions

View File

@ -31,7 +31,7 @@ The whole interface lays out and navigates right-to-left, whichever UI language
On a tablet or an unfolded foldable (600dp and wider) the poets become a narrow column on the right,
with the open poet's books, chapters and poems in columns beside it and the page in the rest of the
screen. The columns narrow while a poem is open and can be hidden for a reader view. The dictionary
opens in a panel to the left of the poem instead of over it. Phones are unchanged.
and reading settings open in a panel to the left of the poem instead of over it. Phones are unchanged.
## Fonts

View File

@ -1,9 +1,16 @@
package com.ganjoor.android.ui
import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@ -102,6 +109,10 @@ fun GanjoorApp() {
val wide by rememberUpdatedState(maxWidth >= 600.dp)
// Up to three list columns beside the poets; below this, only the newest one.
val expanded by rememberUpdatedState(maxWidth >= 840.dp)
// On a large screen reading settings open in a panel on the left, where the dictionary
// opens, so the page stays in view and shows each change as it is made.
Row(Modifier.fillMaxSize()) {
Box(Modifier.weight(1f)) {
NavHost(
navController = nav,
startDestination = PoetsRoute,
@ -226,8 +237,19 @@ fun GanjoorApp() {
}
}
}
if (wide) {
AnimatedVisibility(
visible = settingsOpen,
enter = expandHorizontally() + fadeIn(),
exit = shrinkHorizontally() + fadeOut(),
) {
ReadingSettingsPanel(onDismiss = { settingsOpen = false })
}
}
}
// Inside the provider: the sheet reads LocalOpenAbout, so it has to be in scope.
if (settingsOpen) ReadingSettingsSheet(onDismiss = { settingsOpen = false })
if (settingsOpen && !wide) ReadingSettingsSheet(onDismiss = { settingsOpen = false })
}
}
}

View File

@ -1,24 +1,32 @@
package com.ganjoor.android.ui
import android.app.Activity
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Slider
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.TextButton
import androidx.compose.material3.Text
@ -58,11 +66,53 @@ fun ReadingSettingsAction() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ReadingSettingsSheet(onDismiss: () -> Unit) {
ModalBottomSheet(onDismissRequest = onDismiss) {
ReadingSettingsContent()
}
}
/**
* The same settings as [ReadingSettingsSheet], as a panel on the left of a large screen — the
* place the dictionary opens too. The page stays in view beside it, so a change of theme, font
* or size shows on the poem itself as it is made. The cross, or Back, closes it.
*/
@Composable
fun ReadingSettingsPanel(onDismiss: () -> Unit) {
BackHandler(onBack = onDismiss)
Surface(
color = MaterialTheme.colorScheme.surfaceContainerLow,
modifier = Modifier.width(360.dp).fillMaxHeight(),
) {
Column(Modifier.statusBarsPadding()) {
Row(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
.padding(start = 20.dp, end = 4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResource(R.string.reading_settings),
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.weight(1f),
)
IconButton(onClick = onDismiss) {
Icon(Icons.Default.Close, stringResource(R.string.close))
}
}
HorizontalDivider(modifier = Modifier.padding(bottom = 8.dp))
ReadingSettingsContent()
}
}
}
@Composable
private fun ReadingSettingsContent() {
val settings = LocalSettings.current
val prefs = settings.value
val context = LocalContext.current
ModalBottomSheet(onDismissRequest = onDismiss) {
Column(
modifier = Modifier
// Inset first, then scroll: the viewport has to stop above the nav bar,
@ -148,7 +198,6 @@ fun ReadingSettingsSheet(onDismiss: () -> Unit) {
Text(stringResource(R.string.about))
}
}
}
}
@Composable

View File

@ -60,4 +60,4 @@ Poet portraits come from Ganjoor and are cropped into a circle on `secondary-con
Material Icons in the filled style, at 24px, tinted with colour roles (see the Icons group). Use the standard Android share glyph wherever there is sharing, because people recognise it before reading the label. The brand mark is the eight-pointed khatam star (see Logos). There is no wordmark: گنجور is set in Naskh.
## Large screens
Tablets and unfolded foldables use **ColumnBrowser**. Tapping a poet collapses the home grid into a narrow poets column on the far right (portrait with the name underneath). To its left come the poet's books, then the chapters or poems of the open book, each column scrolling on its own. Older columns narrow as new ones open, so the poem stays near the middle, and a top-bar button hides the columns when the reader wants to focus on the poem. Phones are unchanged.
Tablets and unfolded foldables use **ColumnBrowser**. Tapping a poet collapses the home grid into a narrow poets column on the far right (portrait with the name underneath). To its left come the poet's books, then the chapters or poems of the open book, each column scrolling on its own. Older columns narrow as new ones open, so the poem stays near the middle, and a top-bar button hides the columns when the reader wants to focus on the poem. The dictionary and reading settings open in a panel on the left, beside the poem rather than over it. Phones are unchanged.

View File

@ -1,6 +1,6 @@
# ColumnBrowser
The layout for tablets and unfolded foldables. A narrow column of poets sits on the right. Beside it is a column for each level of the open book (books › chapters › poems), and the open page fills the rest of the screen on the left. Phones keep today's navigation. Built in `app/src/main/java/com/ganjoor/android/ui/ColumnBrowser.kt`; wireframes are in `design/wireframes/`.
The layout for tablets and unfolded foldables. A narrow column of poets sits on the right. Beside it is a column for each level of the open book (books › chapters › poems), and the open page fills the rest of the screen on the left. Phones keep today's navigation. Built in `app/src/main/java/com/ganjoor/android/ui/ColumnBrowser.kt`; wireframes are in `design/wireframes/` (1–8).
## Window sizes
@ -46,6 +46,13 @@ On large screens, tapping a word opens **WordPanel** on the left instead of the
- The tapped word stays highlighted in the verse (`secondary-container` / `on-secondary-container`), on phones too.
- ✕ or Back closes the panel.
## Reading settings
On large screens the gear opens **ReadingSettingsPanel** on the left, where the dictionary opens, instead of the bottom sheet:
- It has the same width and surface as the dictionary panel, with a "Reading settings" header and a ✕ button. The settings and their order are the same as in the sheet.
- The page stays in view beside the panel, so a change of theme, font, weight or size shows on the poem as it's made.
- ✕ or Back closes it. Phones keep the bottom sheet.
## Loading
Nothing covers the whole screen while it loads, on phones as well:

View File

@ -7,3 +7,4 @@ The Material bottom sheet behind the gear icon: theme, OLED, font, weight, text
- Order: Theme chips → OLED toggle → Font chips → Weight chips → Text size slider (14–40, steps of 2) → **live preview** of a hemistich in the chosen reading style → Language chips → Offline mode → Show summaries → AI assistant, About & licences as TextButtons.
- Every group has a **SectionLabel**. Changes apply immediately; there is no Save.
- Changing language recreates the activity.
- On tablets and unfolded foldables the same settings open as a panel on the left instead (`ReadingSettingsPanel`, see ColumnBrowser), so the poem stays in view while they change.

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB