I push my tiles into my database
This commit is contained in:
parent
8bec8e4b16
commit
c0644b4c70
5 changed files with 81 additions and 32 deletions
13
.idea/deviceManager.xml
generated
Normal file
13
.idea/deviceManager.xml
generated
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DeviceTable">
|
||||||
|
<option name="columnSorters">
|
||||||
|
<list>
|
||||||
|
<ColumnSorterState>
|
||||||
|
<option name="column" value="Name" />
|
||||||
|
<option name="order" value="ASCENDING" />
|
||||||
|
</ColumnSorterState>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -3,15 +3,11 @@ 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.BoxWithConstraints
|
|
||||||
import androidx.compose.foundation.layout.absoluteOffset
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
|
||||||
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
|
||||||
|
|
@ -24,7 +20,6 @@ import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
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.Surface
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
|
@ -76,7 +71,7 @@ class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Main(vm: TileViewModel = viewModel()) {
|
fun Main(vm: TileViewModel = viewModel()) {
|
||||||
var sliderValue = rememberSaveable { mutableFloatStateOf(1F) }
|
val sliderValue = rememberSaveable { mutableFloatStateOf(1F) }
|
||||||
KtHeightMapTheme {
|
KtHeightMapTheme {
|
||||||
Box(modifier = Modifier.background(color = colorScheme.background)) {
|
Box(modifier = Modifier.background(color = colorScheme.background)) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,27 @@
|
||||||
package com.mirenkov.ktheightmap
|
package com.mirenkov.ktheightmap
|
||||||
|
|
||||||
import android.graphics.BitmapFactory
|
import android.app.Application
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
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.activity.result.ActivityResultLauncher
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
import androidx.compose.foundation.layout.safeDrawingPadding
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
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.ui.theme.KtHeightMapTheme
|
import com.mirenkov.ktheightmap.ui.theme.KtHeightMapTheme
|
||||||
import com.nareshchocha.filepickerlibrary.FilePickerResultContracts
|
import com.nareshchocha.filepickerlibrary.FilePickerResultContracts
|
||||||
|
import com.nareshchocha.filepickerlibrary.models.DocumentFilePickerConfig
|
||||||
import com.nareshchocha.filepickerlibrary.models.FilePickerResult
|
import com.nareshchocha.filepickerlibrary.models.FilePickerResult
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
|
|
@ -25,7 +30,10 @@ import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
class SettingsActivity : ComponentActivity() {
|
class SettingsActivity : ComponentActivity() {
|
||||||
|
|
||||||
var filePath: String? = null
|
companion object {
|
||||||
|
var filePath: String? = null
|
||||||
|
}
|
||||||
|
|
||||||
fun filePickerResult(result: FilePickerResult): String? {
|
fun filePickerResult(result: FilePickerResult): String? {
|
||||||
if (result.errorMessage != null) {
|
if (result.errorMessage != null) {
|
||||||
Log.e(TAG, result.errorMessage ?: "")
|
Log.e(TAG, result.errorMessage ?: "")
|
||||||
|
|
@ -41,47 +49,72 @@ class SettingsActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val launcher = registerForActivityResult(FilePickerResultContracts.PickDocumentFile(),
|
val launcher = registerForActivityResult(FilePickerResultContracts.PickDocumentFile())
|
||||||
{ result -> filePath = filePickerResult(result) }
|
{ result -> filePath = filePickerResult(result) }
|
||||||
)
|
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val owner = LocalViewModelStoreOwner.current
|
||||||
|
owner?.let {
|
||||||
KtHeightMapTheme {
|
val viewModel: TileViewModel = viewModel(
|
||||||
Column(Modifier.fillMaxSize()
|
it,
|
||||||
.safeDrawingPadding()) {
|
"TileViewModel2",
|
||||||
Button(onClick = {
|
TileViewModelFactory(LocalContext.current.applicationContext as Application)
|
||||||
launcher.launch(null)
|
)
|
||||||
}) { Text(text = "Select database") }
|
SettingsMain(viewModel, launcher)
|
||||||
Button(onClick = { coroutineScope.launch { processZip(filePath) } }) {
|
|
||||||
Text(text = "Load database")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processZip(filePath: String?) = coroutineScope {
|
@Composable
|
||||||
|
fun SettingsMain(vm: TileViewModel, launcher: ActivityResultLauncher<DocumentFilePickerConfig?>) {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
KtHeightMapTheme {
|
||||||
|
Column(Modifier.fillMaxSize()
|
||||||
|
.safeDrawingPadding()) {
|
||||||
|
Button(onClick = {
|
||||||
|
launcher.launch(null)
|
||||||
|
}) { Text(text = "Select database") }
|
||||||
|
Button(onClick = { coroutineScope.launch {
|
||||||
|
processZip(SettingsActivity.filePath).forEach {
|
||||||
|
with(vm.repository) {
|
||||||
|
val t = getTile(it.x, it.y, it.level)
|
||||||
|
if (t == null) {
|
||||||
|
pushTile(it)
|
||||||
|
Log.i(TAG, "pushed to db: %d, %d, %d".format(it.level, it.x, it.y))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log.i(TAG, "found in db: %d, %d, %d".format(t.level, t.x, t.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} }) { Text(text = "Load database") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun processZip(filePath: String?): List<Tile> = coroutineScope {
|
||||||
|
val list: MutableList<Tile> = mutableListOf()
|
||||||
filePath?.let {
|
filePath?.let {
|
||||||
ZipInputStream(FileInputStream(it)).use { zipInputStream ->
|
ZipInputStream(FileInputStream(it)).use { zipInputStream ->
|
||||||
var entry = zipInputStream.nextEntry
|
var entry = zipInputStream.nextEntry
|
||||||
while (true) {
|
while (true) {
|
||||||
if (entry.name.endsWith(".jpg")) {
|
if (entry.name.endsWith(".jpg")) {
|
||||||
Log.i(TAG, entry.name)
|
Log.i(TAG, entry.name)
|
||||||
processEntry(zipInputStream, entry)
|
val tile = processEntry(zipInputStream, entry)
|
||||||
|
list.add(tile)
|
||||||
}
|
}
|
||||||
entry = zipInputStream.nextEntry
|
entry = zipInputStream.nextEntry
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
Log.i(TAG, "got list")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return@coroutineScope list
|
||||||
}
|
}
|
||||||
|
|
||||||
fun processEntry(zis: ZipInputStream, entry: ZipEntry) {
|
fun processEntry(zis: ZipInputStream, entry: ZipEntry): Tile {
|
||||||
val ba = ByteArray(entry.size.toInt())
|
val ba = ByteArray(entry.size.toInt())
|
||||||
var offset = 0
|
var offset = 0
|
||||||
var size = zis.read(ba, 0, ba.size)
|
var size = zis.read(ba, 0, ba.size)
|
||||||
|
|
@ -93,5 +126,5 @@ fun processEntry(zis: ZipInputStream, entry: ZipEntry) {
|
||||||
|
|
||||||
val ( level, x, y ) = regex.findAll(entry.name).map { it.value.toInt() }.toList()
|
val ( level, x, y ) = regex.findAll(entry.name).map { it.value.toInt() }.toList()
|
||||||
val base64 = ba.toBase64()
|
val base64 = ba.toBase64()
|
||||||
val tile = Tile(x, y, level, base64)
|
return Tile(x, y, level, base64)
|
||||||
}
|
}
|
||||||
|
|
@ -1,20 +1,28 @@
|
||||||
package com.mirenkov.ktheightmap
|
package com.mirenkov.ktheightmap
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class TileRepository(private val tileDao: TileDao) {
|
class TileRepository(private val tileDao: TileDao) {
|
||||||
private val coroutineScope = CoroutineScope(Dispatchers.Main)
|
private val coroutineScope = CoroutineScope(Dispatchers.Main)
|
||||||
|
|
||||||
fun pushTile(tile: Tile) {
|
fun pushTile(tile: Tile) {
|
||||||
tileDao.pushTile(tile)
|
coroutineScope.launch(Dispatchers.IO) { tileDao.pushTile(tile) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTile(x: Int, y: Int, level: Int): Tile? {
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
return tileDao.getTile(x, y, level)
|
suspend fun getTile(x: Int, y: Int, level: Int): Tile? {
|
||||||
|
val tileDeferred = coroutineScope.async(Dispatchers.IO) {
|
||||||
|
tileDao.getTile(x, y, level)
|
||||||
|
}
|
||||||
|
return tileDeferred.await()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearTiles() {
|
fun clearTiles() {
|
||||||
tileDao.clearTiles()
|
coroutineScope.launch(Dispatchers.IO) { tileDao.clearTiles() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
class TileViewModel(application: Application): ViewModel() {
|
class TileViewModel(application: Application): ViewModel() {
|
||||||
private val repository: TileRepository
|
val repository: TileRepository
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val tileDb = TileDB.getInstance(application)
|
val tileDb = TileDB.getInstance(application)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue