Compare commits

..

7 commits

6 changed files with 119 additions and 25 deletions

View file

@ -123,6 +123,12 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
// Ktor
val ktor_version = "2.3.1"
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-cio:$ktor_version")
implementation(platform("dev.forkhandles:forkhandles-bom:2.6.0.0")) implementation(platform("dev.forkhandles:forkhandles-bom:2.6.0.0"))
implementation("dev.forkhandles:result4k") implementation("dev.forkhandles:result4k")
@ -143,5 +149,6 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
// Map Compose library
implementation("ovh.plrapps:mapcompose:2.7.1")
} }

View file

@ -2,9 +2,6 @@
package ru.nm17.narodmon.ui.elements package ru.nm17.narodmon.ui.elements
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -22,9 +19,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.activity.ComponentActivity
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.core.content.ContextCompat.startActivity
import ru.nm17.narodmon.R import ru.nm17.narodmon.R
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -40,7 +35,7 @@ fun AgreementDialog(modifier: Modifier = Modifier, onClick: () -> Unit) {
Text(text = stringResource(id = R.string.agreement_dialog_text)) Text(text = stringResource(id = R.string.agreement_dialog_text))
Divider(Modifier.padding(vertical = 8.dp)) Divider(Modifier.padding(vertical = 8.dp))
ListItem( ListItem(
headlineText = { headlineContent = {
Text( Text(
text = stringResource(id = R.string.privacy_policy), text = stringResource(id = R.string.privacy_policy),
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
@ -56,7 +51,7 @@ fun AgreementDialog(modifier: Modifier = Modifier, onClick: () -> Unit) {
) )
ListItem( ListItem(
headlineText = { headlineContent = {
Text( Text(
text = stringResource(id = R.string.user_agreement), text = stringResource(id = R.string.user_agreement),
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall

View file

@ -35,7 +35,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View file

@ -1,46 +1,97 @@
package ru.nm17.narodmon.ui.pages package ru.nm17.narodmon.ui.pages
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChip
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
import ru.nm17.narodmon.Greeting import ovh.plrapps.mapcompose.api.scale
import ovh.plrapps.mapcompose.api.setScroll
import ovh.plrapps.mapcompose.ui.MapUI
import ru.nm17.narodmon.R import ru.nm17.narodmon.R
import ru.nm17.narodmon.ui.elements.GenericNavScaffold import ru.nm17.narodmon.ui.elements.GenericNavScaffold
import ru.nm17.narodmon.ui.viewmodel.MapViewModel
enum class SensorsFilter {
All, Thermometer, Camera,
}
@ExperimentalMaterial3Api @ExperimentalMaterial3Api
@Composable @Composable
fun SensorsPage(navController: NavController) { fun SensorsPage(navController: NavController) {
val mapVM by remember { mutableStateOf(MapViewModel()) }
var filter by remember { mutableStateOf(SensorsFilter.All) }
val scrConfig = LocalConfiguration.current
val mapHeight = scrConfig.screenHeightDp / 3
LaunchedEffect(mapVM) {
// TODO: Подгружать сохранённую позицию
mapVM.state.setScroll(Offset(28702.6F, 14787.6F))
mapVM.state.scale = 1.4658884F
}
GenericNavScaffold( GenericNavScaffold(
title = { Text(text = stringResource(R.string.sensors_page_title)) } title = { Text(text = stringResource(R.string.sensors_page_title)) }
) { ) {
Column { Column(modifier = Modifier.padding(it)) {
Greeting("Hello sensors")
Row { MapUI(state = mapVM.state, modifier = Modifier.height(mapHeight.dp))
FilterChip(
selected = true, Row(
onClick = { }, modifier = Modifier.padding(horizontal = 8.dp),
label = { Text("Temp") } horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
SensorsFilterChip(
name = stringResource(R.string.sensors_filter_all),
checkFilter = { filter == SensorsFilter.All },
updateFilter = { filter = SensorsFilter.All },
) )
FilterChip( SensorsFilterChip(
selected = false, name = stringResource(R.string.sensors_filter_temp),
onClick = { }, checkFilter = { filter == SensorsFilter.Thermometer },
label = { Text("Abc") } updateFilter = { filter = SensorsFilter.Thermometer },
) )
FilterChip( SensorsFilterChip(
selected = false, name = stringResource(R.string.sensors_filter_camera),
onClick = { }, checkFilter = { filter == SensorsFilter.Camera },
label = { Text("Def") } updateFilter = { filter = SensorsFilter.Camera },
) )
} }
//Text(mapVM.state.scroll.toString())
//Text(mapVM.state.scale.toString())
} }
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SensorsFilterChip(
name: String,
checkFilter: () -> Boolean,
updateFilter: () -> Unit,
) {
FilterChip(
selected = checkFilter(),
onClick = updateFilter,
label = { Text(name) },
)
}

View file

@ -0,0 +1,39 @@
package ru.nm17.narodmon.ui.viewmodel
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsChannel
import io.ktor.utils.io.jvm.javaio.toInputStream
import ovh.plrapps.mapcompose.api.addLayer
import ovh.plrapps.mapcompose.core.TileStreamProvider
import ovh.plrapps.mapcompose.ui.state.MapState
import java.io.InputStream
class MapViewModel : ViewModel() {
private val client = HttpClient(CIO)
private val tileStreamProvider = TileStreamProvider { row, col, zoom ->
requestTile(row, col, zoom)
}
private val mapSize = 32768
val state: MapState by mutableStateOf(
MapState(
levelCount = 8,
fullWidth = mapSize,
fullHeight = mapSize,
workerCount = 16,
).apply {
addLayer(tileStreamProvider)
}
)
private suspend fun requestTile(row: Int, col: Int, zoom: Int): InputStream {
val response = client.get("https://tile.openstreetmap.org/${zoom}/${col}/${row}.png")
return response.bodyAsChannel().toInputStream()
}
}

View file

@ -15,4 +15,7 @@
<string name="agreement_dialog_title">Примите необходимые соглашения</string> <string name="agreement_dialog_title">Примите необходимые соглашения</string>
<string name="sensors_page_title">Сенсоры</string> <string name="sensors_page_title">Сенсоры</string>
<string name="waiting_for_user_agreement">Ожидаю соглашение пользователя</string> <string name="waiting_for_user_agreement">Ожидаю соглашение пользователя</string>
<string name="sensors_filter_all">Все</string>
<string name="sensors_filter_temp">Термометры</string>
<string name="sensors_filter_camera">Камеры</string>
</resources> </resources>