mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Use a bottom sheet for theme, set header based on theme
This commit is contained in:
parent
34f0a964ec
commit
135ecbaa11
3 changed files with 368 additions and 252 deletions
|
|
@ -1,47 +1,31 @@
|
|||
package app.omnivore.omnivore.ui.reader
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
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.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.unit.sp
|
||||
import app.omnivore.omnivore.R
|
||||
import app.omnivore.omnivore.ui.components.SegmentedControl
|
||||
|
||||
@Composable
|
||||
fun WebPreferencesDialog(onDismiss: () -> Unit, webReaderViewModel: WebReaderViewModel) {
|
||||
Dialog(onDismissRequest = { onDismiss() }) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
color = Color.White,
|
||||
modifier = Modifier
|
||||
.height(350.dp)
|
||||
) {
|
||||
WebPreferencesView(webReaderViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
import app.omnivore.omnivore.ui.theme.OmnivoreTheme
|
||||
|
||||
@Composable
|
||||
fun WebPreferencesView(webReaderViewModel: WebReaderViewModel) {
|
||||
|
|
@ -54,125 +38,207 @@ fun WebPreferencesView(webReaderViewModel: WebReaderViewModel) {
|
|||
|
||||
val selectedWebFontRawValue = remember { mutableStateOf(currentWebPreferences.fontFamily.rawValue) }
|
||||
|
||||
|
||||
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 themeListState = rememberLazyListState()
|
||||
|
||||
OmnivoreTheme() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(top = 6.dp, start = 6.dp, end = 6.dp, bottom = 6.dp)
|
||||
.padding(horizontal = 15.dp)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp, bottom = 12.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
.padding(bottom = 15.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text("Web Preferences")
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Stepper(
|
||||
label = "Font Size:",
|
||||
onIncrease = { webReaderViewModel.updateFontSize(isIncrease = true) },
|
||||
onDecrease = { webReaderViewModel.updateFontSize(isIncrease = false) }
|
||||
)
|
||||
|
||||
Stepper(
|
||||
label = "Margin:",
|
||||
onIncrease = { webReaderViewModel.updateMaxWidthPercentage(isIncrease = false) },
|
||||
onDecrease = { webReaderViewModel.updateMaxWidthPercentage(isIncrease = true) }
|
||||
)
|
||||
|
||||
Stepper(
|
||||
label = "Line Spacing:",
|
||||
onIncrease = { webReaderViewModel.updateLineSpacing(isIncrease = true) },
|
||||
onDecrease = { webReaderViewModel.updateLineSpacing(isIncrease = false) }
|
||||
)
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("High Contrast Text")
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Switch(
|
||||
checked = highContrastTextSwitchState.value,
|
||||
onCheckedChange = {
|
||||
highContrastTextSwitchState.value = it
|
||||
webReaderViewModel.updateHighContrastTextPreference(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Justify Text")
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Switch(
|
||||
checked = justifyTextSwitchState.value,
|
||||
onCheckedChange = {
|
||||
justifyTextSwitchState.value = it
|
||||
webReaderViewModel.updateJustifyText(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
) {
|
||||
Text("Theme:")
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
SegmentedControl(
|
||||
items = webReaderViewModel.systemThemeKeys,
|
||||
initialSelectedItemIndex = webReaderViewModel.systemThemeKeys.indexOf(currentWebPreferences.storedThemePreference)
|
||||
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 {
|
||||
OutlinedButton(
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
onClick = { isFontListExpanded.value = true },
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
contentColor = Color(red = 137, green = 137, blue = 137),
|
||||
// containerColor = Color.Transparent,
|
||||
),
|
||||
) {
|
||||
webReaderViewModel.updateStoredThemePreference(it, isDark)
|
||||
Text(selectedWebFontRawValue.value)
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clickable(onClick = { isFontListExpanded.value = !isFontListExpanded.value })
|
||||
) {
|
||||
Text("Font Family")
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Icon(
|
||||
imageVector =
|
||||
if (isFontListExpanded.value)
|
||||
Icons.Filled.KeyboardArrowDown
|
||||
else
|
||||
Icons.Filled.KeyboardArrowRight,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
if (isFontListExpanded.value) {
|
||||
WebFont.values().forEach {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
webReaderViewModel.applyWebFont(it)
|
||||
selectedWebFontRawValue.value = it.rawValue
|
||||
})
|
||||
if (isFontListExpanded.value) {
|
||||
DropdownMenu(
|
||||
expanded = isFontListExpanded.value,
|
||||
onDismissRequest = { isFontListExpanded.value = false }
|
||||
) {
|
||||
Text(
|
||||
it.displayText,
|
||||
modifier = Modifier
|
||||
.padding(top = 6.dp, start = 6.dp, end = 6.dp, bottom = 6.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
if (it.rawValue == selectedWebFontRawValue.value) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Check,
|
||||
contentDescription = null
|
||||
WebFont.values().forEach {
|
||||
DropdownMenuItem(
|
||||
text = { Text(it.displayText) },
|
||||
onClick = {
|
||||
webReaderViewModel.applyWebFont(it)
|
||||
selectedWebFontRawValue.value = it.rawValue
|
||||
isFontListExpanded.value = false
|
||||
},
|
||||
colors = MenuDefaults.itemColors(
|
||||
textColor = Color(red = 137, green = 137, blue = 137),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text("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 = 10,
|
||||
valueRange = 8f..28f,
|
||||
)
|
||||
|
||||
Text("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 = 4,
|
||||
valueRange = 60f..100f,
|
||||
)
|
||||
|
||||
Text("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 = 8,
|
||||
valueRange = 100f..300f,
|
||||
)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
) {
|
||||
Text("Theme:", style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(red = 137, green = 137, blue = 137)
|
||||
))
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
Text("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", isDark)
|
||||
} else {
|
||||
val newThemeKey = if (isDark) "Black" else "Light"
|
||||
themeState.value = newThemeKey
|
||||
webReaderViewModel.updateStoredThemePreference(newThemeKey, isDark)
|
||||
}
|
||||
})
|
||||
}
|
||||
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, isDark)
|
||||
},
|
||||
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("High Contrast 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("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)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Stepper(label: String, onIncrease: () -> Unit, onDecrease: () -> Unit) {
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ import androidx.activity.viewModels
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
|
@ -25,6 +27,7 @@ import androidx.compose.runtime.*
|
|||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
|
|
@ -42,9 +45,8 @@ import app.omnivore.omnivore.ui.theme.OmnivoreTheme
|
|||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlin.math.roundToInt
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import app.omnivore.omnivore.Routes
|
||||
import app.omnivore.omnivore.ui.notebook.NotebookActivity
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
|
|
@ -105,6 +107,7 @@ class WebReaderLoadingContainerActivity: ComponentActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, onLibraryIconTap: (() -> Unit)? = null, webReaderViewModel: WebReaderViewModel) {
|
||||
val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
|
||||
|
|
@ -112,6 +115,10 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
|
|||
var isMenuExpanded by remember { mutableStateOf(false) }
|
||||
var showWebPreferencesDialog by remember { mutableStateOf(false ) }
|
||||
|
||||
val isDark = isSystemInDarkTheme()
|
||||
val currentWebPreferences = webReaderViewModel.storedWebPreferences(isDark)
|
||||
val currentTheme = Themes.values().find { it.themeKey == currentWebPreferences.themeKey }
|
||||
|
||||
val webReaderParams: WebReaderParams? by webReaderViewModel.webReaderParamsLiveData.observeAsState(null)
|
||||
val annotation: String? by webReaderViewModel.annotationLiveData.observeAsState(null)
|
||||
val shouldPopView: Boolean by webReaderViewModel.shouldPopViewLiveData.observeAsState(false)
|
||||
|
|
@ -123,6 +130,7 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
|
|||
webReaderViewModel.loadItem(slug = slug, requestID = requestID)
|
||||
|
||||
val context = LocalContext.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val styledContent = webReaderParams?.let {
|
||||
val webReaderContent = WebReaderContent(
|
||||
|
|
@ -133,111 +141,169 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
|
|||
webReaderContent.styledContent()
|
||||
} ?: null
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.background(color = backgroundColor)
|
||||
) {
|
||||
if (styledContent != null) {
|
||||
WebReader(
|
||||
preferences = webReaderViewModel.storedWebPreferences(isSystemInDarkTheme()),
|
||||
styledContent = styledContent,
|
||||
webReaderViewModel = webReaderViewModel
|
||||
)
|
||||
val modalBottomSheetState = rememberModalBottomSheetState(
|
||||
ModalBottomSheetValue.Hidden,
|
||||
)
|
||||
|
||||
TopAppBar(
|
||||
modifier = Modifier
|
||||
.height(height = with(LocalDensity.current) {
|
||||
toolbarHeightPx.roundToInt().toDp()
|
||||
}),
|
||||
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
title = {},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = {
|
||||
onBackPressedDispatcher?.onBackPressed()
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = androidx.compose.material.icons.Icons.Filled.ArrowBack,
|
||||
modifier = Modifier,
|
||||
contentDescription = "Back"
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
if (onLibraryIconTap != null) {
|
||||
IconButton(onClick = { onLibraryIconTap() }) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Home,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
webReaderParams?.let {
|
||||
ModalBottomSheetLayout(
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
sheetBackgroundColor = Color.Transparent,
|
||||
sheetState = modalBottomSheetState,
|
||||
sheetContent = {
|
||||
if (showWebPreferencesDialog) {
|
||||
BottomSheetUI("Reader Preferences") {
|
||||
WebPreferencesView(webReaderViewModel)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
}
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.background(color = backgroundColor)
|
||||
) {
|
||||
if (styledContent != null) {
|
||||
WebReader(
|
||||
preferences = webReaderViewModel.storedWebPreferences(isSystemInDarkTheme()),
|
||||
styledContent = styledContent,
|
||||
webReaderViewModel = webReaderViewModel
|
||||
)
|
||||
|
||||
TopAppBar(
|
||||
modifier = Modifier
|
||||
.height(height = with(LocalDensity.current) {
|
||||
toolbarHeightPx.roundToInt().toDp()
|
||||
}),
|
||||
backgroundColor = Color(currentTheme?.backgroundColor ?: 0xFFFFFFFF), // MaterialTheme.colorScheme.surfaceVariant,
|
||||
title = {},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = {
|
||||
val intent = Intent(context, NotebookActivity::class.java)
|
||||
intent.putExtra("SAVED_ITEM_ID", it.item.savedItemId)
|
||||
context.startActivity(intent)
|
||||
onBackPressedDispatcher?.onBackPressed()
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.notebook),
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
modifier = Modifier,
|
||||
contentDescription = "Back"
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
if (onLibraryIconTap != null) {
|
||||
IconButton(onClick = { onLibraryIconTap() }) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Home,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
webReaderParams?.let {
|
||||
IconButton(onClick = {
|
||||
val intent = Intent(context, NotebookActivity::class.java)
|
||||
intent.putExtra("SAVED_ITEM_ID", it.item.savedItemId)
|
||||
context.startActivity(intent)
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.notebook),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
IconButton(onClick = {
|
||||
showWebPreferencesDialog = true
|
||||
coroutineScope.launch {
|
||||
modalBottomSheetState.show()
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.format_letter_case),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
IconButton(onClick = { showWebPreferencesDialog = true }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.format_letter_case),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
IconButton(onClick = { isMenuExpanded = true }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.dots_horizontal),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
SavedItemContextMenu(
|
||||
isExpanded = isMenuExpanded,
|
||||
isArchived = webReaderParams!!.item.isArchived,
|
||||
onDismiss = { isMenuExpanded = false },
|
||||
actionHandler = {
|
||||
webReaderViewModel.handleSavedItemAction(
|
||||
webReaderParams!!.item.savedItemId,
|
||||
it
|
||||
IconButton(onClick = { isMenuExpanded = true }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.dots_horizontal),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
SavedItemContextMenu(
|
||||
isExpanded = isMenuExpanded,
|
||||
isArchived = webReaderParams!!.item.isArchived,
|
||||
onDismiss = { isMenuExpanded = false },
|
||||
actionHandler = {
|
||||
webReaderViewModel.handleSavedItemAction(
|
||||
webReaderParams!!.item.savedItemId,
|
||||
it
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (annotation != null) {
|
||||
AnnotationEditView(
|
||||
initialAnnotation = annotation!!,
|
||||
onSave = {
|
||||
webReaderViewModel.saveAnnotation(it)
|
||||
},
|
||||
onCancel = {
|
||||
webReaderViewModel.cancelAnnotationEdit()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (showWebPreferencesDialog) {
|
||||
WebPreferencesDialog(
|
||||
onDismiss = {
|
||||
showWebPreferencesDialog = false
|
||||
},
|
||||
webReaderViewModel = webReaderViewModel
|
||||
)
|
||||
WebReaderLabelsSelectionSheet(webReaderViewModel)
|
||||
}
|
||||
|
||||
if (annotation != null) {
|
||||
AnnotationEditView(
|
||||
initialAnnotation = annotation!!,
|
||||
onSave = {
|
||||
webReaderViewModel.saveAnnotation(it)
|
||||
},
|
||||
onCancel = {
|
||||
webReaderViewModel.cancelAnnotationEdit()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
WebReaderLabelsSelectionSheet(webReaderViewModel)
|
||||
}
|
||||
|
||||
LaunchedEffect(shouldPopView) {
|
||||
if (shouldPopView) {
|
||||
onBackPressedDispatcher?.onBackPressed()
|
||||
LaunchedEffect(shouldPopView) {
|
||||
if (shouldPopView) {
|
||||
onBackPressedDispatcher?.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun BottomSheetUI(title: String?, content: @Composable () -> Unit) {
|
||||
val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.wrapContentHeight()
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(topEnd = 20.dp, topStart = 20.dp))
|
||||
.background(Color.White)
|
||||
.statusBarsPadding()
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text(title ?: "") },
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.background
|
||||
),
|
||||
// navigationIcon = {
|
||||
// IconButton(onClick = {
|
||||
// onBackPressedDispatcher?.onBackPressed()
|
||||
// }) {
|
||||
// Icon(
|
||||
// imageVector = Icons.Filled.ArrowBack,
|
||||
// modifier = Modifier,
|
||||
// contentDescription = "Back"
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.fillMaxSize()) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,15 @@ data class AnnotationWebViewMessage(
|
|||
val annotation: String?
|
||||
)
|
||||
|
||||
enum class Themes(val themeKey: String, val backgroundColor: Long) {
|
||||
SYSTEM("System", 0xFFFFFFFF),
|
||||
LIGHT("Light", 0xFF000000),
|
||||
SEPIA("Sepia", 0xFFFBF0D9),
|
||||
DARK("Dark", 0xFF2a2a2a),
|
||||
APOLLO("Apollo", 0xFF6A6968),
|
||||
BLACK("Black", 0xFFFFFFFF),
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
class WebReaderViewModel @Inject constructor(
|
||||
private val datastoreRepo: DatastoreRepository,
|
||||
|
|
@ -56,9 +65,6 @@ class WebReaderViewModel @Inject constructor(
|
|||
val showLabelsSelectionSheetLiveData = MutableLiveData(false)
|
||||
val savedItemLabelsLiveData = dataService.db.savedItemLabelDao().getSavedItemLabelsLiveData()
|
||||
|
||||
// "Sepia", "Apollo",
|
||||
val systemThemeKeys = listOf("Light", "Black", "System")
|
||||
|
||||
var hasTappedExistingHighlight = false
|
||||
var lastTapCoordinates: TapCoordinates? = null
|
||||
private var isLoading = false
|
||||
|
|
@ -288,59 +294,37 @@ class WebReaderViewModel @Inject constructor(
|
|||
return storedThemePreference
|
||||
}
|
||||
|
||||
fun updateStoredThemePreference(index: Int, isDarkMode: Boolean) {
|
||||
val newThemeKey = themeKey(isDarkMode, systemThemeKeys[index])
|
||||
fun updateStoredThemePreference(newThemeKey: String, isDarkMode: Boolean) {
|
||||
Log.d("theme", "Setting theme key: ${newThemeKey}")
|
||||
|
||||
runBlocking {
|
||||
datastoreRepo.putString(DatastoreKeys.preferredTheme, systemThemeKeys[index])
|
||||
datastoreRepo.putString(DatastoreKeys.preferredTheme, newThemeKey)
|
||||
}
|
||||
|
||||
val script = "var event = new Event('updateTheme');event.themeName = '$newThemeKey';document.dispatchEvent(event);"
|
||||
enqueueScript(script)
|
||||
}
|
||||
|
||||
fun updateFontSize(isIncrease: Boolean) {
|
||||
val delta = if (isIncrease) 2 else -2
|
||||
var newFontSize: Int
|
||||
|
||||
fun setFontSize(newFontSize: Int) {
|
||||
runBlocking {
|
||||
val storedFontSize = datastoreRepo.getInt(DatastoreKeys.preferredWebFontSize)
|
||||
newFontSize = ((storedFontSize ?: 12) + delta).coerceIn(8, 28)
|
||||
datastoreRepo.putInt(DatastoreKeys.preferredWebFontSize, newFontSize)
|
||||
}
|
||||
|
||||
// Get value from data store and then update it
|
||||
val script = "var event = new Event('updateFontSize');event.fontSize = '$newFontSize';document.dispatchEvent(event);"
|
||||
enqueueScript(script)
|
||||
}
|
||||
|
||||
fun updateMaxWidthPercentage(isIncrease: Boolean) {
|
||||
val delta = if (isIncrease) 10 else -10
|
||||
var newMaxWidthPercentageValue: Int
|
||||
|
||||
fun setMaxWidthPercentage(newMaxWidthPercentageValue: Int) {
|
||||
runBlocking {
|
||||
val storedWidth = datastoreRepo.getInt(DatastoreKeys.preferredWebMaxWidthPercentage)
|
||||
newMaxWidthPercentageValue = ((storedWidth ?: 100) + delta).coerceIn(40, 100)
|
||||
datastoreRepo.putInt(DatastoreKeys.preferredWebMaxWidthPercentage, newMaxWidthPercentageValue)
|
||||
}
|
||||
|
||||
// Get value from data store and then update it
|
||||
val script = "var event = new Event('updateMaxWidthPercentage');event.maxWidthPercentage = '$newMaxWidthPercentageValue';document.dispatchEvent(event);"
|
||||
enqueueScript(script)
|
||||
}
|
||||
|
||||
fun updateLineSpacing(isIncrease: Boolean) {
|
||||
val delta = if (isIncrease) 25 else -25
|
||||
var newLineHeight: Int
|
||||
|
||||
fun setLineHeight(newLineHeight: Int) {
|
||||
runBlocking {
|
||||
val storedHeight = datastoreRepo.getInt(DatastoreKeys.preferredWebLineHeight)
|
||||
newLineHeight = ((storedHeight ?: 150) + delta).coerceIn(100, 300)
|
||||
datastoreRepo.putInt(DatastoreKeys.preferredWebLineHeight, newLineHeight)
|
||||
}
|
||||
|
||||
// Get value from data store and then update it
|
||||
val script = "var event = new Event('updateLineHeight');event.lineHeight = '$newLineHeight';document.dispatchEvent(event);"
|
||||
enqueueScript(script)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue