fix reader volume scroll option state
This commit is contained in:
@ -2,8 +2,14 @@ package app.omnivore.omnivore.feature.reader
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
@ -11,300 +17,289 @@ import androidx.compose.material.Switch
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.material3.AssistChip
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.omnivore.omnivore.R
|
||||
import app.omnivore.omnivore.core.designsystem.component.SwitchPreferenceWidget
|
||||
import app.omnivore.omnivore.feature.theme.OmnivoreTheme
|
||||
|
||||
@Composable
|
||||
fun ReaderPreferencesView(webReaderViewModel: WebReaderViewModel) {
|
||||
val isDark = isSystemInDarkTheme()
|
||||
val currentWebPreferences = webReaderViewModel.storedWebPreferences(isDark)
|
||||
val isFontListExpanded = remember { mutableStateOf(false) }
|
||||
val highContrastTextSwitchState = remember { mutableStateOf(currentWebPreferences.prefersHighContrastText) }
|
||||
fun ReaderPreferencesView(
|
||||
webReaderViewModel: WebReaderViewModel
|
||||
) {
|
||||
val isDark = isSystemInDarkTheme()
|
||||
val currentWebPreferences = webReaderViewModel.storedWebPreferences(isDark)
|
||||
val isFontListExpanded = remember { mutableStateOf(false) }
|
||||
val highContrastTextSwitchState =
|
||||
remember { mutableStateOf(currentWebPreferences.prefersHighContrastText) }
|
||||
|
||||
val justifyTextSwitchState = remember { mutableStateOf(currentWebPreferences.prefersJustifyText) }
|
||||
val justifyTextSwitchState =
|
||||
remember { mutableStateOf(currentWebPreferences.prefersJustifyText) }
|
||||
|
||||
val selectedWebFontName = remember { mutableStateOf(currentWebPreferences.fontFamily.displayText) }
|
||||
val selectedWebFontName =
|
||||
remember { mutableStateOf(currentWebPreferences.fontFamily.displayText) }
|
||||
|
||||
var fontSizeSliderValue by remember { mutableStateOf(currentWebPreferences.textFontSize.toFloat()) }
|
||||
var marginSliderValue by remember { mutableStateOf(currentWebPreferences.maxWidthPercentage.toFloat()) }
|
||||
var lineSpacingSliderValue by remember { mutableStateOf(currentWebPreferences.lineHeight.toFloat()) }
|
||||
var fontSizeSliderValue by remember { mutableStateOf(currentWebPreferences.textFontSize.toFloat()) }
|
||||
var marginSliderValue by remember { mutableStateOf(currentWebPreferences.maxWidthPercentage.toFloat()) }
|
||||
var lineSpacingSliderValue by remember { mutableStateOf(currentWebPreferences.lineHeight.toFloat()) }
|
||||
|
||||
val themeState = remember { mutableStateOf(currentWebPreferences.storedThemePreference) }
|
||||
val themeState = remember { mutableStateOf(currentWebPreferences.storedThemePreference) }
|
||||
|
||||
val volumeForScrollState = remember { mutableStateOf(currentWebPreferences.shouldUseVolumeRockerForScroll) }
|
||||
|
||||
OmnivoreTheme {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 15.dp)
|
||||
.padding(vertical = 35.dp)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 15.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text("Font", style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Box {
|
||||
AssistChip(
|
||||
onClick = { isFontListExpanded.value = true },
|
||||
label = { Text(selectedWebFontName.value, color = Color(red = 137, green = 137, blue = 137)) },
|
||||
trailingIcon = {
|
||||
Icon(
|
||||
Icons.Default.ArrowDropDown,
|
||||
contentDescription = "Choose the Reader font",
|
||||
tint = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
},
|
||||
)
|
||||
if (isFontListExpanded.value) {
|
||||
DropdownMenu(
|
||||
expanded = isFontListExpanded.value,
|
||||
onDismissRequest = { isFontListExpanded.value = false },
|
||||
) {
|
||||
WebFont.values().forEach {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(it.displayText, style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
},
|
||||
onClick = {
|
||||
webReaderViewModel.applyWebFont(it)
|
||||
selectedWebFontName.value = it.displayText
|
||||
isFontListExpanded.value = false
|
||||
},
|
||||
)
|
||||
val volumeForScrollState by webReaderViewModel.volumeRockerForScrollState.collectAsStateWithLifecycle()
|
||||
|
||||
OmnivoreTheme {
|
||||
// Temporary wrapping for margin while migrating components to design system
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 35.dp)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 15.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 15.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
"Font", style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Box {
|
||||
AssistChip(
|
||||
onClick = { isFontListExpanded.value = true },
|
||||
label = {
|
||||
Text(
|
||||
selectedWebFontName.value,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
Icon(
|
||||
Icons.Default.ArrowDropDown,
|
||||
contentDescription = "Choose the Reader font",
|
||||
tint = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
},
|
||||
)
|
||||
if (isFontListExpanded.value) {
|
||||
DropdownMenu(
|
||||
expanded = isFontListExpanded.value,
|
||||
onDismissRequest = { isFontListExpanded.value = false },
|
||||
) {
|
||||
WebFont.values().forEach {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(
|
||||
it.displayText, style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
webReaderViewModel.applyWebFont(it)
|
||||
selectedWebFontName.value = it.displayText
|
||||
isFontListExpanded.value = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_font_size), style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
Slider(
|
||||
value = fontSizeSliderValue,
|
||||
onValueChange = {
|
||||
fontSizeSliderValue = it
|
||||
webReaderViewModel.setFontSize(it.toInt())
|
||||
},
|
||||
steps = 40,
|
||||
valueRange = 10f..50f,
|
||||
)
|
||||
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_margin), style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
Slider(
|
||||
value = marginSliderValue,
|
||||
onValueChange = {
|
||||
marginSliderValue = it
|
||||
webReaderViewModel.setMaxWidthPercentage(it.toInt())
|
||||
},
|
||||
steps = 40,
|
||||
valueRange = 60f..100f,
|
||||
)
|
||||
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_line_spacing), style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
Slider(
|
||||
value = lineSpacingSliderValue,
|
||||
onValueChange = {
|
||||
lineSpacingSliderValue = it
|
||||
webReaderViewModel.setLineHeight(it.toInt())
|
||||
},
|
||||
steps = 50,
|
||||
valueRange = 100f..300f,
|
||||
)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 4.dp)
|
||||
) {
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_theme), style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_auto), style = TextStyle(
|
||||
fontSize = 10.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
Checkbox(checked = themeState.value == "System", onCheckedChange = {
|
||||
if (it) {
|
||||
themeState.value = "System"
|
||||
webReaderViewModel.updateStoredThemePreference("System")
|
||||
} else {
|
||||
val newThemeKey = if (isDark) "Black" else "Light"
|
||||
themeState.value = newThemeKey
|
||||
webReaderViewModel.updateStoredThemePreference(newThemeKey)
|
||||
}
|
||||
})
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
for (theme in Themes.values()) {
|
||||
if (theme.themeKey != "System") {
|
||||
val isSelected = theme.themeKey == themeState.value
|
||||
Button(
|
||||
onClick = {
|
||||
themeState.value = theme.themeKey
|
||||
webReaderViewModel.updateStoredThemePreference(theme.themeKey)
|
||||
},
|
||||
shape = CircleShape,
|
||||
border = BorderStroke(
|
||||
3.dp,
|
||||
if (isSelected) colorResource(R.color.cta_yellow) else Color.Transparent
|
||||
),
|
||||
modifier = Modifier.size(35.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
|
||||
containerColor = Color(theme.backgroundColor)
|
||||
)
|
||||
) {
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(0.1F))
|
||||
}
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(2.0F))
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_high_constrast_text),
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Switch(checked = highContrastTextSwitchState.value, onCheckedChange = {
|
||||
highContrastTextSwitchState.value = it
|
||||
webReaderViewModel.updateHighContrastTextPreference(it)
|
||||
})
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_justify_text),
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Switch(checked = justifyTextSwitchState.value, onCheckedChange = {
|
||||
justifyTextSwitchState.value = it
|
||||
webReaderViewModel.updateJustifyText(it)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(stringResource(R.string.reader_preferences_view_font_size), style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
Slider(
|
||||
value = fontSizeSliderValue,
|
||||
onValueChange = {
|
||||
fontSizeSliderValue = it
|
||||
webReaderViewModel.setFontSize(it.toInt())
|
||||
},
|
||||
steps = 40,
|
||||
valueRange = 10f..50f,
|
||||
)
|
||||
|
||||
Text(stringResource(R.string.reader_preferences_view_margin), style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
Slider(
|
||||
value = marginSliderValue,
|
||||
onValueChange = {
|
||||
marginSliderValue = it
|
||||
webReaderViewModel.setMaxWidthPercentage(it.toInt())
|
||||
},
|
||||
steps = 40,
|
||||
valueRange = 60f..100f,
|
||||
)
|
||||
|
||||
Text(stringResource(R.string.reader_preferences_view_line_spacing), style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
Slider(
|
||||
value = lineSpacingSliderValue,
|
||||
onValueChange = {
|
||||
lineSpacingSliderValue = it
|
||||
webReaderViewModel.setLineHeight(it.toInt())
|
||||
},
|
||||
steps = 50,
|
||||
valueRange = 100f..300f,
|
||||
)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.reader_preferences_view_theme), style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Text(stringResource(R.string.reader_preferences_view_auto), style = TextStyle(
|
||||
fontSize = 10.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
Checkbox(
|
||||
checked = themeState.value == "System",
|
||||
onCheckedChange = {
|
||||
if (it) {
|
||||
themeState.value = "System"
|
||||
webReaderViewModel.updateStoredThemePreference("System")
|
||||
} else {
|
||||
val newThemeKey = if (isDark) "Black" else "Light"
|
||||
themeState.value = newThemeKey
|
||||
webReaderViewModel.updateStoredThemePreference(newThemeKey)
|
||||
}
|
||||
})
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
for(theme in Themes.values()) {
|
||||
if (theme.themeKey != "System") {
|
||||
val isSelected = theme.themeKey == themeState.value
|
||||
Button(
|
||||
onClick = {
|
||||
themeState.value = theme.themeKey
|
||||
webReaderViewModel.updateStoredThemePreference(theme.themeKey)
|
||||
},
|
||||
shape = CircleShape,
|
||||
border = BorderStroke(3.dp, if (isSelected) colorResource(R.color.cta_yellow) else Color.Transparent),
|
||||
modifier = Modifier.size(35.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
|
||||
containerColor = Color(theme.backgroundColor)
|
||||
SwitchPreferenceWidget(
|
||||
title = stringResource(R.string.reader_preferences_view_volume_scroll),
|
||||
checked = volumeForScrollState,
|
||||
onCheckedChanged = { webReaderViewModel.setVolumeRockerForScrollState(it) },
|
||||
)
|
||||
) {
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(0.1F))
|
||||
}
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(2.0F))
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_high_constrast_text),
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Switch(
|
||||
checked = highContrastTextSwitchState.value,
|
||||
onCheckedChange = {
|
||||
highContrastTextSwitchState.value = it
|
||||
webReaderViewModel.updateHighContrastTextPreference(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_justify_text),
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137))
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Switch(
|
||||
checked = justifyTextSwitchState.value,
|
||||
onCheckedChange = {
|
||||
justifyTextSwitchState.value = it
|
||||
webReaderViewModel.updateJustifyText(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
stringResource(R.string.reader_preferences_view_volume_scroll),
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137))
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Switch (
|
||||
checked = volumeForScrollState.value,
|
||||
onCheckedChange = {
|
||||
volumeForScrollState.value = it
|
||||
webReaderViewModel.updateVolumeRockerForScroll(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Stepper(label: String, onIncrease: () -> Unit, onDecrease: () -> Unit) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = label,
|
||||
modifier = Modifier
|
||||
.padding(bottom = 6.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
|
||||
IconButton(onClick = { onDecrease() }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.minus),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
Divider(
|
||||
color = Color.Black,
|
||||
modifier = Modifier
|
||||
.height(20.dp)
|
||||
.width(1.dp)
|
||||
)
|
||||
|
||||
IconButton(onClick = { onIncrease() }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.plus),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class WebPreferences(
|
||||
val textFontSize: Int,
|
||||
val lineHeight: Int,
|
||||
val maxWidthPercentage: Int,
|
||||
val themeKey: String,
|
||||
val storedThemePreference: String,
|
||||
val fontFamily: WebFont,
|
||||
val prefersHighContrastText: Boolean,
|
||||
val prefersJustifyText: Boolean,
|
||||
var shouldUseVolumeRockerForScroll: Boolean
|
||||
val textFontSize: Int,
|
||||
val lineHeight: Int,
|
||||
val maxWidthPercentage: Int,
|
||||
val themeKey: String,
|
||||
val storedThemePreference: String,
|
||||
val fontFamily: WebFont,
|
||||
val prefersHighContrastText: Boolean,
|
||||
val prefersJustifyText: Boolean
|
||||
)
|
||||
|
||||
@ -22,6 +22,7 @@ import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.omnivore.omnivore.R
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -32,7 +33,9 @@ import java.util.*
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Composable
|
||||
fun WebReader(
|
||||
styledContent: String, webReaderViewModel: WebReaderViewModel, currentTheme: Themes?
|
||||
styledContent: String,
|
||||
webReaderViewModel: WebReaderViewModel,
|
||||
currentTheme: Themes?
|
||||
) {
|
||||
val javascriptActionLoopUUID: UUID by webReaderViewModel.javascriptActionLoopUUIDLiveData.observeAsState(
|
||||
UUID.randomUUID()
|
||||
@ -41,6 +44,8 @@ fun WebReader(
|
||||
|
||||
WebView.setWebContentsDebuggingEnabled(true)
|
||||
|
||||
val volumeForScrollState by webReaderViewModel.volumeRockerForScrollState.collectAsStateWithLifecycle()
|
||||
|
||||
Box {
|
||||
AndroidView(factory = {
|
||||
OmnivoreWebView(it).apply {
|
||||
@ -170,7 +175,7 @@ fun WebReader(
|
||||
if (event.action == KeyEvent.ACTION_DOWN) {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||
if (!webReaderViewModel.shouldUseVolumeRockerForScroll) {
|
||||
if (!volumeForScrollState) {
|
||||
return@setOnKeyListener false
|
||||
}
|
||||
scrollVertically(OmnivoreWebView.Direction.UP)
|
||||
@ -178,7 +183,7 @@ fun WebReader(
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||
if (!webReaderViewModel.shouldUseVolumeRockerForScroll) {
|
||||
if (!volumeForScrollState) {
|
||||
return@setOnKeyListener false
|
||||
}
|
||||
scrollVertically(OmnivoreWebView.Direction.DOWN)
|
||||
|
||||
@ -28,6 +28,7 @@ import app.omnivore.omnivore.core.database.dao.SavedItemDao
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItem
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItemLabel
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.followingTabActive
|
||||
import app.omnivore.omnivore.core.datastore.preferredTheme
|
||||
import app.omnivore.omnivore.core.datastore.preferredWebFontFamily
|
||||
import app.omnivore.omnivore.core.datastore.preferredWebFontSize
|
||||
@ -35,6 +36,7 @@ import app.omnivore.omnivore.core.datastore.preferredWebLineHeight
|
||||
import app.omnivore.omnivore.core.datastore.preferredWebMaxWidthPercentage
|
||||
import app.omnivore.omnivore.core.datastore.prefersJustifyText
|
||||
import app.omnivore.omnivore.core.datastore.prefersWebHighContrastText
|
||||
import app.omnivore.omnivore.core.datastore.volumeForScroll
|
||||
import app.omnivore.omnivore.core.network.Networker
|
||||
import app.omnivore.omnivore.core.network.createNewLabel
|
||||
import app.omnivore.omnivore.core.network.saveUrl
|
||||
@ -42,14 +44,16 @@ import app.omnivore.omnivore.core.network.savedItem
|
||||
import app.omnivore.omnivore.feature.components.HighlightColor
|
||||
import app.omnivore.omnivore.feature.library.SavedItemAction
|
||||
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import com.apollographql.apollo3.api.Optional.Companion.presentIfNotNull
|
||||
import com.google.gson.Gson
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -83,7 +87,7 @@ enum class Themes(
|
||||
|
||||
@HiltViewModel
|
||||
class WebReaderViewModel @Inject constructor(
|
||||
private val datastoreRepo: DatastoreRepository,
|
||||
private val datastoreRepository: DatastoreRepository,
|
||||
private val dataService: DataService,
|
||||
private val networker: Networker,
|
||||
private val eventTracker: EventTracker,
|
||||
@ -457,28 +461,27 @@ class WebReaderViewModel @Inject constructor(
|
||||
javascriptActionLoopUUIDLiveData.value = UUID.randomUUID()
|
||||
}
|
||||
|
||||
val currentThemeKey: LiveData<String> = datastoreRepo
|
||||
val currentThemeKey: LiveData<String> = datastoreRepository
|
||||
.themeKeyFlow
|
||||
.distinctUntilChanged()
|
||||
.asLiveData()
|
||||
|
||||
fun storedWebPreferences(isDarkMode: Boolean): WebPreferences = runBlocking {
|
||||
val storedFontSize = datastoreRepo.getInt(preferredWebFontSize)
|
||||
val storedLineHeight = datastoreRepo.getInt(preferredWebLineHeight)
|
||||
val storedMaxWidth = datastoreRepo.getInt(preferredWebMaxWidthPercentage)
|
||||
val storedFontSize = datastoreRepository.getInt(preferredWebFontSize)
|
||||
val storedLineHeight = datastoreRepository.getInt(preferredWebLineHeight)
|
||||
val storedMaxWidth = datastoreRepository.getInt(preferredWebMaxWidthPercentage)
|
||||
|
||||
val storedFontFamily =
|
||||
datastoreRepo.getString(preferredWebFontFamily) ?: WebFont.SYSTEM.rawValue
|
||||
datastoreRepository.getString(preferredWebFontFamily) ?: WebFont.SYSTEM.rawValue
|
||||
val storedThemePreference =
|
||||
datastoreRepo.getString(preferredTheme) ?: "System"
|
||||
datastoreRepository.getString(preferredTheme) ?: "System"
|
||||
val storedWebFont =
|
||||
WebFont.entries.firstOrNull { it.rawValue == storedFontFamily } ?: WebFont.entries
|
||||
.first()
|
||||
|
||||
val prefersHighContrastFont =
|
||||
datastoreRepo.getString(prefersWebHighContrastText) == "true"
|
||||
val prefersJustifyText = datastoreRepo.getString(DatastoreKeys.prefersJustifyText) == "true"
|
||||
val shouldUseVolumeRockerForScroll = datastoreRepo.getString(DatastoreKeys.volumeForScroll) != "false"
|
||||
datastoreRepository.getString(prefersWebHighContrastText) == "true"
|
||||
val prefersJustifyText = datastoreRepository.getString(prefersJustifyText) == "true"
|
||||
|
||||
WebPreferences(
|
||||
textFontSize = storedFontSize ?: 12,
|
||||
@ -488,8 +491,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
storedThemePreference = storedThemePreference,
|
||||
fontFamily = storedWebFont,
|
||||
prefersHighContrastText = prefersHighContrastFont,
|
||||
prefersJustifyText = prefersJustifyText,
|
||||
shouldUseVolumeRockerForScroll = shouldUseVolumeRockerForScroll
|
||||
prefersJustifyText = prefersJustifyText
|
||||
)
|
||||
}
|
||||
|
||||
@ -505,7 +507,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
Log.d("theme", "Setting theme key: $newThemeKey")
|
||||
|
||||
runBlocking {
|
||||
datastoreRepo.putString(preferredTheme, newThemeKey)
|
||||
datastoreRepository.putString(preferredTheme, newThemeKey)
|
||||
}
|
||||
|
||||
val script =
|
||||
@ -515,7 +517,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun setFontSize(newFontSize: Int) {
|
||||
runBlocking {
|
||||
datastoreRepo.putInt(preferredWebFontSize, newFontSize)
|
||||
datastoreRepository.putInt(preferredWebFontSize, newFontSize)
|
||||
}
|
||||
val script =
|
||||
"var event = new Event('updateFontSize');event.fontSize = '$newFontSize';document.dispatchEvent(event);"
|
||||
@ -524,7 +526,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun setMaxWidthPercentage(newMaxWidthPercentageValue: Int) {
|
||||
runBlocking {
|
||||
datastoreRepo.putInt(
|
||||
datastoreRepository.putInt(
|
||||
preferredWebMaxWidthPercentage,
|
||||
newMaxWidthPercentageValue
|
||||
)
|
||||
@ -536,7 +538,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun setLineHeight(newLineHeight: Int) {
|
||||
runBlocking {
|
||||
datastoreRepo.putInt(preferredWebLineHeight, newLineHeight)
|
||||
datastoreRepository.putInt(preferredWebLineHeight, newLineHeight)
|
||||
}
|
||||
val script =
|
||||
"var event = new Event('updateLineHeight');event.lineHeight = '$newLineHeight';document.dispatchEvent(event);"
|
||||
@ -545,7 +547,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun updateHighContrastTextPreference(prefersHighContrastText: Boolean) {
|
||||
runBlocking {
|
||||
datastoreRepo.putString(
|
||||
datastoreRepository.putString(
|
||||
prefersWebHighContrastText,
|
||||
prefersHighContrastText.toString()
|
||||
)
|
||||
@ -558,23 +560,30 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun updateJustifyText(justifyText: Boolean) {
|
||||
runBlocking {
|
||||
datastoreRepo.putString(prefersJustifyText, justifyText.toString())
|
||||
datastoreRepository.putString(prefersJustifyText, justifyText.toString())
|
||||
}
|
||||
val script =
|
||||
"var event = new Event('updateJustifyText');event.justifyText = $justifyText;document.dispatchEvent(event);"
|
||||
enqueueScript(script)
|
||||
}
|
||||
|
||||
fun updateVolumeRockerForScroll(shouldUseVolumeRockerForScroll: Boolean) {
|
||||
runBlocking {
|
||||
datastoreRepo.putString(DatastoreKeys.volumeForScroll, shouldUseVolumeRockerForScroll.toString())
|
||||
val volumeRockerForScrollState: StateFlow<Boolean> = datastoreRepository.getBoolean(
|
||||
volumeForScroll
|
||||
).stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Lazily,
|
||||
initialValue = false
|
||||
)
|
||||
|
||||
fun setVolumeRockerForScrollState(value: Boolean) {
|
||||
viewModelScope.launch {
|
||||
datastoreRepository.putBoolean(volumeForScroll, value)
|
||||
}
|
||||
this.shouldUseVolumeRockerForScroll = shouldUseVolumeRockerForScroll
|
||||
}
|
||||
|
||||
fun applyWebFont(font: WebFont) {
|
||||
runBlocking {
|
||||
datastoreRepo.putString(preferredWebFontFamily, font.rawValue)
|
||||
datastoreRepository.putString(preferredWebFontFamily, font.rawValue)
|
||||
}
|
||||
|
||||
val script =
|
||||
|
||||
Reference in New Issue
Block a user