SettingsActivity refactor

This commit is contained in:
Alexey 2025-11-07 12:50:34 +03:00
commit 2b821d8204
6 changed files with 117 additions and 96 deletions

View file

@ -0,0 +1,31 @@
package com.mirenkov.ktheightmap
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import com.mirenkov.ktheightmap.FileLoader.Companion.filePickerResult
import com.nareshchocha.filepickerlibrary.FilePickerResultContracts
import com.nareshchocha.filepickerlibrary.models.DocumentFilePickerConfig
import com.nareshchocha.filepickerlibrary.models.FilePickerResult
class FileLoader {
companion object {
var filePath: MutableState<String?> = mutableStateOf(null)
fun filePickerResult(result: FilePickerResult): String? {
if (result.errorMessage != null) {
Log.e(TAG, result.errorMessage!!)
return null
} else {
val filePath = result.selectedFilePath
return filePath
}
}
}
}
fun ComponentActivity.registerFileLoader(): ActivityResultLauncher<DocumentFilePickerConfig?> {
return registerForActivityResult(FilePickerResultContracts.PickDocumentFile())
{ result -> FileLoader.filePath.value = filePickerResult(result) }
}

View file

@ -27,6 +27,7 @@ import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle
import com.mirenkov.ktheightmap.parser.KhmParser
import kotlin.math.absoluteValue
import kotlin.math.floor
import kotlin.math.pow

View file

