262 lines
7.2 KiB
Kotlin
262 lines
7.2 KiB
Kotlin
package eu.wa5p.lightmeter
|
|
|
|
import android.content.Context
|
|
import android.hardware.Sensor
|
|
import android.hardware.SensorEvent
|
|
import android.hardware.SensorEventListener
|
|
import android.hardware.SensorManager
|
|
import android.os.Bundle
|
|
import android.util.Log
|
|
import androidx.activity.ComponentActivity
|
|
import androidx.activity.compose.setContent
|
|
import androidx.activity.enableEdgeToEdge
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
import androidx.compose.foundation.layout.Column
|
|
import androidx.compose.foundation.layout.Row
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.material3.Slider
|
|
import androidx.compose.material3.Text
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.MutableState
|
|
import androidx.compose.runtime.mutableStateOf
|
|
import androidx.compose.runtime.remember
|
|
import androidx.compose.ui.Alignment
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.text.style.TextAlign
|
|
import androidx.compose.ui.tooling.preview.Preview
|
|
import androidx.compose.ui.unit.dp
|
|
import eu.wa5p.lightmeter.ui.theme.LightMeterTheme
|
|
import kotlin.math.roundToInt
|
|
|
|
const val TAG: String = "lightmeter MainActivity"
|
|
|
|
class MainActivity : ComponentActivity(), SensorEventListener {
|
|
private lateinit var sensorManager: SensorManager
|
|
private var illuminanceSensor: Sensor? = null
|
|
private var lightmeterState = mutableStateOf(
|
|
LightmeterState(
|
|
illuminance = 0.0,
|
|
aperture = 1.8,
|
|
iso = 100,
|
|
shutterSpeed = 0.01
|
|
)
|
|
)
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
enableEdgeToEdge()
|
|
setContent {
|
|
LightMeterTheme {
|
|
LightmeterHomeScreen(state = lightmeterState )
|
|
}
|
|
}
|
|
|
|
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
|
illuminanceSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
|
|
}
|
|
|
|
private fun updateLightmeterState(illuminance: Double) {
|
|
val iso = lightmeterState.value.iso
|
|
val aperture = lightmeterState.value.aperture
|
|
val shutterSpeed = (aperture * aperture) / (illuminance * (iso / 100))
|
|
lightmeterState.value = lightmeterState.value.copy(
|
|
illuminance = illuminance,
|
|
iso = iso,
|
|
aperture = aperture,
|
|
shutterSpeed = shutterSpeed
|
|
)
|
|
}
|
|
|
|
override fun onSensorChanged(event: SensorEvent?) {
|
|
event?.values?.let {
|
|
for (v in it) {
|
|
Log.d(TAG, "sensor changed: $v lux")
|
|
updateLightmeterState(v.toDouble())
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
|
|
Log.d(TAG, "accuracy changed: sensor: ${sensor?.name}. accuracy: $accuracy")
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
sensorManager.registerListener(this, illuminanceSensor, SensorManager.SENSOR_DELAY_NORMAL)
|
|
}
|
|
|
|
override fun onPause() {
|
|
super.onPause()
|
|
sensorManager.unregisterListener(this)
|
|
}
|
|
|
|
override fun onDestroy() {
|
|
super.onDestroy()
|
|
sensorManager.unregisterListener(this)
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
fun LightmeterListItem(
|
|
label: String,
|
|
value: String,
|
|
unit: String
|
|
) {
|
|
Row(modifier = Modifier.padding(bottom = 8.dp)) {
|
|
Text(
|
|
modifier = Modifier
|
|
.weight(0.4f)
|
|
.padding(all = 8.dp),
|
|
text = label
|
|
)
|
|
Text(
|
|
modifier = Modifier
|
|
.weight(0.4f)
|
|
.padding(all = 8.dp),
|
|
textAlign = TextAlign.Right,
|
|
text = value
|
|
)
|
|
Text(
|
|
modifier = Modifier
|
|
.weight(0.2f)
|
|
.padding(all = 8.dp),
|
|
text = unit
|
|
)
|
|
}
|
|
}
|
|
|
|
@Preview(showBackground = true)
|
|
@Composable
|
|
fun LightmeterListItemPreview() {
|
|
LightMeterTheme {
|
|
LightmeterListItem(
|
|
label = "Illuminance",
|
|
value = "1234",
|
|
unit = "lux"
|
|
)
|
|
}
|
|
}
|
|
|
|
// TODO: Recalculate state on change
|
|
@Composable
|
|
fun IsoSlider(state: MutableState<LightmeterState>) {
|
|
Row(
|
|
modifier = Modifier.padding(all = 8.dp),
|
|
verticalAlignment = Alignment.CenterVertically
|
|
) {
|
|
Text(
|
|
modifier = Modifier.weight(0.3f),
|
|
text = "ISO"
|
|
)
|
|
Slider(
|
|
modifier = Modifier.weight(0.7f),
|
|
value = state.value.iso.toFloat(),
|
|
onValueChange = { value ->
|
|
state.value = state.value.copy(iso = value.roundToInt())
|
|
},
|
|
valueRange = 1f..2000f
|
|
)
|
|
}
|
|
}
|
|
|
|
val previewlightmeterState = mutableStateOf(
|
|
LightmeterState(
|
|
illuminance = 0.0,
|
|
aperture = 1.8,
|
|
iso = 100,
|
|
shutterSpeed = 0.01
|
|
)
|
|
)
|
|
|
|
@Preview(showBackground = true)
|
|
@Composable
|
|
fun IsoSliderPreview() {
|
|
LightMeterTheme {
|
|
IsoSlider(
|
|
state = remember { previewlightmeterState }
|
|
)
|
|
}
|
|
}
|
|
|
|
// TODO: Recalculate state on change
|
|
@Composable
|
|
fun ApertureSlider(state: MutableState<LightmeterState>) {
|
|
Row(
|
|
modifier = Modifier.padding(all = 8.dp),
|
|
verticalAlignment = Alignment.CenterVertically
|
|
) {
|
|
Text(
|
|
modifier = Modifier.weight(0.3f),
|
|
text = "Aperture"
|
|
)
|
|
Slider(
|
|
modifier = Modifier.weight(0.7f),
|
|
value = state.value.aperture.toFloat(),
|
|
onValueChange = { value ->
|
|
state.value = state.value.copy(aperture = value.toDouble())
|
|
},
|
|
valueRange = 0.85f..22f
|
|
)
|
|
}
|
|
}
|
|
|
|
@Preview(showBackground = true)
|
|
@Composable
|
|
fun ApertureSliderPreview() {
|
|
LightMeterTheme {
|
|
ApertureSlider(state = remember { previewlightmeterState })
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
fun LightmeterHomeScreen(state: MutableState<LightmeterState>) {
|
|
Column(modifier = Modifier
|
|
.fillMaxSize()
|
|
.padding(top = 64.dp)
|
|
.padding(all = 32.dp)
|
|
) {
|
|
Column(
|
|
verticalArrangement = Arrangement.Top
|
|
) {
|
|
LightmeterListItem(
|
|
label = "Illuminance",
|
|
value = "%.2f".format(state.value.illuminance),
|
|
unit = "lux"
|
|
)
|
|
LightmeterListItem(
|
|
label = "ISO",
|
|
value = state.value.iso.toString(),
|
|
unit = ""
|
|
)
|
|
LightmeterListItem(
|
|
label = "Aperture",
|
|
value = "%.2f".format(state.value.aperture),
|
|
unit = "f"
|
|
)
|
|
LightmeterListItem(
|
|
label = "Shutter Speed",
|
|
value = "%.2f".format(state.value.shutterSpeed),
|
|
unit = "s"
|
|
)
|
|
}
|
|
|
|
Column(
|
|
modifier = Modifier.padding(top = 64.dp),
|
|
verticalArrangement = Arrangement.Bottom
|
|
) {
|
|
IsoSlider(state = state)
|
|
ApertureSlider(state = state)
|
|
}
|
|
}
|
|
}
|
|
|
|
@Preview(showBackground = true)
|
|
@Composable
|
|
fun LightmeterHomeScreenPreview() {
|
|
LightMeterTheme {
|
|
LightmeterHomeScreen(
|
|
state = remember { previewlightmeterState }
|
|
)
|
|
}
|
|
} |