Compare commits
No commits in common. "2a6bfb205c34fb5e7892019311484168f9af0167" and "4c3584d63c864a42e174cb5dcc9aaf975b2f81bf" have entirely different histories.
2a6bfb205c
...
4c3584d63c
14 changed files with 226 additions and 346 deletions
|
@ -106,6 +106,12 @@ dependencies {
|
||||||
// optional - Kotlin Extensions and Coroutines support for Room
|
// optional - Kotlin Extensions and Coroutines support for Room
|
||||||
implementation("androidx.room:room-ktx:$room_version")
|
implementation("androidx.room:room-ktx:$room_version")
|
||||||
|
|
||||||
|
// optional - RxJava2 support for Room
|
||||||
|
implementation("androidx.room:room-rxjava2:$room_version")
|
||||||
|
|
||||||
|
// optional - RxJava3 support for Room
|
||||||
|
implementation("androidx.room:room-rxjava3:$room_version")
|
||||||
|
|
||||||
// optional - Guava support for Room, including Optional and ListenableFuture
|
// optional - Guava support for Room, including Optional and ListenableFuture
|
||||||
implementation("androidx.room:room-guava:$room_version")
|
implementation("androidx.room:room-guava:$room_version")
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,23 @@ class MainActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Greeting(name: String, modifier: Modifier = Modifier) {
|
||||||
|
Text(
|
||||||
|
text = "Hello $name!",
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NavHolderEl() {
|
fun NavHolderEl() {
|
||||||
//NavHost(navController = NavHostController(N), graph =)
|
//NavHost(navController = NavHostController(N), graph =)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun GreetingPreview() {
|
||||||
|
NarodMonTheme {
|
||||||
|
Greeting("Android")
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,119 +0,0 @@
|
||||||
package ru.nm17.narodmon.ui.bottomSheets
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
|
||||||
import androidx.compose.material3.SheetState
|
|
||||||
import androidx.compose.material3.SheetValue
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import ru.nm17.narodmon.R
|
|
||||||
import ru.nm17.narodmon.ui.entities.SensorFilterUiEntity
|
|
||||||
import ru.nm17.narodmon.ui.pages.FilterCheckbox
|
|
||||||
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun FilterSensorsBottomSheet(
|
|
||||||
onApply: (filters: List<SensorFilterUiEntity>) -> Unit,
|
|
||||||
onDismissRequest: () -> Unit
|
|
||||||
) {
|
|
||||||
val filterItems = remember {
|
|
||||||
listOf(
|
|
||||||
/* TODO:
|
|
||||||
* Заменить `code` на настоящее значение
|
|
||||||
* либо динамически его подгружать из ответа АПИ
|
|
||||||
* (см. /appInit, ключ в жсоне: types.type) */
|
|
||||||
SensorFilterUiEntity(R.string.filter_temp, 0),
|
|
||||||
SensorFilterUiEntity(R.string.filter_temp_water, 1),
|
|
||||||
SensorFilterUiEntity(R.string.filter_temp_ground, 2),
|
|
||||||
SensorFilterUiEntity(R.string.filter_temp_dew_point, 3),
|
|
||||||
SensorFilterUiEntity(R.string.filter_humidity, 4),
|
|
||||||
SensorFilterUiEntity(R.string.filter_pressure, 5),
|
|
||||||
SensorFilterUiEntity(R.string.filter_lightness, 6),
|
|
||||||
SensorFilterUiEntity(R.string.filter_uv, 7),
|
|
||||||
SensorFilterUiEntity(R.string.filter_radiation, 8),
|
|
||||||
SensorFilterUiEntity(R.string.filter_rainfall, 9),
|
|
||||||
SensorFilterUiEntity(R.string.filter_dust, 10),
|
|
||||||
SensorFilterUiEntity(R.string.filter_wind_speed, 11),
|
|
||||||
SensorFilterUiEntity(R.string.filter_wind_direction, 12),
|
|
||||||
SensorFilterUiEntity(R.string.filter_concentration, 13),
|
|
||||||
SensorFilterUiEntity(R.string.filter_power, 14),
|
|
||||||
SensorFilterUiEntity(R.string.filter_voltage, 15),
|
|
||||||
SensorFilterUiEntity(R.string.filter_amperage, 16),
|
|
||||||
SensorFilterUiEntity(R.string.filter_energy, 17),
|
|
||||||
SensorFilterUiEntity(R.string.filter_battery, 18),
|
|
||||||
SensorFilterUiEntity(R.string.filter_rxtx, 19),
|
|
||||||
SensorFilterUiEntity(R.string.filter_signal, 20),
|
|
||||||
SensorFilterUiEntity(R.string.filter_water_meter, 21),
|
|
||||||
SensorFilterUiEntity(R.string.filter_time, 22),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ModalBottomSheet(
|
|
||||||
onDismissRequest = { onDismissRequest.invoke() },
|
|
||||||
sheetState = SheetState(true)
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
) {
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.sensors_filter_title),
|
|
||||||
fontSize = 24.sp,
|
|
||||||
fontWeight = FontWeight(500),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Box(contentAlignment = Alignment.BottomCenter) {
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 4.dp)
|
|
||||||
.fillMaxWidth(),
|
|
||||||
) {
|
|
||||||
items(filterItems) {
|
|
||||||
FilterCheckbox(
|
|
||||||
checked = it.enabled.value,
|
|
||||||
stringRes = it.stringRes,
|
|
||||||
) { it.enabled.value = !it.enabled.value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
onClick = { onApply.invoke(filterItems) },
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 16.dp, horizontal = 64.dp)
|
|
||||||
) {
|
|
||||||
Text(text = stringResource(id = R.string.apply))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun PreviewSensorFilterBottomSheet() {
|
|
||||||
NarodMonTheme {
|
|
||||||
FilterSensorsBottomSheet({}) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
package ru.nm17.narodmon.ui.bottomSheets
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
|
||||||
import androidx.compose.material3.SheetState
|
|
||||||
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.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import ru.nm17.narodmon.R
|
|
||||||
import ru.nm17.narodmon.ui.entities.SensorSortingUiEntity
|
|
||||||
import ru.nm17.narodmon.ui.entities.SortingTypes
|
|
||||||
import ru.nm17.narodmon.ui.pages.FilterRadioButton
|
|
||||||
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun SortSensorsBottomSheet(
|
|
||||||
onApply: (sortingType: SortingTypes) -> Unit,
|
|
||||||
onDismissRequest: () -> Unit
|
|
||||||
) {
|
|
||||||
var sortingType by remember { mutableStateOf(SortingTypes.DISTANCE) }
|
|
||||||
|
|
||||||
val sortingTypes = remember {
|
|
||||||
listOf(
|
|
||||||
SensorSortingUiEntity(R.string.sort_by_name, SortingTypes.NAME),
|
|
||||||
SensorSortingUiEntity(R.string.sort_by_name_desc, SortingTypes.NAME_DESC),
|
|
||||||
SensorSortingUiEntity(R.string.sort_by_distance, SortingTypes.DISTANCE),
|
|
||||||
SensorSortingUiEntity(R.string.sort_by_distance_desc, SortingTypes.DISTANCE_DESC),
|
|
||||||
SensorSortingUiEntity(R.string.sort_by_type, SortingTypes.TYPE),
|
|
||||||
SensorSortingUiEntity(R.string.sort_by_type_desc, SortingTypes.TYPE_DESC),
|
|
||||||
SensorSortingUiEntity(R.string.sort_update_time, SortingTypes.UPD_TIME),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ModalBottomSheet(
|
|
||||||
onDismissRequest = { onDismissRequest.invoke() },
|
|
||||||
sheetState = SheetState(true)
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.sensors_sort_title),
|
|
||||||
fontSize = 24.sp,
|
|
||||||
fontWeight = FontWeight(500),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 4.dp)
|
|
||||||
.fillMaxWidth(),
|
|
||||||
) {
|
|
||||||
items(sortingTypes) {
|
|
||||||
FilterRadioButton(
|
|
||||||
selected = (sortingType == it.sortingType),
|
|
||||||
onClick = { sortingType = it.sortingType },
|
|
||||||
stringRes = it.stringRes,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 64.dp, vertical = 8.dp),
|
|
||||||
onClick = {
|
|
||||||
onApply.invoke(sortingType)
|
|
||||||
}) {
|
|
||||||
Text(text = stringResource(R.string.apply))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun PreviewSortBottomSheet() {
|
|
||||||
NarodMonTheme {
|
|
||||||
SortSensorsBottomSheet(onApply = {}) {}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package ru.nm17.narodmon.ui.entities
|
|
||||||
|
|
||||||
import ru.nm17.narodmon.db.entities.SensorType
|
|
||||||
|
|
||||||
|
|
||||||
data class SensorEntity(
|
|
||||||
// TODO: Вынести в отдельный класс, и явно не в директорию `ui`
|
|
||||||
val id: Int,
|
|
||||||
val type: SensorType,
|
|
||||||
val deviceName: String,
|
|
||||||
val deviceOwner: Int,
|
|
||||||
val name: String,
|
|
||||||
val favorite: Boolean,
|
|
||||||
val public: Boolean,
|
|
||||||
val mine: Boolean,
|
|
||||||
val location: String,
|
|
||||||
val distance: Double, // километры
|
|
||||||
val value: Double,
|
|
||||||
val unit: String,
|
|
||||||
val changed: Int,
|
|
||||||
)
|
|
|
@ -1,11 +0,0 @@
|
||||||
package ru.nm17.narodmon.ui.entities
|
|
||||||
|
|
||||||
import androidx.compose.runtime.MutableState
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
|
|
||||||
data class SensorFilterUiEntity(
|
|
||||||
// TODO: Можно попробовать объединить с db/SensorType.kt
|
|
||||||
val stringRes: Int,
|
|
||||||
val code: Int,
|
|
||||||
var enabled: MutableState<Boolean> = mutableStateOf(false),
|
|
||||||
)
|
|
|
@ -1,7 +0,0 @@
|
||||||
package ru.nm17.narodmon.ui.entities
|
|
||||||
|
|
||||||
|
|
||||||
data class SensorSortingUiEntity(
|
|
||||||
val stringRes: Int,
|
|
||||||
val sortingType: SortingTypes,
|
|
||||||
)
|
|
|
@ -1 +0,0 @@
|
||||||
package ru.nm17.narodmon.ui.entities
|
|
|
@ -1,13 +0,0 @@
|
||||||
package ru.nm17.narodmon.ui.entities
|
|
||||||
|
|
||||||
enum class SortingTypes {
|
|
||||||
DISTANCE,
|
|
||||||
DISTANCE_DESC,
|
|
||||||
TYPE,
|
|
||||||
TYPE_DESC,
|
|
||||||
UPD_TIME,
|
|
||||||
NAME,
|
|
||||||
NAME_DESC,
|
|
||||||
VALUE,
|
|
||||||
VALUE_DESC
|
|
||||||
}
|
|
|
@ -11,17 +11,20 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.AssistChip
|
import androidx.compose.material3.AssistChip
|
||||||
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.Divider
|
import androidx.compose.material3.Divider
|
||||||
import androidx.compose.material3.ElevatedCard
|
import androidx.compose.material3.ElevatedCard
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.FilterChip
|
import androidx.compose.material3.FilterChip
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
import androidx.compose.material3.RadioButton
|
import androidx.compose.material3.RadioButton
|
||||||
import androidx.compose.material3.SearchBar
|
import androidx.compose.material3.SearchBar
|
||||||
|
import androidx.compose.material3.Shapes
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
@ -29,24 +32,53 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
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.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import ru.nm17.narodmon.R
|
import ru.nm17.narodmon.R
|
||||||
import ru.nm17.narodmon.db.entities.SensorType
|
import ru.nm17.narodmon.db.entities.SensorType
|
||||||
import ru.nm17.narodmon.ui.bottomSheets.FilterSensorsBottomSheet
|
|
||||||
import ru.nm17.narodmon.ui.bottomSheets.SortSensorsBottomSheet
|
|
||||||
import ru.nm17.narodmon.ui.elements.GenericNavScaffold
|
import ru.nm17.narodmon.ui.elements.GenericNavScaffold
|
||||||
import ru.nm17.narodmon.ui.elements.TileMap
|
import ru.nm17.narodmon.ui.elements.TileMap
|
||||||
import ru.nm17.narodmon.ui.entities.SensorEntity
|
|
||||||
import ru.nm17.narodmon.ui.entities.SensorFilterUiEntity
|
|
||||||
import ru.nm17.narodmon.ui.entities.SortingTypes
|
|
||||||
import ru.nm17.narodmon.ui.iosevkaFamily
|
import ru.nm17.narodmon.ui.iosevkaFamily
|
||||||
|
|
||||||
|
data class Sensor(
|
||||||
|
// TODO: Вынести в отдельный класс, и явно не в директорию `ui`
|
||||||
|
val id: Int,
|
||||||
|
val type: SensorType,
|
||||||
|
val deviceName: String,
|
||||||
|
val deviceOwner: Int,
|
||||||
|
val name: String,
|
||||||
|
val favorite: Boolean,
|
||||||
|
val public: Boolean,
|
||||||
|
val mine: Boolean,
|
||||||
|
val location: String,
|
||||||
|
val distance: Double, // километры
|
||||||
|
val value: Double,
|
||||||
|
val unit: String,
|
||||||
|
val changed: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class SensorFilter(
|
||||||
|
// TODO: Можно попробовать объединить с db/SensorType.kt
|
||||||
|
val stringRes: Int,
|
||||||
|
val code: Int,
|
||||||
|
var enabled: MutableState<Boolean> = mutableStateOf(false),
|
||||||
|
)
|
||||||
|
|
||||||
|
data class SensorSortingItem(
|
||||||
|
val stringRes: Int,
|
||||||
|
val sortingType: SortingType,
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class SortingType {
|
||||||
|
DISTANCE, TYPE, UPD_TIME,
|
||||||
|
NAME, VALUE,
|
||||||
|
}
|
||||||
|
|
||||||
@ExperimentalMaterial3Api
|
@ExperimentalMaterial3Api
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -54,18 +86,61 @@ fun SensorsPage(navController: NavController) {
|
||||||
var searchQuery by remember { mutableStateOf("") }
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
var searchActive by remember { mutableStateOf(false) }
|
var searchActive by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
|
||||||
var sortingShow by remember { mutableStateOf(false) }
|
var sortingShow by remember { mutableStateOf(false) }
|
||||||
var sortingType by remember { mutableStateOf(SortingTypes.DISTANCE) }
|
var sortingType by remember { mutableStateOf(SortingType.DISTANCE) }
|
||||||
|
var sortingDesc by remember { mutableStateOf(false) }
|
||||||
|
var sortingMine by remember { mutableStateOf(false) }
|
||||||
|
var sortingFav by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val sortingTypes = remember {
|
||||||
|
listOf(
|
||||||
|
SensorSortingItem(R.string.sort_distance, SortingType.DISTANCE),
|
||||||
|
SensorSortingItem(R.string.sort_type, SortingType.TYPE),
|
||||||
|
SensorSortingItem(R.string.sort_update_time, SortingType.UPD_TIME),
|
||||||
|
SensorSortingItem(R.string.sort_name, SortingType.NAME),
|
||||||
|
SensorSortingItem(R.string.sort_value, SortingType.VALUE),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var filterShow by remember { mutableStateOf(false) }
|
var filterShow by remember { mutableStateOf(false) }
|
||||||
var filterMine by remember { mutableStateOf(false) }
|
var filterMine by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val filterItems = remember {
|
||||||
|
listOf(
|
||||||
|
/* TODO:
|
||||||
|
* Заменить `code` на настоящее значение
|
||||||
|
* либо динамически его подгружать из ответа АПИ
|
||||||
|
* (см. /appInit, ключ в жсоне: types.type) */
|
||||||
|
SensorFilter(R.string.filter_temp, 0),
|
||||||
|
SensorFilter(R.string.filter_temp_water, 1),
|
||||||
|
SensorFilter(R.string.filter_temp_ground, 2),
|
||||||
|
SensorFilter(R.string.filter_temp_dew_point, 3),
|
||||||
|
SensorFilter(R.string.filter_humidity, 4),
|
||||||
|
SensorFilter(R.string.filter_pressure, 5),
|
||||||
|
SensorFilter(R.string.filter_lightness, 6),
|
||||||
|
SensorFilter(R.string.filter_uv, 7),
|
||||||
|
SensorFilter(R.string.filter_radiation, 8),
|
||||||
|
SensorFilter(R.string.filter_rainfall, 9),
|
||||||
|
SensorFilter(R.string.filter_dust, 10),
|
||||||
|
SensorFilter(R.string.filter_wind_speed, 11),
|
||||||
|
SensorFilter(R.string.filter_wind_direction, 12),
|
||||||
|
SensorFilter(R.string.filter_concentration, 13),
|
||||||
|
SensorFilter(R.string.filter_power, 14),
|
||||||
|
SensorFilter(R.string.filter_voltage, 15),
|
||||||
|
SensorFilter(R.string.filter_amperage, 16),
|
||||||
|
SensorFilter(R.string.filter_energy, 17),
|
||||||
|
SensorFilter(R.string.filter_battery, 18),
|
||||||
|
SensorFilter(R.string.filter_rxtx, 19),
|
||||||
|
SensorFilter(R.string.filter_signal, 20),
|
||||||
|
SensorFilter(R.string.filter_water_meter, 21),
|
||||||
|
SensorFilter(R.string.filter_time, 22),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val sensorEntities = remember {
|
val sensors = remember {
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
// TODO: загружать датчики с сервера. Этот список -- для макета
|
// TODO: загружать датчики с сервера. Этот список -- для макета
|
||||||
SensorEntity(
|
Sensor(
|
||||||
0,
|
0,
|
||||||
SensorType(0, "temp", "C"),
|
SensorType(0, "temp", "C"),
|
||||||
"device0", 0,
|
"device0", 0,
|
||||||
|
@ -74,7 +149,7 @@ fun SensorsPage(navController: NavController) {
|
||||||
"Москва", 0.4,
|
"Москва", 0.4,
|
||||||
20.0, "C", 1686142800,
|
20.0, "C", 1686142800,
|
||||||
),
|
),
|
||||||
SensorEntity(
|
Sensor(
|
||||||
1,
|
1,
|
||||||
SensorType(4, "humidity", "%"),
|
SensorType(4, "humidity", "%"),
|
||||||
"device1", 0,
|
"device1", 0,
|
||||||
|
@ -83,7 +158,7 @@ fun SensorsPage(navController: NavController) {
|
||||||
"Подмосковье", 1.1,
|
"Подмосковье", 1.1,
|
||||||
39.0, "%", 1686142800,
|
39.0, "%", 1686142800,
|
||||||
),
|
),
|
||||||
SensorEntity(
|
Sensor(
|
||||||
2,
|
2,
|
||||||
SensorType(11, "wind speed", "m/s"),
|
SensorType(11, "wind speed", "m/s"),
|
||||||
"device2", 1,
|
"device2", 1,
|
||||||
|
@ -112,9 +187,7 @@ fun SensorsPage(navController: NavController) {
|
||||||
onQueryChange = { query -> searchQuery = query },
|
onQueryChange = { query -> searchQuery = query },
|
||||||
onSearch = { searchActive = false },
|
onSearch = { searchActive = false },
|
||||||
placeholder = { Text(stringResource(R.string.search)) },
|
placeholder = { Text(stringResource(R.string.search)) },
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxWidth()
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = if (!searchActive) 8.dp else 0.dp)
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
|
@ -123,23 +196,11 @@ fun SensorsPage(navController: NavController) {
|
||||||
) {
|
) {
|
||||||
AssistChip(
|
AssistChip(
|
||||||
onClick = { filterShow = true },
|
onClick = { filterShow = true },
|
||||||
leadingIcon = {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_filter),
|
|
||||||
contentDescription = stringResource(id = R.string.sensors_filter)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
label = { Text(text = stringResource(R.string.sensors_filter)) },
|
label = { Text(text = stringResource(R.string.sensors_filter)) },
|
||||||
)
|
)
|
||||||
|
|
||||||
AssistChip(
|
AssistChip(
|
||||||
onClick = { sortingShow = true },
|
onClick = { sortingShow = true },
|
||||||
leadingIcon = {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_sort),
|
|
||||||
contentDescription = stringResource(id = R.string.sensors_sorting)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
label = { Text(text = stringResource(R.string.sensors_sorting)) },
|
label = { Text(text = stringResource(R.string.sensors_sorting)) },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -155,7 +216,7 @@ fun SensorsPage(navController: NavController) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxHeight(),
|
modifier = Modifier.fillMaxHeight(),
|
||||||
) {
|
) {
|
||||||
items(sensorEntities) { sensor ->
|
items(sensors) { sensor ->
|
||||||
SensorItem(sensor)
|
SensorItem(sensor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,42 +224,105 @@ fun SensorsPage(navController: NavController) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterShow) {
|
if (filterShow) {
|
||||||
FilterSensorsBottomSheet(
|
ModalBottomSheet(onDismissRequest = { filterShow = false }) {
|
||||||
onApply = {
|
Row(
|
||||||
// TODO применение фильтров
|
horizontalArrangement = Arrangement.Center,
|
||||||
filterShow = false
|
modifier = Modifier.fillMaxWidth(),
|
||||||
},
|
) {
|
||||||
onDismissRequest = { filterShow = false }
|
Text(
|
||||||
|
text = stringResource(R.string.sensors_filter_title),
|
||||||
|
fontSize = 24.sp,
|
||||||
|
fontWeight = FontWeight(500),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
items(filterItems) {
|
||||||
|
FilterCheckbox(
|
||||||
|
checked = it.enabled.value,
|
||||||
|
onCheckedChange = { it.enabled.value = !it.enabled.value },
|
||||||
|
stringRes = it.stringRes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sortingShow) {
|
if (sortingShow) {
|
||||||
SortSensorsBottomSheet(
|
ModalBottomSheet(onDismissRequest = { sortingShow = false }) {
|
||||||
onApply = { s ->
|
Row(
|
||||||
sortingType = s
|
horizontalArrangement = Arrangement.Center,
|
||||||
sortingShow = false
|
modifier = Modifier.fillMaxWidth(),
|
||||||
},
|
) {
|
||||||
onDismissRequest = { sortingShow = false })
|
Text(
|
||||||
|
text = stringResource(R.string.sensors_sort_title),
|
||||||
|
fontSize = 24.sp,
|
||||||
|
fontWeight = FontWeight(500),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
items(sortingTypes) {
|
||||||
|
FilterRadioButton(
|
||||||
|
selected = (sortingType == it.sortingType),
|
||||||
|
onClick = { sortingType = it.sortingType },
|
||||||
|
stringRes = it.stringRes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
FilterCheckbox(
|
||||||
|
checked = sortingDesc,
|
||||||
|
onCheckedChange = { sortingDesc = !sortingDesc },
|
||||||
|
stringRes = R.string.sort_option_desc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
FilterCheckbox(
|
||||||
|
checked = sortingFav,
|
||||||
|
onCheckedChange = { sortingFav = !sortingFav },
|
||||||
|
stringRes = R.string.sort_option_fav,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
FilterCheckbox(
|
||||||
|
checked = sortingMine,
|
||||||
|
onCheckedChange = { sortingMine = !sortingMine },
|
||||||
|
stringRes = R.string.sort_option_mine,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalMaterial3Api
|
@ExperimentalMaterial3Api
|
||||||
@Composable
|
@Composable
|
||||||
fun SensorItem(sensorEntity: SensorEntity) {
|
fun SensorItem(sensor: Sensor) {
|
||||||
ListItem(
|
ListItem(
|
||||||
overlineContent = { Text(text = "${sensorEntity.deviceName} от ${sensorEntity.deviceOwner}") },
|
overlineContent = { Text(text = "${sensor.deviceName} от ${sensor.deviceOwner}") },
|
||||||
headlineContent = { Text(text = sensorEntity.type.name) },
|
headlineContent = { Text(text = sensor.type.name) },
|
||||||
supportingContent = { Text(text = sensorEntity.name) },
|
supportingContent = { Text(text = sensor.name) },
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.End,
|
horizontalAlignment = Alignment.End,
|
||||||
) {
|
) {
|
||||||
Text(text = "${sensorEntity.distance} km")
|
Text(text = "${sensor.distance} km")
|
||||||
ElevatedCard(
|
ElevatedCard(
|
||||||
shape = RectangleShape,
|
shape = RectangleShape,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "${sensorEntity.value} ${sensorEntity.unit}",
|
text = "${sensor.value} ${sensor.unit}",
|
||||||
fontFamily = iosevkaFamily,
|
fontFamily = iosevkaFamily,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Medium,
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
|
@ -212,12 +336,9 @@ fun SensorItem(sensorEntity: SensorEntity) {
|
||||||
|
|
||||||
@ExperimentalMaterial3Api
|
@ExperimentalMaterial3Api
|
||||||
@Composable
|
@Composable
|
||||||
fun FilterCheckbox(checked: Boolean, stringRes: Int, onCheckedChange: () -> Unit) {
|
fun FilterCheckbox(checked: Boolean, onCheckedChange: () -> Unit, stringRes: Int) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clickable { onCheckedChange() }
|
|
||||||
) {
|
) {
|
||||||
Checkbox(
|
Checkbox(
|
||||||
checked = checked,
|
checked = checked,
|
||||||
|
@ -225,6 +346,7 @@ fun FilterCheckbox(checked: Boolean, stringRes: Int, onCheckedChange: () -> Unit
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = stringRes),
|
text = stringResource(id = stringRes),
|
||||||
|
modifier = Modifier.clickable { onCheckedChange() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,14 +356,14 @@ fun FilterCheckbox(checked: Boolean, stringRes: Int, onCheckedChange: () -> Unit
|
||||||
fun FilterRadioButton(selected: Boolean, onClick: () -> Unit, stringRes: Int) {
|
fun FilterRadioButton(selected: Boolean, onClick: () -> Unit, stringRes: Int) {
|
||||||
Row (
|
Row (
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clickable { onClick.invoke() }
|
|
||||||
) {
|
) {
|
||||||
RadioButton(
|
RadioButton(
|
||||||
selected = selected,
|
selected = selected,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
)
|
)
|
||||||
Text(text = stringResource(id = stringRes))
|
Text(
|
||||||
|
text = stringResource(id = stringRes),
|
||||||
|
modifier = Modifier.clickable { onClick() },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
<vector android:height="24dp" android:tint="#000000"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/>
|
|
||||||
</vector>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<vector android:autoMirrored="true" android:height="24dp"
|
|
||||||
android:tint="#000000" android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
|
|
||||||
</vector>
|
|
14
app/src/main/res/layout/fragment_sensors.xml
Normal file
14
app/src/main/res/layout/fragment_sensors.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".Sensors">
|
||||||
|
|
||||||
|
<!-- TODO: Update blank fragment layout -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="@string/hello_blank_fragment" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
|
@ -1,6 +1,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Народный Мониторинг</string>
|
<string name="app_name">Народный Мониторинг</string>
|
||||||
<!-- TODO: Remove or change this placeholder text -->
|
<!-- TODO: Remove or change this placeholder text -->
|
||||||
|
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||||
<string name="accept_agreements">Я принимаю соглашения</string>
|
<string name="accept_agreements">Я принимаю соглашения</string>
|
||||||
<string name="exit">Выйти</string>
|
<string name="exit">Выйти</string>
|
||||||
<string name="agreement_dialog_text">
|
<string name="agreement_dialog_text">
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
<string name="search">Поиск</string>
|
<string name="search">Поиск</string>
|
||||||
<string name="sensors_filter">Фильтр</string>
|
<string name="sensors_filter">Фильтр</string>
|
||||||
<string name="sensors_sorting">Сортировка</string>
|
<string name="sensors_sorting">Сортировка</string>
|
||||||
<string name="sensors_mine">Мои датчики</string>
|
<string name="sensors_mine">Мои</string>
|
||||||
<string name="filter_temp_dew_point">Температура точки росы</string>
|
<string name="filter_temp_dew_point">Температура точки росы</string>
|
||||||
<string name="filter_temp">Температура воздуха</string>
|
<string name="filter_temp">Температура воздуха</string>
|
||||||
<string name="filter_temp_water">Температура воды</string>
|
<string name="filter_temp_water">Температура воды</string>
|
||||||
|
@ -42,13 +43,13 @@
|
||||||
<string name="filter_water_meter">Счётчик воды</string>
|
<string name="filter_water_meter">Счётчик воды</string>
|
||||||
<string name="filter_time">Время работы</string>
|
<string name="filter_time">Время работы</string>
|
||||||
<string name="sensors_filter_title">Тип датчиков</string>
|
<string name="sensors_filter_title">Тип датчиков</string>
|
||||||
<string name="sort_by_distance">От ближних к дальним</string>
|
<string name="sort_distance">Расстояние</string>
|
||||||
<string name="sort_by_type">По типу (от А до Я)</string>
|
<string name="sort_type">Тип датчика</string>
|
||||||
<string name="sort_by_type_desc">По типу (от Я до А)</string>
|
<string name="sort_update_time">Время последнего обновления</string>
|
||||||
<string name="sort_by_name">По названию (от А до Я)</string>
|
<string name="sort_name">Название</string>
|
||||||
<string name="sort_by_name_desc">По названию (от Я до А)</string>
|
<string name="sort_value">Данные</string>
|
||||||
<string name="sensors_sort_title">Сортировка датчиков</string>
|
<string name="sort_option_desc">По убыванию</string>
|
||||||
<string name="sort_update_time">По времени обновления</string>
|
<string name="sort_option_fav">Избранные сверху</string>
|
||||||
<string name="apply">Применить</string>
|
<string name="sort_option_mine">Мои датчики сверху</string>
|
||||||
<string name="sort_by_distance_desc">От дальних к ближним</string>
|
<string name="sensors_sort_title">Сортировка</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Add table
Reference in a new issue