@ -2,7 +2,6 @@ package com.mirenkov.ktheightmap
import android.app.Application
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
@ -14,50 +13,26 @@ import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import com.mirenkov.ktheightmap.parser.KhmParser
import com.mirenkov.ktheightmap.parser.SasJPEGParser
import com.mirenkov.ktheightmap.parser.SasSQLiteParser
import com.mirenkov.ktheightmap.ui.theme.KtHeightMapTheme
import com.nareshchocha.filepickerlibrary.FilePickerResultContracts
import com.nareshchocha.filepickerlibrary.models.DocumentFilePickerConfig
import com.nareshchocha.filepickerlibrary.models.FilePickerResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import java.io.FileInputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
class SettingsActivity : ComponentActivity() {
companion object {
var filePath: MutableState<String?> = mutableStateOf(null)
}
fun filePickerResult(result: FilePickerResult): String? {
if (result.errorMessage != null) {
Log.e(TAG, result.errorMessage ?: "")
return null
} else {
val filePath = result.selectedFilePath
filePath?.let {
if (it.endsWith(".zip") || it.endsWith(".khm"))
return filePath
}
return null
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val launcher = registerForActivityResult(FilePickerResultContracts.PickDocumentFile())
{ result -> filePath.value = filePickerResult(result) }
val launcher = registerFileLoader()
enableEdgeToEdge()
setContent {
@ -77,79 +52,38 @@ class SettingsActivity : ComponentActivity() {
@Composable
fun SettingsMain(vm: TileViewModel, launcher: ActivityResultLauncher<DocumentFilePickerConfig?>) {
val coroutineScope = rememberCoroutineScope()
val filePath by remember { SettingsActivity.filePath }
val filePath by remember { FileLoader.filePath }
val ctx = LocalContext.current
val toast = Toast.makeText(ctx, "File parsed.", Toast.LENGTH_LONG)
KtHeightMapTheme {
Column(Modifier.fillMaxSize()
.safeDrawingPadding()) {
Button(
onClick = { launcher.launch(null) }
) { Text(text = "Select database") }
Button(
onClick = { coroutineScope.launch {
processZip(filePath).forEach {
with(vm.repository) {
val t = getTile(it.x, it.y, it.level)
if (t == null) {
pushTile(it)
}
}
}
} },
) { Text(text = "Load .zip") }
Button(
onClick = { coroutineScope.launch { vm.repository.clearTiles() } },
) { Text(text = "Clear database") }
Button(
onClick = { filePath?.let {
KhmParser.load(it, ctx)
} },
) { Text(text = "Load .khm") }
Button(
onClick = {
Button({ launcher.launch(null) }) { Text("Select file") }
Button({
filePath?.let {
coroutineScope.launch(Dispatchers.IO) {
SasSQLiteParser.processZip(it, vm.repository, ctx)
coroutineScope.launch(Dispatchers.Main) { Toast.makeText(ctx, "File parsed.", Toast.LENGTH_LONG).show() }
coroutineScope.launch(Dispatchers.Main) { toast.show() }
}
} }
) { Text("Load SQLite") }
Button({
filePath?.let {
coroutineScope.launch(Dispatchers.IO) {
SasJPEGParser.processZip(it, vm.repository)
coroutineScope.launch(Dispatchers.Main) { toast.show() }
}
}
}
) { Text("Load SAS") }
},
) { Text("Load JPEG") }
Button({
filePath?.let {
KhmParser.load(it, ctx)
toast.show()
} },
) { Text("Load KHM") }
Button({ coroutineScope.launch { vm.repository.clearTiles() } }) { Text("Clear tiles") }
Button({ KhmParser.clear(ctx) }) { Text("Clear KHM") }
}
}
}
suspend fun processZip(filePath: String?): List<Tile> = coroutineScope {
val list: MutableList<Tile> = mutableListOf()
filePath?.let {
ZipInputStream(FileInputStream(it)).use { zipInputStream ->
var entry = zipInputStream.nextEntry
while (true) {
if (entry.name.endsWith(".jpg")) {
Log.i(TAG, entry.name)
val tile = processEntry(zipInputStream, entry)
list.add(tile)
}
entry = zipInputStream.nextEntry
if (entry == null)
break
}
}
}
return@coroutineScope list
}
fun processEntry(zis: ZipInputStream, entry: ZipEntry): Tile {
val ba = ByteArray(entry.size.toInt())
var offset = 0
var size = zis.read(ba)
while (size > 0) {
offset += size
size = zis.read(ba, offset, ba.size - offset)
}
val regex = Regex("(?<=z)(\\d+)|(?<=x)(\\d+)|(?<=y)(\\d+)")
val ( level, x, y ) = regex.findAll(entry.name).map { it.value.toInt() }.toList()
val base64 = ba.toBase64()
return Tile(x, y, level, base64)
}

View file

@ -1,4 +1,4 @@
package com.mirenkov.ktheightmap
package com.mirenkov.ktheightmap.parser
import android.content.Context
import java.io.DataInputStream
@ -32,6 +32,12 @@ class KhmParser {
inp.close()
}
fun clear(ctx: Context) {
if (ctx.getFileStreamPath(HEIGHT_FILE).exists()) {
assert(ctx.deleteFile(HEIGHT_FILE))
}
}
private fun getOffset(header: HeightInfo, x: Int, y: Int): Int {
return (x * header.width + y) * 2
}

View file

@ -0,0 +1,49 @@
package com.mirenkov.ktheightmap.parser
import android.util.Log
import com.mirenkov.ktheightmap.TAG
import com.mirenkov.ktheightmap.Tile
import com.mirenkov.ktheightmap.TileRepository
import com.mirenkov.ktheightmap.toBase64
import java.io.FileInputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
class SasJPEGParser {
companion object {
fun processZip(filePath: String?, repo: TileRepository) {
filePath?.let {
ZipInputStream(FileInputStream(it)).use { zipInputStream ->
var entry = zipInputStream.nextEntry
while (true) {
if (entry.name.endsWith(".jpg")) {
Log.i(TAG, entry.name)
processEntry(zipInputStream, entry, repo)
}
entry = zipInputStream.nextEntry
if (entry == null)
break
}
}
}
}
private fun processEntry(zis: ZipInputStream, entry: ZipEntry, repo: TileRepository) {
val ba = ByteArray(entry.size.toInt())
var offset = 0
var size = zis.read(ba)
while (size > 0) {
offset += size
size = zis.read(ba, offset, ba.size - offset)
}
val regex = Regex("(?<=z)(\\d+)|(?<=x)(\\d+)|(?<=y)(\\d+)")
val ( level, x, y ) = regex.findAll(entry.name).map { it.value.toInt() }.toList()
val base64 = ba.toBase64()
val tile = Tile(x, y, level, base64)
val checkedTile = repo.getTile(tile.x, tile.y, tile.level)
if (checkedTile == null)
repo.pushTile(tile)
}
}
}