Set location dialog prefab and proper ViewModel handling

This commit is contained in:
Alexey 2025-09-02 13:31:35 +03:00
commit 2937f17a69
3 changed files with 92 additions and 20 deletions

View file

@ -3,18 +3,22 @@ package com.mirenkov.ktheightmap
import android.app.Application import android.app.Application
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Build
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButton
@ -23,7 +27,10 @@ import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -35,7 +42,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.toUpperCase
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
@ -79,8 +87,6 @@ class MainActivity : ComponentActivity() {
@Composable @Composable
fun Main(vm: TileViewModel = viewModel()) { fun Main(vm: TileViewModel = viewModel()) {
val sliderValue = rememberSaveable { mutableFloatStateOf(1F) } val sliderValue = rememberSaveable { mutableFloatStateOf(1F) }
val canvasOffsetX = rememberSaveable { mutableFloatStateOf(-652.0647F) }
val canvasOffsetY = rememberSaveable { mutableFloatStateOf(-1145.693F) }
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val tileContainer = TileContainer(vm, coroutineScope) val tileContainer = TileContainer(vm, coroutineScope)
KtHeightMapTheme { KtHeightMapTheme {
@ -97,8 +103,6 @@ fun Main(vm: TileViewModel = viewModel()) {
backColor = colorScheme.background, backColor = colorScheme.background,
scale = sliderValue, scale = sliderValue,
tileContainer = tileContainer, tileContainer = tileContainer,
offsetX = canvasOffsetX,
offsetY = canvasOffsetY,
modifier = Modifier.padding(innerPadding), modifier = Modifier.padding(innerPadding),
) )
} }
@ -122,7 +126,10 @@ fun Main(vm: TileViewModel = viewModel()) {
@Composable @Composable
fun ToolButton(viewModel: TileViewModel) { fun ToolButton(viewModel: TileViewModel) {
val context = LocalContext.current val context = LocalContext.current
var expanded by remember{ mutableStateOf(false) } var expanded by rememberSaveable{ mutableStateOf(false) }
var debug by rememberSaveable{ viewModel.debug }
var logRequested by remember{ viewModel.logRequested }
val dialogShown = rememberSaveable{ mutableStateOf(false) }
FloatingActionButton( FloatingActionButton(
onClick = { onClick = {
expanded = !expanded expanded = !expanded
@ -135,23 +142,79 @@ fun ToolButton(viewModel: TileViewModel) {
) { ) {
DropdownMenuItem( DropdownMenuItem(
text = { Text("Toggle debug") }, text = { Text("Toggle debug") },
onClick = { viewModel.debug = !viewModel.debug } onClick = {
debug = !debug
expanded = false
}
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text("Log") }, text = { Text("Log") },
onClick = { viewModel.logRequested = true } onClick = {
logRequested = true
expanded = false
}
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text("Set location") }, text = { Text("Set location") },
onClick = {} onClick = {
expanded = false
dialogShown.value = true
}
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text("Settings") }, text = { Text("Settings") },
onClick = { onClick = {
expanded = false
val intent = Intent(context, SettingsActivity::class.java) val intent = Intent(context, SettingsActivity::class.java)
context.startActivity(intent) context.startActivity(intent)
} }
) )
SetLocationDialog(viewModel, dialogShown)
} }
} }
}
@Composable
fun SetLocationDialog(vm: TileViewModel, dialogShown: MutableState<Boolean>) {
var showLocationDialog by dialogShown
if (showLocationDialog) {
var latitudeText by remember { vm.latitudeText }
var longitudeText by remember { vm.longitudeText }
AlertDialog (
onDismissRequest = { showLocationDialog = false },
title = { Text("Input coordinates") },
text = {
Column {
TextField(
value = latitudeText,
onValueChange = { newValue ->
latitudeText = newValue
},
label = { Text("Latitude") },
placeholder = { Text("60.086763") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
TextField(
value = longitudeText,
onValueChange = { newValue ->
longitudeText = newValue
},
label = { Text("Longitude") },
placeholder = { Text("30.014658") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
}
},
confirmButton = { TextButton(onClick = {
Log.i(TAG, "Lat: %.6f, Lon: %.6f".format(
latitudeText.text.toDoubleOrNull() ?: 0.0, longitudeText.text.toDoubleOrNull() ?: 0.0
))
}) {
Text("Confirm".uppercase())
} },
dismissButton = { TextButton(onClick = { showLocationDialog = false }) {
Text("Cancel".uppercase())
} }
)
}
} }

View file

@ -34,15 +34,15 @@ fun MapCanvas(
backColor: Color, backColor: Color,
gridColor: Color, gridColor: Color,
scale: MutableFloatState, scale: MutableFloatState,
offsetX: MutableFloatState,
offsetY: MutableFloatState,
tileContainer: TileContainer, tileContainer: TileContainer,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
var offsetX by rememberSaveable { offsetX } var offsetX by rememberSaveable { viewModel.mapOffsetX }
var offsetY by rememberSaveable { offsetY } var offsetY by rememberSaveable { viewModel.mapOffsetY }
val scale by rememberSaveable { scale } val scale by rememberSaveable { scale }
val textMeasurer = rememberTextMeasurer() val textMeasurer = rememberTextMeasurer()
val debug by rememberSaveable { viewModel.debug }
var logRequested by rememberSaveable { viewModel.logRequested }
Canvas( Canvas(
modifier = modifier.fillMaxSize() modifier = modifier.fillMaxSize()
.pointerInput(Unit) { .pointerInput(Unit) {
@ -57,9 +57,9 @@ fun MapCanvas(
size = size size = size
) )
if (viewModel.logRequested) { if (logRequested) {
Log.i(TAG, "Offset: %.6f, %.6f".format(offsetX, offsetY)) Log.i(TAG, "Offset: %.6f, %.6f".format(offsetX, offsetY))
viewModel.logRequested = false logRequested = false
} }
val oldLevel = tileContainer.getLevel() val oldLevel = tileContainer.getLevel()
@ -101,7 +101,7 @@ fun MapCanvas(
val crossRadius = 24F val crossRadius = 24F
val additionalSize = if (viewModel.debug) 96F else 0F val additionalSize = if (debug) 96F else 0F
val latLonSize = Size(196F, 96F + additionalSize) val latLonSize = Size(196F, 96F + additionalSize)
val latLonOffset = Offset(16F, 16F) val latLonOffset = Offset(16F, 16F)
@ -124,7 +124,7 @@ fun MapCanvas(
) )
} }
if (viewModel.debug) { if (debug) {
drawRect( drawRect(
color = gridColor, color = gridColor,
size = Size(TILE_SIZE, TILE_SIZE), size = Size(TILE_SIZE, TILE_SIZE),
@ -175,7 +175,7 @@ fun MapCanvas(
val lon = SphereMercator.mercateX(centerTileX, level) val lon = SphereMercator.mercateX(centerTileX, level)
val lat = SphereMercator.mercateY(centerTileY, level) val lat = SphereMercator.mercateY(centerTileY, level)
append("%.6f\n%.6f".format(lon, lat)) append("%.6f\n%.6f".format(lon, lat))
if (viewModel.debug) { if (debug) {
append("\n%.0f\n%.0f".format(offsetX, offsetY)) append("\n%.0f\n%.0f".format(offsetX, offsetY))
} }
} }

View file

@ -1,13 +1,22 @@
package com.mirenkov.ktheightmap package com.mirenkov.ktheightmap
import android.app.Application import android.app.Application
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
class TileViewModel(application: Application): ViewModel() { class TileViewModel(application: Application): ViewModel() {
val repository: TileRepository val repository: TileRepository
var debug = false
var logRequested = false var debug = mutableStateOf(false)
var logRequested = mutableStateOf(false)
var latitudeText = mutableStateOf(TextFieldValue(""))
var longitudeText = mutableStateOf(TextFieldValue(""))
val mapOffsetX = mutableFloatStateOf(-646.65625F)
val mapOffsetY = mutableFloatStateOf(-1157.2814F)
init { init {
val tileDb = TileDB.getInstance(application) val tileDb = TileDB.getInstance(application)