Skip to content

Instantly share code, notes, and snippets.

@elfefe
Last active September 16, 2024 13:47
Show Gist options
  • Select an option

  • Save elfefe/d15b86d7aaef81e4165677383de16676 to your computer and use it in GitHub Desktop.

Select an option

Save elfefe/d15b86d7aaef81e4165677383de16676 to your computer and use it in GitHub Desktop.
Utilitaires Kotlin/Compose
package fr.exem.citymapper2.controllers
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.json.JSONObject
import java.io.File
class Config {
private var configFile: File = File(FileManager.appDirectory, "config.json").apply {
if (!exists()) createNewFile()
}
private val config = configFile.run { JSONObject(readText()) }
private val scope = CoroutineScope(Dispatchers.IO)
private var job: Job? = null
private val map: JSONObject
get() {
return try {
config.getJSONObject("map")
} catch (e: Exception) {
JSONObject()
}
}
private val trail: JSONObject
get() {
return try {
config.getJSONObject("trail")
} catch (e: Exception) {
JSONObject()
}
}
private var _macAdress by mutableStateOf(try {
config.getString("mac")
} catch (e: Exception) {
""
})
var macAdress: String
get() = _macAdress
set(value) {
_macAdress = value
config.put("mac", value)
updateConfig()
}
val defaultMapWidth = .3f
private var _mapWidth by mutableFloatStateOf(try {
map.getDouble("width").toFloat()
} catch (e: Exception) {
defaultMapWidth
})
var mapWidth: Float
get() = _mapWidth
set(value) {
_mapWidth = value
map.put("width", value)
config.put("map", map)
updateConfig()
}
val defaultTrailWidth = 5f
private var _trailWidth by mutableFloatStateOf(try {
trail.getDouble("width").toFloat()
} catch (e: Exception) {
defaultTrailWidth
})
var trailWidth: Float
get() = _trailWidth
set(value) {
_trailWidth = value
trail.put("width", value)
config.put("trail", trail)
updateConfig()
}
val defaultTrailColor = Color.Red
private var _trailColor by mutableStateOf(try {
Color(trail.getInt("color"))
} catch (e: Exception) {
defaultTrailColor
})
var trailColor: Color
get() = _trailColor
set(value) {
_trailColor = value
trail.put("color", value.toArgb())
config.put("trail", trail)
updateConfig()
}
private fun updateConfig() {
if (job?.isActive == true) return
job = scope.launch {
while (config.toString() != configFile.readText()) {
configFile.writeText(config.toString())
}
}
}
companion object {
val instance = Config()
}
}
class ConfigViewModel: ViewModel() {
var config = Config.instance
}
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Text
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.geometry.Size
import androidx.compose.ui.layout.boundsInParent
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.toSize
import kotlin.math.abs
@Composable
fun TimePicker(modifier: Modifier = Modifier, onPickTime: (Int, Int, Int) -> Unit) {
var hours by remember { mutableStateOf(0) }
var minuts by remember { mutableStateOf(0) }
var seconds by remember { mutableStateOf(0) }
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically
) {
NumberPicker(numbers = (0..24).toList()) {
hours = it
onPickTime(hours, minuts, seconds)
}
Text(text = "h", fontSize = 16.sp)
NumberPicker(numbers = (0..59).toList()) {
minuts = it
onPickTime(hours, minuts, seconds)
}
Text(text = "m", fontSize = 16.sp)
NumberPicker(numbers = (0..59).toList()) {
seconds = it
onPickTime(hours, minuts, seconds)
}
Text(text = "s", fontSize = 16.sp)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun <T: Number> NumberPicker(numbers: List<T>, onPickNumber: (T) -> Unit) {
val hoursListState = rememberLazyListState()
val hoursSnapFling = rememberSnapFlingBehavior(lazyListState = hoursListState)
var hoursLayoutSize by remember { mutableStateOf(Size.Zero) }
LazyColumn(
flingBehavior = hoursSnapFling,
modifier = Modifier
.width(48.dp)
.height(64.dp)
.onSizeChanged { hoursLayoutSize = it.toSize() },
state = hoursListState,
contentPadding = PaddingValues(0.dp, 24.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
items(numbers.toList()) { hour ->
var positionRatio by remember { mutableStateOf(0f) }
Box(
modifier = Modifier
.size(24.dp)
.onGloballyPositioned { coordinates ->
coordinates
.boundsInParent()
.run {
val x =
(((top + (height / 2)) / (hoursLayoutSize.height)) - .5f) * 2
positionRatio = x * x
if (top > 0 && bottom < hoursLayoutSize.height) onPickNumber(hour)
}
},
contentAlignment = Alignment.Center
) {
Text(
text = "$hour",
textAlign = TextAlign.Center,
fontSize = (16 - 14 * positionRatio).sp,
)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment