From 95acdc75e8a93fc2e921229c77fdfbb4ff8228b4 Mon Sep 17 00:00:00 2001 From: Joe Reeve Date: Sat, 11 Jan 2025 22:41:50 +0000 Subject: [PATCH] :sparkles: Add generic settings panel --- .../stonephone/stonecamera/StoneCameraApp.kt | 24 ++- .../stonecamera/plugins/AspectRatio.kt | 10 +- .../stonephone/stonecamera/plugins/Debug.kt | 2 +- .../stonephone/stonecamera/plugins/Flash.kt | 56 +++--- .../stonephone/stonecamera/plugins/IPlugin.kt | 11 +- .../stonecamera/plugins/QRScanner.kt | 114 +++++++----- .../stonecamera/plugins/SettingsTray.kt | 168 ++++++++++++++++++ .../stonecamera/plugins/VolumeControls.kt | 10 +- .../stonephone/stonecamera/plugins/ZoomBar.kt | 3 - .../stonecamera/ui/RenderPluginSetting.kt | 21 +-- 10 files changed, 319 insertions(+), 100 deletions(-) create mode 100644 app/src/main/java/co/stonephone/stonecamera/plugins/SettingsTray.kt diff --git a/app/src/main/java/co/stonephone/stonecamera/StoneCameraApp.kt b/app/src/main/java/co/stonephone/stonecamera/StoneCameraApp.kt index b8048f9..bb724ce 100644 --- a/app/src/main/java/co/stonephone/stonecamera/StoneCameraApp.kt +++ b/app/src/main/java/co/stonephone/stonecamera/StoneCameraApp.kt @@ -1,4 +1,6 @@ // StoneCameraApp.kt +@file:kotlin.OptIn(ExperimentalMaterial3Api::class) + package co.stonephone.stonecamera import android.annotation.SuppressLint @@ -10,6 +12,12 @@ import androidx.camera.lifecycle.ProcessCameraProvider import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.FlipCameraAndroid +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.* @@ -27,6 +35,7 @@ import co.stonephone.stonecamera.plugins.PhotoModePlugin import co.stonephone.stonecamera.plugins.PinchToZoomPlugin import co.stonephone.stonecamera.plugins.QRScannerPlugin import co.stonephone.stonecamera.plugins.SettingLocation +import co.stonephone.stonecamera.plugins.SettingsTrayPlugin import co.stonephone.stonecamera.plugins.ShutterFlashPlugin import co.stonephone.stonecamera.plugins.TapToFocusPlugin import co.stonephone.stonecamera.plugins.VolumeControlsPlugin @@ -53,10 +62,13 @@ val PLUGINS = listOf( VolumeControlsPlugin(), PhotoModePlugin(), VideoModePlugin(), + SettingsTrayPlugin() // DebugPlugin() ) -@OptIn(ExperimentalCamera2Interop::class) +@OptIn( + ExperimentalCamera2Interop::class +) @SuppressLint("ClickableViewAccessibility") @Composable fun StoneCameraApp( @@ -141,8 +153,13 @@ fun StoneCameraApp( .align(Alignment.BottomCenter), verticalArrangement = Arrangement.SpaceBetween ) { - plugins.map { - it.renderTray(stoneCameraViewModel, it) + + Box( + modifier = Modifier.fillMaxWidth(), + ) { + plugins.map { + it.renderTray(stoneCameraViewModel, it) + } } // Translucent overlay for mode switch & shutter @@ -179,5 +196,6 @@ fun StoneCameraApp( } } } + } } diff --git a/app/src/main/java/co/stonephone/stonecamera/plugins/AspectRatio.kt b/app/src/main/java/co/stonephone/stonecamera/plugins/AspectRatio.kt index 63c19ee..fa2f60c 100644 --- a/app/src/main/java/co/stonephone/stonecamera/plugins/AspectRatio.kt +++ b/app/src/main/java/co/stonephone/stonecamera/plugins/AspectRatio.kt @@ -1,6 +1,5 @@ package co.stonephone.stonecamera.plugins -import android.app.Application import android.util.Size import androidx.camera.core.AspectRatio import androidx.camera.core.ImageCapture @@ -14,7 +13,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import co.stonephone.stonecamera.MyApplication @@ -175,10 +173,10 @@ class AspectRatioPlugin : IPlugin { key = "aspectRatio", defaultValue = "16:9", options = listOf("16:9", "4:3", "FULL"), - render = { value -> + render = { value, isSelected -> Text( text = value, - color = Color.White, + color = if (isSelected) Color(0xFFFFCC00) else Color.White, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold, modifier = Modifier @@ -193,9 +191,9 @@ class AspectRatioPlugin : IPlugin { previewView!!.scaleType = PreviewView.ScaleType.FIT_CENTER } viewModel.recreateUseCases() - }, - renderLocation = SettingLocation.TOP + renderLocation = SettingLocation.TOP, + label = "Aspect Ratio" ) ) } diff --git a/app/src/main/java/co/stonephone/stonecamera/plugins/Debug.kt b/app/src/main/java/co/stonephone/stonecamera/plugins/Debug.kt index 8ed6754..0c8b6c4 100644 --- a/app/src/main/java/co/stonephone/stonecamera/plugins/Debug.kt +++ b/app/src/main/java/co/stonephone/stonecamera/plugins/Debug.kt @@ -51,7 +51,7 @@ class DebugPlugin : IPlugin { x = visibleRegion!!.left.dp, y = visibleRegion!!.top.dp ) - .border(2.dp, Color.Yellow) + .border(2.dp, Color(0xAAFFCC00)) .padding(16.dp), contentAlignment = Alignment.TopCenter ) { } diff --git a/app/src/main/java/co/stonephone/stonecamera/plugins/Flash.kt b/app/src/main/java/co/stonephone/stonecamera/plugins/Flash.kt index 93bf10c..4c4095d 100644 --- a/app/src/main/java/co/stonephone/stonecamera/plugins/Flash.kt +++ b/app/src/main/java/co/stonephone/stonecamera/plugins/Flash.kt @@ -2,12 +2,17 @@ package co.stonephone.stonecamera.plugins import android.util.Log import androidx.camera.core.ImageCapture +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FlashAuto import androidx.compose.material.icons.filled.FlashOff import androidx.compose.material.icons.filled.FlashOn import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp import co.stonephone.stonecamera.StoneCameraViewModel class FlashPlugin : IPlugin { @@ -19,8 +24,7 @@ class FlashPlugin : IPlugin { } override fun onImageCapture( - viewModel: StoneCameraViewModel, - imageCapture: ImageCapture.Builder + viewModel: StoneCameraViewModel, imageCapture: ImageCapture.Builder ): ImageCapture.Builder { val flashMode = viewModel.getSetting("flash") ?: "OFF" val mode = flashModeStringToMode(flashMode) @@ -40,33 +44,37 @@ class FlashPlugin : IPlugin { } } - override val settings = { viewModel: StoneCameraViewModel -> + override val settings: (StoneCameraViewModel) -> List = { viewModel -> listOf( PluginSetting.EnumSetting( key = "flash", + label = "Flash", defaultValue = "OFF", options = listOf("OFF", "ON", "AUTO"), - render = { flashMode -> - Icon( - imageVector = when (flashMode) { - "OFF" -> Icons.Default.FlashOff // Replace with your preferred icon - "ON" -> Icons.Default.FlashOn - "AUTO" -> Icons.Default.FlashAuto // You may need to add custom icons for Flash Auto - else -> { - Icons.Default.FlashOff - } - }, - contentDescription = when (flashMode) { - "OFF" -> "Flash Off" - "ON" -> "Flash On" - "AUTO" -> "Flash Auto" - else -> { - "Flash" - } - }, - tint = Color.White // Customize as needed - ) - + render = { flashMode, isSelected -> + Box( + modifier = Modifier.padding(8.dp) + ) { + Icon( + imageVector = when (flashMode) { + "OFF" -> Icons.Default.FlashOff // Replace with your preferred icon + "ON" -> Icons.Default.FlashOn + "AUTO" -> Icons.Default.FlashAuto // You may need to add custom icons for Flash Auto + else -> { + Icons.Default.FlashOff + } + }, + contentDescription = when (flashMode) { + "OFF" -> "Flash Off" + "ON" -> "Flash On" + "AUTO" -> "Flash Auto" + else -> { + "Flash" + } + }, + tint = if (isSelected) Color(0xFFFFCC00) else Color.White + ) + } }, onChange = { viewModel, value -> viewModel.recreateUseCases() diff --git a/app/src/main/java/co/stonephone/stonecamera/plugins/IPlugin.kt b/app/src/main/java/co/stonephone/stonecamera/plugins/IPlugin.kt index a38ab56..d8a2b5d 100644 --- a/app/src/main/java/co/stonephone/stonecamera/plugins/IPlugin.kt +++ b/app/src/main/java/co/stonephone/stonecamera/plugins/IPlugin.kt @@ -2,7 +2,6 @@ package co.stonephone.stonecamera.plugins import android.content.ContentValues import android.media.Image -import androidx.camera.core.ImageAnalysis import androidx.camera.core.ImageCapture import androidx.camera.core.ImageProxy import androidx.camera.core.Preview @@ -115,6 +114,7 @@ enum class SettingLocation { sealed class PluginSetting( val key: String, val defaultValue: Any?, + val label: String, val onChange: (StoneCameraViewModel, Any?) -> Unit, val renderLocation: SettingLocation? = SettingLocation.NONE, ) { @@ -122,13 +122,15 @@ sealed class PluginSetting( class EnumSetting( key: String, defaultValue: String, + label: String, renderLocation: SettingLocation? = SettingLocation.NONE, val options: List, - val render: @Composable (value: String) -> Unit, + val render: @Composable (value: String, Boolean) -> Unit, onChange: (StoneCameraViewModel, String) -> Unit ) : PluginSetting( key, defaultValue, + label, onChange as (StoneCameraViewModel, Any?) -> Unit, renderLocation ) @@ -137,6 +139,7 @@ sealed class PluginSetting( key: String, defaultValue: Float, renderLocation: SettingLocation? = SettingLocation.NONE, + label: String, val minValue: Float, val maxValue: Float, val stepValue: Float? = null, @@ -144,6 +147,7 @@ sealed class PluginSetting( ) : PluginSetting( key, defaultValue, + label, onChange as (StoneCameraViewModel, Any?) -> Unit, renderLocation ) @@ -151,8 +155,9 @@ sealed class PluginSetting( class CustomSetting( key: String, defaultValue: String, + label: String, renderLocation: SettingLocation? = SettingLocation.NONE, val customRender: @Composable (StoneCameraViewModel, Any?, (Any?) -> Unit) -> Unit, // Render function with a callback for value changes onChange: (StoneCameraViewModel, Any?) -> Unit - ) : PluginSetting(key, defaultValue, onChange, renderLocation) + ) : PluginSetting(key, defaultValue, label, onChange, renderLocation) } \ No newline at end of file diff --git a/app/src/main/java/co/stonephone/stonecamera/plugins/QRScanner.kt b/app/src/main/java/co/stonephone/stonecamera/plugins/QRScanner.kt index aaa083c..7da2ebb 100644 --- a/app/src/main/java/co/stonephone/stonecamera/plugins/QRScanner.kt +++ b/app/src/main/java/co/stonephone/stonecamera/plugins/QRScanner.kt @@ -5,7 +5,6 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent -import android.graphics.RectF import android.media.Image import android.net.Uri import android.os.Handler @@ -23,6 +22,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -52,19 +52,20 @@ class QRScannerPlugin : IPlugin { var scanner: BarcodeScanner? = null var value by mutableStateOf(null) - var barcodePos by mutableStateOf(null) + var qrScannerEnabled by mutableStateOf("ON") private val handler = Handler(Looper.getMainLooper()) private var clearValueRunnable: Runnable? = null @SuppressLint("ClickableViewAccessibility") override fun initialize(viewModel: StoneCameraViewModel) { + value = null scanner = BarcodeScanning.getClient() + qrScannerEnabled = viewModel.getSetting("qrScannerEnabled").toString() } var width = 0f - // TODO RenderViewfinder to show the box around the QR code - I spent 6hrs on it and couldn't get it to line up @Composable @@ -114,7 +115,6 @@ class QRScannerPlugin : IPlugin { } value = null - barcodePos = null }) ) { Text( @@ -133,54 +133,82 @@ class QRScannerPlugin : IPlugin { @SuppressLint("RestrictedApi") @OptIn(ExperimentalGetImage::class) - override val onImageAnalysis = { viewModel: StoneCameraViewModel, + override var onImageAnalysis = { viewModel: StoneCameraViewModel, imageProxy: ImageProxy, image: Image -> - val deferred = CompletableDeferred() - - val inputImage = - InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees) - - scanner?.process(inputImage) - ?.addOnSuccessListener { barcodes -> - if (barcodes.size > 0) { - val prevBarcode = value - val barcode = barcodes[0] - value = barcode.rawValue - - if (value !== prevBarcode) { - // Trigger haptic feedback - val vibrator = MyApplication.getAppContext() - .getSystemService(Context.VIBRATOR_SERVICE) as Vibrator - vibrator.vibrate( - VibrationEffect.createOneShot( - 100, - VibrationEffect.DEFAULT_AMPLITUDE + var deferred = CompletableDeferred() + + if (qrScannerEnabled == "ON") { + val inputImage = + InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees) + + scanner?.process(inputImage) + ?.addOnSuccessListener { barcodes -> + if (barcodes.size > 0) { + val prevBarcode = value + val barcode = barcodes[0] + value = barcode.rawValue + + if (value !== prevBarcode) { + // Trigger haptic feedback + val vibrator = MyApplication.getAppContext() + .getSystemService(Context.VIBRATOR_SERVICE) as Vibrator + vibrator.vibrate( + VibrationEffect.createOneShot( + 100, + VibrationEffect.DEFAULT_AMPLITUDE + ) ) - ) - } + } - // Cancel any pending clear - clearValueRunnable?.let { handler.removeCallbacks(it) } - } else { - if (value !== null && clearValueRunnable == null) { - clearValueRunnable = Runnable { - value = null - barcodePos = null - clearValueRunnable = null + // Cancel any pending clear + clearValueRunnable?.let { handler.removeCallbacks(it) } + } else { + if (value !== null && clearValueRunnable == null) { + clearValueRunnable = Runnable { + value = null + clearValueRunnable = null + } + handler.postDelayed(clearValueRunnable!!, 5000) } - handler.postDelayed(clearValueRunnable!!, 5000) } + deferred.complete(Unit) } - deferred.complete(Unit) - } - ?.addOnFailureListener { - // Handle failure - Log.e("QRCode", "QR Code Detection Failed", it) - deferred.completeExceptionally(it) - } + ?.addOnFailureListener { + // Handle failure + Log.e("QRCode", "QR Code Detection Failed", it) + deferred.completeExceptionally(it) + } + } else { + deferred.complete(Unit) + } deferred } + + override val settings: (StoneCameraViewModel) -> List = { viewModel -> + listOf( + PluginSetting.EnumSetting( + key = "qrScannerEnabled", + label = "QR Scanner", + defaultValue = "ON", + options = listOf("ON", "OFF"), + render = { value, isSelected -> + Text( + text = value, + color = if (isSelected) Color(0xFFFFCC00) else Color.White, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Bold, + modifier = Modifier + .padding(8.dp) + ) + }, + onChange = { viewModel, value -> + viewModel.recreateUseCases() + }, + renderLocation = SettingLocation.NONE + ) + ) + } } diff --git a/app/src/main/java/co/stonephone/stonecamera/plugins/SettingsTray.kt b/app/src/main/java/co/stonephone/stonecamera/plugins/SettingsTray.kt new file mode 100644 index 0000000..1ca58af --- /dev/null +++ b/app/src/main/java/co/stonephone/stonecamera/plugins/SettingsTray.kt @@ -0,0 +1,168 @@ +package co.stonephone.stonecamera.plugins + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material3.ExperimentalMaterial3Api +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.Text +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.rememberCoroutineScope +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.platform.LocalConfiguration +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import co.stonephone.stonecamera.StoneCameraViewModel +import kotlinx.coroutines.launch + +class SettingsTrayPlugin : IPlugin { + override val id: String = "settingsTrayPlugin" + override val name: String = "Settings Tray" + + var showSettingsTray by mutableStateOf(false) + + @OptIn(ExperimentalMaterial3Api::class) + @Composable + override fun renderTray(viewModel: StoneCameraViewModel, pluginInstance: IPlugin) { + val sheetState = rememberModalBottomSheetState( + skipPartiallyExpanded = false, // Enables partially expanded states + ) + val coroutineScope = rememberCoroutineScope() + val plugins = viewModel.plugins + + val modifier = Modifier + + if (showSettingsTray) { + ModalBottomSheet( + onDismissRequest = { + coroutineScope.launch { + sheetState.hide() // Hides the bottom sheet on dismiss + showSettingsTray = false + } + }, + sheetState = sheetState, + modifier = Modifier.fillMaxWidth(), + containerColor = Color.Black, + ) { + Box( + modifier = Modifier.padding(16.dp, top = 0.dp) + ) { + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .heightIn(max = (0.7 * LocalConfiguration.current.screenHeightDp).dp) + ) { + plugins.map { plugin -> + item { + plugin.settings(viewModel).map { setting -> + val value = + viewModel.getSetting(setting.key) ?: setting.defaultValue + + Text( + text = setting.label, + color = Color.White, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(4.dp) + ) + + when (setting) { + is PluginSetting.EnumSetting -> { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 2.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + setting.options.map { option -> + Box(modifier = Modifier + .then(modifier) + .clickable { + viewModel.setSetting( + setting.key, option + ) + }) { + setting.render(option, option == value) + } + } + } + } + + is PluginSetting.ScalarSetting -> { + Slider( + value = value as Float, + onValueChange = { newValue -> + viewModel.setSetting(setting.key, newValue) + }, + valueRange = setting.minValue..setting.maxValue, + modifier = modifier + ) + } + + is PluginSetting.CustomSetting -> setting.customRender( + viewModel, value + ) { value -> + viewModel.setSetting(setting.key, value) + } + } + } + } + } + } + } + } + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 1.dp, horizontal = 8.dp), + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically + ) { + IconButton( + onClick = { + showSettingsTray = true + }, + modifier = Modifier + .size(36.dp) + .background( + Color.White.copy(alpha = 0.1f), CircleShape + ) + .padding(8.dp), + ) { + Icon( + imageVector = Icons.Default.Settings, + contentDescription = "Settings Tray", + tint = Color.White, + modifier = Modifier.fillMaxSize() + ) + } + } + } + + override fun initialize(viewModel: StoneCameraViewModel) { + + } +} diff --git a/app/src/main/java/co/stonephone/stonecamera/plugins/VolumeControls.kt b/app/src/main/java/co/stonephone/stonecamera/plugins/VolumeControls.kt index 17c0e1a..53bf0fe 100644 --- a/app/src/main/java/co/stonephone/stonecamera/plugins/VolumeControls.kt +++ b/app/src/main/java/co/stonephone/stonecamera/plugins/VolumeControls.kt @@ -91,10 +91,11 @@ class VolumeControlsPlugin : IPlugin { key = "volumeControlMode", options = listOf("Zoom", "Capture", "Smart"), defaultValue = "Smart", - renderLocation = SettingLocation.TOP, - render = { value -> + renderLocation = SettingLocation.NONE, + render = { value, isSelected -> Text( - value.uppercase(), color = Color.White, + value.uppercase(), + color = if (isSelected) Color(0xFFFFCC00) else Color.White, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold, modifier = Modifier @@ -103,7 +104,8 @@ class VolumeControlsPlugin : IPlugin { }, onChange = { viewModel, value -> // NOOP - } + }, + label = "Volume Control Mode" ) ) } diff --git a/app/src/main/java/co/stonephone/stonecamera/plugins/ZoomBar.kt b/app/src/main/java/co/stonephone/stonecamera/plugins/ZoomBar.kt index 026f58f..25cbf0a 100644 --- a/app/src/main/java/co/stonephone/stonecamera/plugins/ZoomBar.kt +++ b/app/src/main/java/co/stonephone/stonecamera/plugins/ZoomBar.kt @@ -1,12 +1,10 @@ package co.stonephone.stonecamera.plugins import android.annotation.SuppressLint -import androidx.compose.ui.platform.LocalContext import co.stonephone.stonecamera.StoneCameraViewModel import co.stonephone.stonecamera.ui.ZoomBar import androidx.compose.foundation.layout.* import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -29,7 +27,6 @@ class ZoomBarPlugin : IPlugin { Column( modifier = Modifier .fillMaxWidth(), - verticalArrangement = Arrangement.SpaceBetween ) { viewModel.camera?.let { cam -> diff --git a/app/src/main/java/co/stonephone/stonecamera/ui/RenderPluginSetting.kt b/app/src/main/java/co/stonephone/stonecamera/ui/RenderPluginSetting.kt index 174973a..0b57472 100644 --- a/app/src/main/java/co/stonephone/stonecamera/ui/RenderPluginSetting.kt +++ b/app/src/main/java/co/stonephone/stonecamera/ui/RenderPluginSetting.kt @@ -10,12 +10,10 @@ import co.stonephone.stonecamera.plugins.PluginSetting @Composable fun RenderPluginSetting( - setting: PluginSetting, - viewModel: StoneCameraViewModel, - modifier: Modifier = Modifier + setting: PluginSetting, viewModel: StoneCameraViewModel, modifier: Modifier = Modifier // TODO modes (e.g. compact: toggle in place, row: inform parent to hide others when active, full-row: always open) ) { - val value = viewModel.getSetting(setting.key) ?: setting.defaultValue + val value = viewModel.settings[setting.key] ?: setting.defaultValue when (setting) { is PluginSetting.EnumSetting -> { Box(modifier = Modifier @@ -25,25 +23,22 @@ fun RenderPluginSetting( val nextIndex = (currentIndex + 1) % setting.options.size viewModel.setSetting(setting.key, setting.options[nextIndex]) }) { - setting.render(value as String) + setting.render(value as String, false) } } is PluginSetting.ScalarSetting -> { Slider( - value = value as Float, - onValueChange = { newValue -> + value = value as Float, onValueChange = { newValue -> viewModel.setSetting(setting.key, newValue) - }, - valueRange = setting.minValue..setting.maxValue, + }, valueRange = setting.minValue..setting.maxValue, // steps = setting.stepValue?.toInt() modifier = modifier ) } - is PluginSetting.CustomSetting -> setting.customRender(viewModel, - value, { value -> - viewModel.setSetting(setting.key, value) - }) + is PluginSetting.CustomSetting -> setting.customRender(viewModel, value, { value -> + viewModel.setSetting(setting.key, value) + }) } } \ No newline at end of file