Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.apadmi.mockzilla.desktop.i18n

import cafe.adriel.lyricist.LyricistStrings
import io.ktor.http.HttpStatusCode
import kotlin.math.roundToInt

@LyricistStrings(languageTag = "En", default = true)
val EnStrings = Strings(
Expand Down Expand Up @@ -128,7 +129,9 @@ val EnStrings = Strings(
miscControls = Strings.Widgets.MiscControls(
refreshAll = "Re-sync all",
clearOverrides = "Reset all overrides",
title = "Tools"
title = "Tools",
presentationMode = "Presentation mode",
fontScaleLabel = { scale -> "${(scale * 100).roundToInt()}%" }
),
unsupportedMockzilla = Strings.Widgets.UnsupportedMockzillaVersion(
heading = "Unsupported SDK",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,15 @@ data class Strings(
* @property refreshAll
* @property clearOverrides
* @property title
* @property presentationMode
* @property fontScaleLabel
*/
data class MiscControls(
val refreshAll: String,
val clearOverrides: String,
val title: String
val title: String,
val presentationMode: String,
val fontScaleLabel: (Float) -> String,
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.platform.LocalDensity
Expand Down Expand Up @@ -86,6 +90,13 @@ private val darkColors = darkColorScheme(
@Suppress("VARIABLE_NAME_INCORRECT_FORMAT")
val LocalForceDarkMode = compositionLocalOf { false }

@Suppress("VARIABLE_NAME_INCORRECT_FORMAT")
val LocalSetScaleFactor = compositionLocalOf<(Float) -> Unit> { { /* noop */ } }

data object ScaleFactor {
const val DEFAULT = 0.9F
}

@Composable
fun Modifier.alternatingBackground(index: Int) = background(
if (index % 2 == 0) {
Expand All @@ -106,12 +117,17 @@ fun AppTheme(
lightColors
}

var scaleFactor by rememberSaveable { mutableFloatStateOf(ScaleFactor.DEFAULT) }
ProvideLocalisableStrings {
ScaledDensity(scaleFactor = 0.9f) {
MaterialTheme(
colorScheme = colors,
content = content
)
CompositionLocalProvider(
LocalSetScaleFactor provides { scale -> scaleFactor = scale },
) {
ScaledDensity(scaleFactor = scaleFactor) {
MaterialTheme(
colorScheme = colors,
content = content
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,60 @@
package com.apadmi.mockzilla.desktop.ui.widgets.misccontrols

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.selection.toggleable
import androidx.compose.material3.Button
import androidx.compose.material3.Slider
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import com.apadmi.mockzilla.desktop.di.utils.getViewModel
import com.apadmi.mockzilla.desktop.engine.device.Device
import com.apadmi.mockzilla.desktop.i18n.LocalStrings
import com.apadmi.mockzilla.desktop.i18n.Strings
import com.apadmi.mockzilla.desktop.ui.theme.LocalSetScaleFactor
import com.apadmi.mockzilla.desktop.ui.theme.ScaleFactor
import org.koin.core.parameter.parametersOf

private data object PresentationModeScaleFactor {
const val MIN = 0.8F
const val MAX = 1.4F
const val DEFAULT = 1.2F

// These variables are in-memory caches for the state that we
// may want to save to disk in the future. Without an in-memory
// cache the compose state would reset on tab switches since the
// entire tab tree UI is removed from the composition on tab switching
// These are not themselves mutable state tracked by compose so we must
// ensure we don't reference these values outside of the defaults
// for setting up rememberSaveable states.
var enabled = false
var scaleFactor = DEFAULT
}

@Composable
fun MiscControlsWidget(
device: Device?
) {
val viewModel = getViewModel<MiscControlsViewModel>(key = device?.toString()) { parametersOf(device) }
MiscControlsWidgetContent(
onRefreshAll = viewModel::refreshAllData,
onClearAllOverrides = viewModel::clearAllOverrides
onClearAllOverrides = viewModel::clearAllOverrides,
)
}

Expand All @@ -33,4 +70,73 @@ fun MiscControlsWidgetContent(
Button(onClick = onClearAllOverrides) {
Text(strings.widgets.miscControls.clearOverrides)
}
var presentationMode by rememberSaveable { mutableStateOf(PresentationModeScaleFactor.enabled) }
var presentationModeScaleFactor by rememberSaveable {
mutableFloatStateOf(PresentationModeScaleFactor.scaleFactor)
}
val setScaleFactor = LocalSetScaleFactor.current
PresentationModeSettings(
presentationMode = presentationMode,
onPresentationModeChange = { presentationModeEnabled ->
presentationMode = presentationModeEnabled
PresentationModeScaleFactor.enabled = presentationModeEnabled
if (presentationModeEnabled) {
setScaleFactor(presentationModeScaleFactor)
} else {
setScaleFactor(ScaleFactor.DEFAULT)
}
},
presentationModeScaleFactor = presentationModeScaleFactor,
onPresentationModeScaleFactorChange = { scaleFactor ->
setScaleFactor(scaleFactor)
presentationModeScaleFactor = scaleFactor
PresentationModeScaleFactor.scaleFactor = scaleFactor
},
)
}

@Composable
private fun PresentationModeSettings(
presentationMode: Boolean,
onPresentationModeChange: (Boolean) -> Unit,
presentationModeScaleFactor: Float,
onPresentationModeScaleFactorChange: (Float) -> Unit,
strings: Strings = LocalStrings.current
) = Column {
Row(
modifier = Modifier
.toggleable(
value = presentationMode,
onValueChange = { checked ->
onPresentationModeChange(checked)
},
role = Role.Switch,
)
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = strings.widgets.miscControls.presentationMode,
)
Spacer(modifier = Modifier.width(4.dp))
Switch(
checked = presentationMode,
onCheckedChange = null,
)
}
AnimatedVisibility(visible = presentationMode) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize().padding(horizontal = 12.dp),
) {
Slider(
value = presentationModeScaleFactor,
onValueChange = { onPresentationModeScaleFactorChange(it) },
steps = 5,
valueRange = PresentationModeScaleFactor.MIN..PresentationModeScaleFactor.MAX,
)
Text(text = strings.widgets.miscControls.fontScaleLabel(presentationModeScaleFactor))
}
}
Spacer(modifier = Modifier.height(4.dp))
}