General improvements (#50)
* Implemented long-press gestures(on the left and right region) for rapid scrolling(to top or bottom) in Musician Mode for both EPUB and PDF readers. * Added support for book-specific reader settings and redesigned the format adjustment UI. * perf: implement persistent caching and parallel parsing for single-file imports - Replaced random UUID generation with bookId-based pathing in SingleFileImporter to enable cache reuse. - Added a JSON metadata fast-path to return EpubBook objects instantly on subsequent opens for MD, TXT, and HTML. - Parallelized Markdown chapter parsing using Coroutines (async/awaitAll) to leverage multicore CPUs.
This commit is contained in:
parent
ef1bfdc57a
commit
acf282d4c7
6 changed files with 684 additions and 299 deletions
|
|
@ -29,7 +29,12 @@ import androidx.compose.animation.fadeOut
|
|||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
|
@ -37,19 +42,16 @@ 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.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
|
|
@ -84,6 +86,7 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.text.font.Font
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.edit
|
||||
import com.aryan.reader.R
|
||||
import com.aryan.reader.data.CustomFontEntity
|
||||
|
|
@ -116,6 +119,89 @@ enum class ReaderTextAlign(val id: String, val cssValue: String, val iconResId:
|
|||
JUSTIFY("justify", "justify", R.drawable.format_align_justify, "Justify")
|
||||
}
|
||||
|
||||
data class FormatSettings(
|
||||
val fontSize: Float,
|
||||
val lineHeight: Float,
|
||||
val font: ReaderFont,
|
||||
val customPath: String?,
|
||||
val textAlign: ReaderTextAlign
|
||||
)
|
||||
|
||||
private const val FORMAT_IS_LOCAL_PREFIX = "format_is_local_"
|
||||
private const val LOCAL_FONT_SIZE_PREFIX = "local_font_size_"
|
||||
private const val LOCAL_LINE_HEIGHT_PREFIX = "local_line_height_"
|
||||
private const val LOCAL_FONT_FAMILY_PREFIX = "local_font_family_"
|
||||
private const val LOCAL_TEXT_ALIGN_PREFIX = "local_text_align_"
|
||||
|
||||
fun loadFormatIsLocal(context: Context, bookId: String): Boolean {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
return prefs.getBoolean(FORMAT_IS_LOCAL_PREFIX + bookId, false)
|
||||
}
|
||||
|
||||
fun saveFormatIsLocal(context: Context, bookId: String, isLocal: Boolean) {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
prefs.edit { putBoolean(FORMAT_IS_LOCAL_PREFIX + bookId, isLocal) }
|
||||
}
|
||||
|
||||
fun saveLocalReaderSettings(
|
||||
context: Context,
|
||||
bookId: String,
|
||||
fontSize: Float,
|
||||
lineHeight: Float,
|
||||
fontFamily: ReaderFont,
|
||||
customFontPath: String?,
|
||||
textAlign: ReaderTextAlign
|
||||
) {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
prefs.edit {
|
||||
putFloat(LOCAL_FONT_SIZE_PREFIX + bookId, fontSize)
|
||||
putFloat(LOCAL_LINE_HEIGHT_PREFIX + bookId, lineHeight)
|
||||
if (customFontPath != null) {
|
||||
putString(LOCAL_FONT_FAMILY_PREFIX + bookId, "custom|$customFontPath")
|
||||
} else {
|
||||
putString(LOCAL_FONT_FAMILY_PREFIX + bookId, fontFamily.id)
|
||||
}
|
||||
putString(LOCAL_TEXT_ALIGN_PREFIX + bookId, textAlign.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadFormatSettings(context: Context, bookId: String, isLocal: Boolean): FormatSettings {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
|
||||
val fontSize = if (isLocal && prefs.contains(LOCAL_FONT_SIZE_PREFIX + bookId)) {
|
||||
prefs.getFloat(LOCAL_FONT_SIZE_PREFIX + bookId, DEFAULT_FONT_SIZE_VAL)
|
||||
} else {
|
||||
prefs.getFloat(FONT_SIZE_KEY, DEFAULT_FONT_SIZE_VAL)
|
||||
}
|
||||
|
||||
val lineHeight = if (isLocal && prefs.contains(LOCAL_LINE_HEIGHT_PREFIX + bookId)) {
|
||||
prefs.getFloat(LOCAL_LINE_HEIGHT_PREFIX + bookId, DEFAULT_LINE_HEIGHT_VAL)
|
||||
} else {
|
||||
prefs.getFloat(LINE_HEIGHT_KEY, DEFAULT_LINE_HEIGHT_VAL)
|
||||
}
|
||||
|
||||
val savedFontVal = if (isLocal && prefs.contains(LOCAL_FONT_FAMILY_PREFIX + bookId)) {
|
||||
prefs.getString(LOCAL_FONT_FAMILY_PREFIX + bookId, ReaderFont.ORIGINAL.id) ?: ReaderFont.ORIGINAL.id
|
||||
} else {
|
||||
prefs.getString(FONT_FAMILY_KEY, ReaderFont.ORIGINAL.id) ?: ReaderFont.ORIGINAL.id
|
||||
}
|
||||
|
||||
val (font, customPath) = if (savedFontVal.startsWith("custom|")) {
|
||||
Pair(ReaderFont.ORIGINAL, savedFontVal.substringAfter("custom|"))
|
||||
} else {
|
||||
Pair(ReaderFont.entries.find { it.id == savedFontVal } ?: ReaderFont.ORIGINAL, null)
|
||||
}
|
||||
|
||||
val alignId = if (isLocal && prefs.contains(LOCAL_TEXT_ALIGN_PREFIX + bookId)) {
|
||||
prefs.getString(LOCAL_TEXT_ALIGN_PREFIX + bookId, ReaderTextAlign.DEFAULT.id)
|
||||
} else {
|
||||
prefs.getString(TEXT_ALIGN_KEY, ReaderTextAlign.DEFAULT.id)
|
||||
}
|
||||
val textAlign = ReaderTextAlign.entries.find { it.id == alignId } ?: ReaderTextAlign.DEFAULT
|
||||
|
||||
return FormatSettings(fontSize, lineHeight, font, customPath, textAlign)
|
||||
}
|
||||
|
||||
fun getComposeFontFamily(
|
||||
font: ReaderFont,
|
||||
customFontPath: String? = null,
|
||||
|
|
@ -147,19 +233,6 @@ fun getComposeFontFamily(
|
|||
return FontFamily.Default
|
||||
}
|
||||
|
||||
fun loadFontSelection(context: Context): Pair<ReaderFont, String?> {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
val savedVal = prefs.getString(FONT_FAMILY_KEY, ReaderFont.ORIGINAL.id) ?: ReaderFont.ORIGINAL.id
|
||||
|
||||
return if (savedVal.startsWith("custom|")) {
|
||||
val path = savedVal.substringAfter("custom|")
|
||||
Pair(ReaderFont.ORIGINAL, path)
|
||||
} else {
|
||||
val font = ReaderFont.entries.find { it.id == savedVal } ?: ReaderFont.ORIGINAL
|
||||
Pair(font, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveReaderSettings(
|
||||
context: Context,
|
||||
fontSize: Float,
|
||||
|
|
@ -181,22 +254,6 @@ fun saveReaderSettings(
|
|||
}
|
||||
}
|
||||
|
||||
fun loadFontSize(context: Context): Float {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
return prefs.getFloat(FONT_SIZE_KEY, DEFAULT_FONT_SIZE_VAL)
|
||||
}
|
||||
|
||||
fun loadLineHeight(context: Context): Float {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
return prefs.getFloat(LINE_HEIGHT_KEY, DEFAULT_LINE_HEIGHT_VAL)
|
||||
}
|
||||
|
||||
fun loadTextAlign(context: Context): ReaderTextAlign {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
val id = prefs.getString(TEXT_ALIGN_KEY, ReaderTextAlign.DEFAULT.id)
|
||||
return ReaderTextAlign.entries.find { it.id == id } ?: ReaderTextAlign.DEFAULT
|
||||
}
|
||||
|
||||
fun saveAutoScrollSpeed(context: Context, speed: Float) {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
prefs.edit { putFloat(AUTO_SCROLL_SPEED_KEY, speed) }
|
||||
|
|
@ -240,6 +297,9 @@ fun ReaderTextFormatPanel(
|
|||
currentTextAlign: ReaderTextAlign,
|
||||
onTextAlignChange: (ReaderTextAlign) -> Unit,
|
||||
onReset: () -> Unit,
|
||||
isLocalMode: Boolean,
|
||||
onLocalModeToggle: (Boolean) -> Unit,
|
||||
onClose: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
|
|
@ -249,40 +309,106 @@ fun ReaderTextFormatPanel(
|
|||
modifier = modifier
|
||||
) {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.surface,
|
||||
tonalElevation = 8.dp,
|
||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||
shadowElevation = 8.dp,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
shape = RoundedCornerShape(28.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = 0.95f),
|
||||
tonalElevation = 0.dp,
|
||||
shadowElevation = 0.dp,
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.8f)),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(24.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(24.dp)
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text("Font Family", style = MaterialTheme.typography.labelLarge)
|
||||
Box {
|
||||
var showModeMenu by remember { mutableStateOf(false) }
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.clickable { showModeMenu = true }
|
||||
.padding(4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = if (isLocalMode) "Local Format" else "Global Format",
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowDropDown,
|
||||
contentDescription = "Select Mode",
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu(expanded = showModeMenu, onDismissRequest = { showModeMenu = false }) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Column {
|
||||
Text("Global Format", style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Bold)
|
||||
Text("Applies to all files", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
}
|
||||
},
|
||||
onClick = { onLocalModeToggle(false); showModeMenu = false },
|
||||
trailingIcon = { if (!isLocalMode) Icon(Icons.Default.Check, null) }
|
||||
)
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Column {
|
||||
Text("Local Format", style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Bold)
|
||||
Text("Saved for this file only", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
}
|
||||
},
|
||||
onClick = { onLocalModeToggle(true); showModeMenu = false },
|
||||
trailingIcon = { if (isLocalMode) Icon(Icons.Default.Check, null) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
TextButton(onClick = onReset, contentPadding = PaddingValues(horizontal = 8.dp)) {
|
||||
Text("Reset")
|
||||
}
|
||||
IconButton(onClick = onClose, modifier = Modifier.size(32.dp)) {
|
||||
Icon(Icons.Default.Close, "Close", tint = MaterialTheme.colorScheme.error, modifier = Modifier.size(18.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Surface(
|
||||
onClick = onFontOptionClick,
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
color = MaterialTheme.colorScheme.secondaryContainer,
|
||||
modifier = Modifier.height(40.dp)
|
||||
modifier = Modifier
|
||||
.weight(0.45f)
|
||||
.height(48.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.padding(horizontal = 12.dp)
|
||||
) {
|
||||
val displayName = currentCustomFontName ?: currentFont.displayName
|
||||
Text(
|
||||
text = displayName,
|
||||
text = currentCustomFontName ?: currentFont.displayName,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
maxLines = 1, overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
|
||||
contentDescription = null,
|
||||
|
|
@ -291,117 +417,69 @@ fun ReaderTextFormatPanel(
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
Surface(
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
modifier = Modifier
|
||||
.weight(0.55f)
|
||||
.height(48.dp)
|
||||
) {
|
||||
Text("Font Size", style = MaterialTheme.typography.labelLarge)
|
||||
Text(
|
||||
"%.1fx".format(currentFontSize),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
Slider(
|
||||
value = currentFontSize,
|
||||
onValueChange = onFontSizeChange,
|
||||
valueRange = 0.5f..3.0f,
|
||||
steps = 24,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text("Line Spacing", style = MaterialTheme.typography.labelLarge)
|
||||
Text(
|
||||
"%.1fx".format(currentLineHeight),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
Slider(
|
||||
value = currentLineHeight,
|
||||
onValueChange = onLineHeightChange,
|
||||
valueRange = 1.0f..2.5f,
|
||||
steps = 14,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box {
|
||||
var alignmentMenuExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
Surface(
|
||||
onClick = { alignmentMenuExpanded = true },
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(8.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = androidx.compose.ui.res.painterResource(id = currentTextAlign.iconResId),
|
||||
contentDescription = "Text Alignment",
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowDropDown,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = alignmentMenuExpanded,
|
||||
onDismissRequest = { alignmentMenuExpanded = false }
|
||||
) {
|
||||
Row {
|
||||
ReaderTextAlign.entries.forEach { align ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(align.displayName) },
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painter = androidx.compose.ui.res.painterResource(id = align.iconResId),
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (align == currentTextAlign) {
|
||||
Icon(Icons.Default.Check, contentDescription = "Selected")
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
onTextAlignChange(align)
|
||||
alignmentMenuExpanded = false
|
||||
}
|
||||
)
|
||||
val isSelected = currentTextAlign == align
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.background(if (isSelected) MaterialTheme.colorScheme.primary else Color.Transparent)
|
||||
.clickable { onTextAlignChange(align) },
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Icon(
|
||||
painter = androidx.compose.ui.res.painterResource(id = align.iconResId),
|
||||
contentDescription = align.displayName,
|
||||
tint = if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
Text(
|
||||
text = align.displayName,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontSize = 10.sp,
|
||||
color = if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextButton(onClick = onReset) {
|
||||
Text("Reset Defaults")
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
// Sliders
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Text("Size", style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(55.dp))
|
||||
Slider(
|
||||
value = currentFontSize,
|
||||
onValueChange = onFontSizeChange,
|
||||
valueRange = 0.5f..3.0f,
|
||||
steps = 24,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Text("%.1fx".format(currentFontSize), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(35.dp), textAlign = TextAlign.End)
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Text("Spacing", style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(55.dp))
|
||||
Slider(
|
||||
value = currentLineHeight,
|
||||
onValueChange = onLineHeightChange,
|
||||
valueRange = 1.0f..2.5f,
|
||||
steps = 14,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Text("%.1fx".format(currentLineHeight), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(35.dp), textAlign = TextAlign.End)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -485,7 +563,7 @@ fun FontSelectionSheetContent(
|
|||
items(customFonts) { fontEntity ->
|
||||
val isSelected = currentCustomFontPath == fontEntity.path
|
||||
val fontFamily = remember(fontEntity.path) {
|
||||
try { FontFamily(androidx.compose.ui.text.font.Font(File(fontEntity.path))) } catch(_:Exception) { FontFamily.Default }
|
||||
try { FontFamily(Font(File(fontEntity.path))) } catch(_:Exception) { FontFamily.Default }
|
||||
}
|
||||
|
||||
ListItem(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue