Compare commits
62 commits
Author | SHA1 | Date | |
---|---|---|---|
e2ecbc4df9 | |||
5d501d201d | |||
0a6c3e703e | |||
55c583ba6a | |||
c774b8a402 | |||
3c03aed629 | |||
f09f98e637 | |||
4f67569409 | |||
033aa34c38 | |||
d181b39c55 | |||
4bbba45d49 | |||
b9376be372 | |||
1998931a98 | |||
80f8cc77b6 | |||
628b168bcf | |||
9975db912e | |||
1a2612d4ba | |||
a8aede84ff | |||
e5e6e5dfb5 | |||
7e5673f96e | |||
82c3797c90 | |||
b1e5af538a | |||
8c1c35afdd | |||
1811a22a5a | |||
0bdf64b7ed | |||
2a6bfb205c | |||
9cd0bcddc8 | |||
45c9101f9d | |||
1c8f993dcb | |||
937f4890e1 | |||
01b362ce4e | |||
d82a4b28b7 | |||
9d024a0c69 | |||
c32ea30772 | |||
b17e853103 | |||
be9b491c44 | |||
4c3584d63c | |||
9739d1cdfe | |||
9c6be5d8c5 | |||
12db4ba8df | |||
95e849e27a | |||
965533c8cc | |||
ebd8dadf7f | |||
e6f7ff8238 | |||
5639ebd4cd | |||
d1e7b60378 | |||
2a318d551c | |||
3a873725f2 | |||
1334014c04 | |||
06bc8a839e | |||
2b2a2c2f5a | |||
0935cd88d4 | |||
06bd65c4e4 | |||
bc73528681 | |||
e384ffdf6c | |||
72b82fa4e4 | |||
8a9ddbc27c | |||
03a758673b | |||
266e2001f2 | |||
96d7819d00 | |||
35bd573cb0 | |||
ecb76ca594 |
98 changed files with 1879 additions and 207 deletions
|
@ -74,63 +74,44 @@ dependencies {
|
||||||
debugImplementation(libs.ui.tooling)
|
debugImplementation(libs.ui.tooling)
|
||||||
debugImplementation(libs.ui.test.manifest)
|
debugImplementation(libs.ui.test.manifest)
|
||||||
|
|
||||||
|
|
||||||
|
//-- Navigation
|
||||||
val nav_version = "2.5.3"
|
val nav_version = "2.5.3"
|
||||||
|
|
||||||
// Java language implementation
|
|
||||||
implementation("androidx.navigation:navigation-fragment:$nav_version")
|
|
||||||
implementation("androidx.navigation:navigation-ui:$nav_version")
|
|
||||||
|
|
||||||
// Kotlin
|
|
||||||
implementation("androidx.navigation:navigation-fragment-ktx:$nav_version")
|
implementation("androidx.navigation:navigation-fragment-ktx:$nav_version")
|
||||||
implementation("androidx.navigation:navigation-ui-ktx:$nav_version")
|
implementation("androidx.navigation:navigation-ui-ktx:$nav_version")
|
||||||
|
|
||||||
// Feature module Support
|
|
||||||
implementation("androidx.navigation:navigation-dynamic-features-fragment:$nav_version")
|
implementation("androidx.navigation:navigation-dynamic-features-fragment:$nav_version")
|
||||||
|
|
||||||
// Testing Navigation
|
|
||||||
androidTestImplementation("androidx.navigation:navigation-testing:$nav_version")
|
androidTestImplementation("androidx.navigation:navigation-testing:$nav_version")
|
||||||
|
|
||||||
// Jetpack Compose Integration
|
|
||||||
implementation("androidx.navigation:navigation-compose:$nav_version")
|
implementation("androidx.navigation:navigation-compose:$nav_version")
|
||||||
|
|
||||||
val room_version = "2.5.1"
|
|
||||||
|
|
||||||
implementation("androidx.room:room-runtime:$room_version")
|
|
||||||
annotationProcessor("androidx.room:room-compiler:$room_version")
|
|
||||||
|
|
||||||
|
//-- Room
|
||||||
// To use Kotlin annotation processing tool (kapt)
|
// To use Kotlin annotation processing tool (kapt)
|
||||||
//kapt("androidx.room:room-compiler:$room_version")
|
//kapt("androidx.room:room-compiler:$room_version")
|
||||||
// To use Kotlin Symbol Processing (KSP)
|
// To use Kotlin Symbol Processing (KSP)
|
||||||
|
val room_version = "2.5.1"
|
||||||
|
|
||||||
ksp("androidx.room:room-compiler:$room_version")
|
ksp("androidx.room:room-compiler:$room_version")
|
||||||
|
annotationProcessor("androidx.room:room-compiler:$room_version")
|
||||||
// optional - Kotlin Extensions and Coroutines support for Room
|
implementation("androidx.room:room-runtime:$room_version")
|
||||||
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
|
|
||||||
implementation("androidx.room:room-guava:$room_version")
|
implementation("androidx.room:room-guava:$room_version")
|
||||||
|
|
||||||
// optional - Test helpers
|
|
||||||
testImplementation("androidx.room:room-testing:$room_version")
|
testImplementation("androidx.room:room-testing:$room_version")
|
||||||
|
|
||||||
// optional - Paging 3 Integration
|
|
||||||
implementation("androidx.room:room-paging:$room_version")
|
implementation("androidx.room:room-paging:$room_version")
|
||||||
|
|
||||||
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("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||||
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")
|
||||||
|
|
||||||
implementation("io.ktor:ktor-client-core:2.3.1")
|
implementation("io.ktor:ktor-client-core:2.3.1")
|
||||||
implementation("io.ktor:ktor-client-okhttp:2.3.1")
|
implementation("io.ktor:ktor-client-okhttp:2.3.1")
|
||||||
|
|
||||||
implementation("androidx.security:security-crypto-ktx:1.1.0-alpha06")
|
implementation("androidx.security:security-crypto-ktx:1.1.0-alpha06")
|
||||||
|
|
||||||
|
|
||||||
// For Identity Credential APIs
|
// For Identity Credential APIs
|
||||||
implementation("androidx.security:security-identity-credential:1.0.0-alpha03")
|
implementation("androidx.security:security-identity-credential:1.0.0-alpha03")
|
||||||
|
|
||||||
|
@ -144,4 +125,13 @@ 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")
|
||||||
|
|
||||||
|
|
||||||
|
//-- Glide
|
||||||
|
implementation("com.github.bumptech.glide:glide:4.14.2")
|
||||||
|
implementation("com.github.bumptech.glide:compose:1.0.0-alpha.1")
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class,
|
|
||||||
ExperimentalMaterial3Api::class
|
|
||||||
)
|
|
||||||
|
|
||||||
package ru.nm17.narodmon
|
package ru.nm17.narodmon
|
||||||
|
|
||||||
|
@ -25,74 +23,44 @@ 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.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.navigation.compose.NavHost
|
|
||||||
import androidx.navigation.compose.composable
|
|
||||||
import androidx.navigation.compose.rememberNavController
|
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import androidx.security.crypto.EncryptedSharedPreferences
|
|
||||||
import androidx.security.crypto.MasterKeys
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.nm17.narodmon.db.AppDatabase
|
import ru.nm17.narodmon.db.AppDatabase
|
||||||
import ru.nm17.narodmon.db.entities.KVSetting
|
import ru.nm17.narodmon.db.entities.KVSetting
|
||||||
import ru.nm17.narodmon.ui.elements.AgreementDialog
|
import ru.nm17.narodmon.ui.dialogs.AgreementDialog
|
||||||
import ru.nm17.narodmon.ui.pages.SensorsPage
|
import ru.nm17.narodmon.ui.navHost.AppNavHost
|
||||||
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AppNavHost() {
|
|
||||||
val navController = rememberNavController()
|
|
||||||
val coScope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NavHost(navController = navController, startDestination = "sensors") {
|
|
||||||
composable("agreement") {
|
|
||||||
|
|
||||||
}
|
|
||||||
composable("sensors") {
|
|
||||||
|
|
||||||
SensorsPage(navController)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*...*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
|
||||||
val db = Room.databaseBuilder(
|
val db = Room.databaseBuilder(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
AppDatabase::class.java, "data"
|
AppDatabase::class.java, "data"
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
|
// val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
|
||||||
|
//
|
||||||
val sharedPreferences = EncryptedSharedPreferences.create(
|
// val sharedPreferences = EncryptedSharedPreferences.create(
|
||||||
"secret_shared_prefs",
|
// "secret_shared_prefs",
|
||||||
masterKeyAlias,
|
// masterKeyAlias,
|
||||||
createDeviceProtectedStorageContext(),
|
// createDeviceProtectedStorageContext(),
|
||||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
// EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
// EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||||
)
|
// )
|
||||||
|
|
||||||
// use the shared preferences and editor as you normally would
|
// use the shared preferences and editor as you normally would
|
||||||
|
|
||||||
// use the shared preferences and editor as you normally would
|
// use the shared preferences and editor as you normally would
|
||||||
val credSharedPreferences = sharedPreferences
|
// val credSharedPreferences = sharedPreferences
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
val coScope = rememberCoroutineScope()
|
val coScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
|
||||||
//var asd = getPreferences()
|
//var asd = getPreferences()
|
||||||
|
|
||||||
NarodMonTheme {
|
NarodMonTheme {
|
||||||
|
@ -125,44 +93,15 @@ class MainActivity : ComponentActivity() {
|
||||||
Text(text = stringResource(R.string.waiting_for_user_agreement))
|
Text(text = stringResource(R.string.waiting_for_user_agreement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
AppNavHost()
|
AppNavHost()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// A surface container using the 'background' color from the theme
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@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")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,8 +16,10 @@ import io.ktor.http.headers
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.take
|
||||||
import kotlinx.datetime.Clock
|
import kotlinx.datetime.Clock
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
|
@ -120,7 +122,7 @@ class Client private constructor(
|
||||||
val client = this.httpClient1Min
|
val client = this.httpClient1Min
|
||||||
return flow<Result4k<AppInitResponse, APIError>> {
|
return flow<Result4k<AppInitResponse, APIError>> {
|
||||||
|
|
||||||
val resp = client.post("https://narodmon.ru/api") {
|
val resp = this@Client.httpClient1Min.take(1).first().post("https://narodmon.ru/api") {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
setBody(
|
setBody(
|
||||||
getJSONRequestBody("appInit", request)
|
getJSONRequestBody("appInit", request)
|
||||||
|
@ -132,7 +134,7 @@ class Client private constructor(
|
||||||
}.flowOn(Dispatchers.IO)
|
}.flowOn(Dispatchers.IO)
|
||||||
|
|
||||||
}
|
}
|
||||||
public fun appInit(request: AppInitRequest): Flow<Result4k<AppInitResponse, APIError>> {
|
/*public fun jjhgjhg(request: AppInitRequest): Flow<Result4k<AppInitResponse, APIError>> {
|
||||||
val client = this.httpClient1Min
|
val client = this.httpClient1Min
|
||||||
return flow<Result4k<AppInitResponse, APIError>> {
|
return flow<Result4k<AppInitResponse, APIError>> {
|
||||||
|
|
||||||
|
@ -147,5 +149,5 @@ class Client private constructor(
|
||||||
|
|
||||||
}.flowOn(Dispatchers.IO)
|
}.flowOn(Dispatchers.IO)
|
||||||
|
|
||||||
}
|
}*/
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities
|
||||||
|
|
||||||
|
|
||||||
|
data class SensorEntity(
|
||||||
|
val changed: Int,
|
||||||
|
val fav: Int,
|
||||||
|
val id: Int,
|
||||||
|
val mac: String,
|
||||||
|
val name: String,
|
||||||
|
val pub: Int,
|
||||||
|
val time: Int,
|
||||||
|
val trend: Int,
|
||||||
|
val type: Int,
|
||||||
|
val unit: String,
|
||||||
|
val value: Double
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.addLike
|
||||||
|
|
||||||
|
data class AddLikeRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val id: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.addLike
|
||||||
|
|
||||||
|
data class AddLikeResponseEntity(
|
||||||
|
val id: Int,
|
||||||
|
val liked: Int,
|
||||||
|
val time: Int
|
||||||
|
)
|
|
@ -0,0 +1,11 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.appInit
|
||||||
|
|
||||||
|
data class AppInitRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val platform: String,
|
||||||
|
val utc: Int,
|
||||||
|
val uuid: String,
|
||||||
|
val version: String
|
||||||
|
)
|
|
@ -0,0 +1,14 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.appInit
|
||||||
|
|
||||||
|
data class AppInitResponseEntity(
|
||||||
|
val addr: String,
|
||||||
|
val favorites: List<Any>,
|
||||||
|
val lat: Double,
|
||||||
|
val latest: String,
|
||||||
|
val login: String,
|
||||||
|
val lon: Double,
|
||||||
|
val timestamp: Int,
|
||||||
|
val types: List<AppInitTypeEntity>,
|
||||||
|
val url: String,
|
||||||
|
val vip: Int
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.appInit
|
||||||
|
|
||||||
|
data class AppInitTypeEntity(
|
||||||
|
val name: String,
|
||||||
|
val type: Int,
|
||||||
|
val unit: String
|
||||||
|
)
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.bugReport
|
||||||
|
|
||||||
|
data class BugReportRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val email: String,
|
||||||
|
val logs: String,
|
||||||
|
val mess: String,
|
||||||
|
val name: String,
|
||||||
|
val time: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.disLike
|
||||||
|
|
||||||
|
data class DisLikeRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val id: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.disLike
|
||||||
|
|
||||||
|
data class DisLikeResponseEntity(
|
||||||
|
val id: Int,
|
||||||
|
val liked: Int,
|
||||||
|
val time: Int
|
||||||
|
)
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.mapBounds
|
||||||
|
|
||||||
|
data class MapBoundsDeviceEntity(
|
||||||
|
val id: Int,
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double,
|
||||||
|
val name: String,
|
||||||
|
val time: Int,
|
||||||
|
val type: Int,
|
||||||
|
val unit: String,
|
||||||
|
val value: Double
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.mapBounds
|
||||||
|
|
||||||
|
data class MapBoundsRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val bounds: List<Int>,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val limit: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.mapBounds
|
||||||
|
|
||||||
|
data class MapBoundsResponseEntity(
|
||||||
|
val devices: List<MapBoundsDeviceEntity>,
|
||||||
|
val webcams: List<MapBoundsWebcamEntity>
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.mapBounds
|
||||||
|
|
||||||
|
data class MapBoundsWebcamEntity(
|
||||||
|
val id: Int,
|
||||||
|
val image: String,
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double,
|
||||||
|
val name: String,
|
||||||
|
val time: Int
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.nameSensor
|
||||||
|
|
||||||
|
data class NameSensorRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.pubSensor
|
||||||
|
|
||||||
|
data class PubSensorRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val id: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.pubSensor
|
||||||
|
|
||||||
|
data class PubSensorResponseEntity(
|
||||||
|
val code: Int,
|
||||||
|
val id: Int
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sendCommand
|
||||||
|
|
||||||
|
data class SendCommandRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val command: String,
|
||||||
|
val id: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sendComplaint
|
||||||
|
|
||||||
|
data class SendComplaintRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val email: String,
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val problem: String,
|
||||||
|
val time: Int,
|
||||||
|
val uuid: String,
|
||||||
|
val value: Int
|
||||||
|
)
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sendMessage
|
||||||
|
|
||||||
|
data class SendMessageRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val email: String,
|
||||||
|
val mess: String,
|
||||||
|
val name: String,
|
||||||
|
val subj: String,
|
||||||
|
val uid: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsHistory
|
||||||
|
|
||||||
|
data class HistoryDataEntity(
|
||||||
|
val id: Int,
|
||||||
|
val time: Int,
|
||||||
|
val value: Double
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsHistory
|
||||||
|
|
||||||
|
data class HistorySensorEntity(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val type: Int,
|
||||||
|
val unit: String
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsHistory
|
||||||
|
|
||||||
|
data class SensorsHistoryRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val id: Int,
|
||||||
|
val offset: Int,
|
||||||
|
val period: String,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsHistory
|
||||||
|
|
||||||
|
data class SensorsHistoryResponseEntity(
|
||||||
|
val `data`: List<HistoryDataEntity>,
|
||||||
|
val sensors: List<HistorySensorEntity>
|
||||||
|
)
|
|
@ -0,0 +1,19 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsNearby
|
||||||
|
|
||||||
|
import ru.nm17.narodmon.appNarodMonApiClient.entities.SensorEntity
|
||||||
|
|
||||||
|
|
||||||
|
data class NearbyDeviceEntity(
|
||||||
|
val cmd: Int,
|
||||||
|
val distance: Double,
|
||||||
|
val id: Int,
|
||||||
|
val lat: Double,
|
||||||
|
val location: String,
|
||||||
|
val lon: Double,
|
||||||
|
val mac: String,
|
||||||
|
val my: Int,
|
||||||
|
val name: String,
|
||||||
|
val owner: String,
|
||||||
|
val sensors: List<SensorEntity>,
|
||||||
|
val time: Int
|
||||||
|
)
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsNearby
|
||||||
|
|
||||||
|
data class SensorsNearbyRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double,
|
||||||
|
val radius: Int,
|
||||||
|
val types: List<Int>,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,5 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsNearby
|
||||||
|
|
||||||
|
data class SensorsNearbyResponseEntity(
|
||||||
|
val devices: List<NearbyDeviceEntity>
|
||||||
|
)
|
|
@ -0,0 +1,19 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsOnDevice
|
||||||
|
|
||||||
|
import ru.nm17.narodmon.ui.entities.SensorEntity
|
||||||
|
|
||||||
|
data class SensorOnDeviceEntity(
|
||||||
|
val cmd: Int,
|
||||||
|
val distance: Double,
|
||||||
|
val id: Int,
|
||||||
|
val info: String,
|
||||||
|
val location: String,
|
||||||
|
val mac: String,
|
||||||
|
val my: Int,
|
||||||
|
val name: String,
|
||||||
|
val owner: String,
|
||||||
|
val photo: String,
|
||||||
|
val sensors: List<SensorEntity>,
|
||||||
|
val site: String,
|
||||||
|
val time: Int
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsOnDevice
|
||||||
|
|
||||||
|
data class SensorsOnDeviceRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val devices: List<Int>,
|
||||||
|
val lang: String,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,5 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsOnDevice
|
||||||
|
|
||||||
|
data class SensorsOnDeviceResponseEntity(
|
||||||
|
val devices: List<SensorOnDeviceEntity>
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsValues
|
||||||
|
|
||||||
|
data class SensorValueEntity(
|
||||||
|
val changed: Int,
|
||||||
|
val id: Int,
|
||||||
|
val time: Int,
|
||||||
|
val trend: Int,
|
||||||
|
val type: Int,
|
||||||
|
val value: Int
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsValues
|
||||||
|
|
||||||
|
data class SensorsValuesRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val sensors: List<Int>,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,5 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.sensorsValues
|
||||||
|
|
||||||
|
data class SensorsValuesResponseEntity(
|
||||||
|
val sensors: List<SensorValueEntity>
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userFavorites
|
||||||
|
|
||||||
|
data class FavoriteSensorEntity(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val time: Int,
|
||||||
|
val type: Int,
|
||||||
|
val value: Double
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userFavorites
|
||||||
|
|
||||||
|
data class FavoriteWebcamEntity(
|
||||||
|
val id: Int,
|
||||||
|
val image: String,
|
||||||
|
val name: String,
|
||||||
|
val time: Int
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userFavorites
|
||||||
|
|
||||||
|
data class UserFavoritesRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val sensors: List<Int>,
|
||||||
|
val uuid: String,
|
||||||
|
val webcams: List<Int>
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userFavorites
|
||||||
|
|
||||||
|
data class UserFavoritesResponseEntity(
|
||||||
|
val sensors: List<FavoriteSensorEntity>,
|
||||||
|
val webcams: List<FavoriteWebcamEntity>
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLocation
|
||||||
|
|
||||||
|
data class CellEntity(
|
||||||
|
val bssid: String,
|
||||||
|
val rssi: Int
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLocation
|
||||||
|
|
||||||
|
data class UserLocationByAddrRequestEntity(
|
||||||
|
val addr: String,
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLocation
|
||||||
|
|
||||||
|
data class UserLocationByCellRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cells: List<CellEntity>,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLocation
|
||||||
|
|
||||||
|
data class UserLocationByCoordRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLocation
|
||||||
|
|
||||||
|
data class UserLocationByWifiRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val uuid: String,
|
||||||
|
val wifi: List<WifiEntity>
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLocation
|
||||||
|
|
||||||
|
data class UserLocationResponseEntity(
|
||||||
|
val addr: String,
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLocation
|
||||||
|
|
||||||
|
data class WifiEntity(
|
||||||
|
val bssid: String,
|
||||||
|
val rssi: Int
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLogon
|
||||||
|
|
||||||
|
data class UserLogonRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val hash: String,
|
||||||
|
val lang: String,
|
||||||
|
val login: String,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLogon
|
||||||
|
|
||||||
|
data class UserLogonResponseEntity(
|
||||||
|
val login: String,
|
||||||
|
val tz: Int,
|
||||||
|
val uid: Int,
|
||||||
|
val vip: Int
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLogout
|
||||||
|
|
||||||
|
data class UserLogoutRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.userLogout
|
||||||
|
|
||||||
|
data class UserLogoutResponseEntity(
|
||||||
|
val login: String,
|
||||||
|
val uid: Int
|
||||||
|
)
|
|
@ -0,0 +1,14 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.weatherReport
|
||||||
|
|
||||||
|
data class WeatherReportRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val humid: String,
|
||||||
|
val lang: String,
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double,
|
||||||
|
val press: String,
|
||||||
|
val temp: String,
|
||||||
|
val uuid: String,
|
||||||
|
val wind: String
|
||||||
|
)
|
|
@ -0,0 +1,5 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.weatherReport
|
||||||
|
|
||||||
|
data class WeatherReportResponseEntity(
|
||||||
|
val result: String
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.webcamImages
|
||||||
|
|
||||||
|
data class WebcamImageEntity(
|
||||||
|
val image: String,
|
||||||
|
val time: Int
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.webcamImages
|
||||||
|
|
||||||
|
data class WebcamImagesRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val id: Int,
|
||||||
|
val limit: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.webcamImages
|
||||||
|
|
||||||
|
data class WebcamImagesResponseEntity(
|
||||||
|
val distance: Double,
|
||||||
|
val id: Int,
|
||||||
|
val images: List<WebcamImageEntity>,
|
||||||
|
val location: String,
|
||||||
|
val name: String
|
||||||
|
)
|
|
@ -0,0 +1,15 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.webcamsNearby
|
||||||
|
|
||||||
|
data class WebcamNearbyEntity(
|
||||||
|
val distance: Double,
|
||||||
|
val fav: Int,
|
||||||
|
val id: Int,
|
||||||
|
val image: String,
|
||||||
|
val lat: Double,
|
||||||
|
val location: String,
|
||||||
|
val lon: Double,
|
||||||
|
val my: Int,
|
||||||
|
val name: String,
|
||||||
|
val owner: String,
|
||||||
|
val time: Int
|
||||||
|
)
|
|
@ -0,0 +1,11 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.webcamsNearby
|
||||||
|
|
||||||
|
data class WebcamsNearbyRequestEntity(
|
||||||
|
val api_key: String,
|
||||||
|
val cmd: String,
|
||||||
|
val lang: String,
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double,
|
||||||
|
val radius: Int,
|
||||||
|
val uuid: String
|
||||||
|
)
|
|
@ -0,0 +1,5 @@
|
||||||
|
package ru.nm17.narodmon.appNarodMonApiClient.entities.webcamsNearby
|
||||||
|
|
||||||
|
data class WebcamsResponseEntity(
|
||||||
|
val webcams: List<WebcamNearbyEntity>
|
||||||
|
)
|
10
app/src/main/java/ru/nm17/narodmon/ui/Font.kt
Normal file
10
app/src/main/java/ru/nm17/narodmon/ui/Font.kt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.nm17.narodmon.ui
|
||||||
|
|
||||||
|
import androidx.compose.ui.text.font.Font
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import ru.nm17.narodmon.R
|
||||||
|
|
||||||
|
val iosevkaFamily = FontFamily(
|
||||||
|
Font(R.font.iosevka, FontWeight.Medium)
|
||||||
|
)
|
9
app/src/main/java/ru/nm17/narodmon/ui/Utils.kt
Normal file
9
app/src/main/java/ru/nm17/narodmon/ui/Utils.kt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.nm17.narodmon.ui
|
||||||
|
|
||||||
|
fun String.toChipTitle(): String {
|
||||||
|
return if (length >= 20) {
|
||||||
|
this.slice(0..16) + ".."
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,7 @@
|
||||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
||||||
package ru.nm17.narodmon.ui.elements
|
package ru.nm17.narodmon.ui.dialogs
|
||||||
|
|
||||||
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,12 +19,13 @@ 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 androidx.compose.ui.tooling.preview.Preview
|
||||||
import ru.nm17.narodmon.R
|
import ru.nm17.narodmon.R
|
||||||
|
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AgreementDialog(modifier: Modifier = Modifier, onClick: () -> Unit) {
|
fun AgreementDialog(modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
|
@ -40,7 +38,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 +54,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
|
||||||
|
@ -88,3 +86,13 @@ fun AgreementDialog(modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewAgreementDialog(){
|
||||||
|
NarodMonTheme {
|
||||||
|
AgreementDialog {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package ru.nm17.narodmon.ui.dialogs
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.heightIn
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.AlertDialogDefaults
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.nm17.narodmon.R
|
||||||
|
import ru.nm17.narodmon.ui.elements.FilterCheckbox
|
||||||
|
import ru.nm17.narodmon.ui.entities.SensorFilterUiEntity
|
||||||
|
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun FilterSensorsDialog(
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = {
|
||||||
|
onDismissRequest.invoke()
|
||||||
|
}) {
|
||||||
|
Surface(
|
||||||
|
shape = MaterialTheme.shapes.large,
|
||||||
|
tonalElevation = AlertDialogDefaults.TonalElevation
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(vertical = 16.dp)) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.sensors_filter_title),
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.heightIn(128.dp, 312.dp)
|
||||||
|
.padding(horizontal = 4.dp),
|
||||||
|
) {
|
||||||
|
items(filterItems) {
|
||||||
|
FilterCheckbox(
|
||||||
|
checked = it.enabled.value,
|
||||||
|
stringRes = it.stringRes,
|
||||||
|
) { it.enabled.value = !it.enabled.value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
TextButton(onClick = { onDismissRequest.invoke() }) {
|
||||||
|
Text(text = "Отмена")
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.padding(horizontal = 8.dp))
|
||||||
|
Button(onClick = { onApply.invoke(filterItems) }) {
|
||||||
|
Text(text = stringResource(id = R.string.apply))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewFilterSensorsDialog() {
|
||||||
|
NarodMonTheme {
|
||||||
|
FilterSensorsDialog({}) {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package ru.nm17.narodmon.ui.dialogs
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.AlertDialogDefaults
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
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.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.nm17.narodmon.R
|
||||||
|
import ru.nm17.narodmon.ui.elements.FilterRadioButton
|
||||||
|
import ru.nm17.narodmon.ui.entities.SensorSortingUiEntity
|
||||||
|
import ru.nm17.narodmon.ui.entities.SortingTypes
|
||||||
|
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun SortSensorsDialog(
|
||||||
|
selected: SensorSortingUiEntity,
|
||||||
|
sortingTypes: List<SensorSortingUiEntity>? = null,
|
||||||
|
onApply: (sortingType: SensorSortingUiEntity) -> Unit,
|
||||||
|
onDismissRequest: () -> Unit
|
||||||
|
) {
|
||||||
|
var selectedType by remember {
|
||||||
|
mutableStateOf(selected)
|
||||||
|
}
|
||||||
|
val sensorsSortingTypes = 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),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = {
|
||||||
|
onDismissRequest.invoke()
|
||||||
|
}) {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentWidth()
|
||||||
|
.wrapContentHeight(),
|
||||||
|
shape = MaterialTheme.shapes.large,
|
||||||
|
tonalElevation = AlertDialogDefaults.TonalElevation
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(vertical = 16.dp)) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.sensors_sort_title),
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 4.dp),
|
||||||
|
) {
|
||||||
|
items(sortingTypes ?: sensorsSortingTypes) {
|
||||||
|
FilterRadioButton(
|
||||||
|
selected = (selectedType == it),
|
||||||
|
onClick = { selectedType = it },
|
||||||
|
stringRes = it.stringRes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
TextButton(onClick = { onDismissRequest.invoke() }) {
|
||||||
|
Text(text = "Отмена")
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.padding(horizontal = 8.dp))
|
||||||
|
Button(onClick = { onApply.invoke(selectedType) }) {
|
||||||
|
Text(text = stringResource(id = R.string.apply))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SortSensorsPreview() {
|
||||||
|
NarodMonTheme {
|
||||||
|
SortSensorsDialog(
|
||||||
|
SensorSortingUiEntity(R.string.sort_by_distance, SortingTypes.DISTANCE),
|
||||||
|
onApply = {}) {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package ru.nm17.narodmon.ui.elements
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material3.Checkbox
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
||||||
|
@ExperimentalMaterial3Api
|
||||||
|
@Composable
|
||||||
|
fun FilterCheckbox(checked: Boolean, stringRes: Int, onCheckedChange: () -> Unit) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable { onCheckedChange() }
|
||||||
|
) {
|
||||||
|
Checkbox(
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = { onCheckedChange() },
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = stringRes),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package ru.nm17.narodmon.ui.elements
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.RadioButton
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
||||||
|
@ExperimentalMaterial3Api
|
||||||
|
@Composable
|
||||||
|
fun FilterRadioButton(selected: Boolean, onClick: () -> Unit, stringRes: Int) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable { onClick.invoke() }
|
||||||
|
) {
|
||||||
|
RadioButton(
|
||||||
|
selected = selected,
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
|
Text(text = stringResource(id = stringRes))
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,7 +47,7 @@ import kotlinx.coroutines.launch
|
||||||
@Composable
|
@Composable
|
||||||
fun GenericNavScaffold(title: @Composable () -> Unit, content: @Composable (PaddingValues) -> Unit) {
|
fun GenericNavScaffold(title: @Composable () -> Unit, content: @Composable (PaddingValues) -> Unit) {
|
||||||
val expanded = rememberDrawerState(initialValue = DrawerValue.Closed)
|
val expanded = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||||
val coScope = rememberCoroutineScope();
|
val coScope = rememberCoroutineScope()
|
||||||
val navController = rememberNavController() // TODO: Используй меня
|
val navController = rememberNavController() // TODO: Используй меня
|
||||||
|
|
||||||
LaunchedEffect(key1 = Unit) {
|
LaunchedEffect(key1 = Unit) {
|
||||||
|
@ -60,7 +60,7 @@ fun GenericNavScaffold(title: @Composable () -> Unit, content: @Composable (Padd
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
Icon(Icons.Default.AccountCircle, contentDescription = "")
|
Icon(Icons.Default.AccountCircle, contentDescription = "")
|
||||||
},
|
},
|
||||||
headlineText = { Text(text = "Гость", style = MaterialTheme.typography.titleLarge)},
|
headlineContent = { Text(text = "Гость", style = MaterialTheme.typography.titleLarge)},
|
||||||
modifier = Modifier.height(72.dp)
|
modifier = Modifier.height(72.dp)
|
||||||
)
|
)
|
||||||
Divider()
|
Divider()
|
||||||
|
@ -75,29 +75,27 @@ fun GenericNavScaffold(title: @Composable () -> Unit, content: @Composable (Padd
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = title,
|
title = title,
|
||||||
colors = TopAppBarDefaults.largeTopAppBarColors(
|
colors = TopAppBarDefaults.largeTopAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme.primaryContainer
|
containerColor = MaterialTheme.colorScheme.primaryContainer
|
||||||
),
|
),
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = { coScope.launch { expanded.open() } }) {
|
IconButton(onClick = { coScope.launch { expanded.open() } }) {
|
||||||
Icon(Icons.Filled.Menu, contentDescription = null)
|
Icon(Icons.Filled.Menu, contentDescription = null)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
|
||||||
},
|
|
||||||
floatingActionButtonPosition = FabPosition.End,
|
|
||||||
floatingActionButton = {
|
|
||||||
FloatingActionButton(onClick = {}) {
|
|
||||||
Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//drawerContent = { Text(text = "Drawer Menu 1") },
|
|
||||||
content = content,
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
floatingActionButtonPosition = FabPosition.End,
|
||||||
|
floatingActionButton = {
|
||||||
|
FloatingActionButton(onClick = {}) {
|
||||||
|
Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//drawerContent = { Text(text = "Drawer Menu 1") },
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
56
app/src/main/java/ru/nm17/narodmon/ui/elements/SensorItem.kt
Normal file
56
app/src/main/java/ru/nm17/narodmon/ui/elements/SensorItem.kt
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package ru.nm17.narodmon.ui.elements
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.ElevatedCard
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
|
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.ui.entities.SensorEntity
|
||||||
|
import ru.nm17.narodmon.ui.iosevkaFamily
|
||||||
|
|
||||||
|
@ExperimentalMaterial3Api
|
||||||
|
@Composable
|
||||||
|
fun SensorItem(sensorEntity: SensorEntity) {
|
||||||
|
ListItem(
|
||||||
|
overlineContent = { Text(text = "${sensorEntity.deviceName} от ${sensorEntity.deviceOwner}") },
|
||||||
|
headlineContent = { Text(text = sensorEntity.type.name) },
|
||||||
|
supportingContent = { Text(text = sensorEntity.name) },
|
||||||
|
trailingContent = {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.End,
|
||||||
|
) {
|
||||||
|
Text(text = "${sensorEntity.distance} km")
|
||||||
|
Spacer(modifier = Modifier.size(2.dp))
|
||||||
|
ElevatedCard(
|
||||||
|
shape = RectangleShape,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${sensorEntity.value} ${sensorEntity.unit}",
|
||||||
|
fontFamily = iosevkaFamily,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
modifier = Modifier.padding(horizontal = 3.dp, vertical = 1.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewSensorItem() {
|
||||||
|
// SensorItem(SensorEntity(0, Se))
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package ru.nm17.narodmon.ui.elements
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.nm17.narodmon.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Кнопка, которая нужна для настроек.
|
||||||
|
* @param titleId Id заголовка кнопки
|
||||||
|
* @param leadingItem Заполнить, когда нужно вставить Composable перед заголовком(например [Icon], [FilterCheckbox] или [Switch]
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun SettingsItem(
|
||||||
|
@StringRes titleId: Int,
|
||||||
|
leadingItem: @Composable (() -> Unit)? = null,
|
||||||
|
onClick: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
Row(modifier = Modifier.padding(16.dp)) {
|
||||||
|
if (leadingItem != null) {
|
||||||
|
leadingItem.invoke()
|
||||||
|
Spacer(modifier = Modifier.size(16.dp))
|
||||||
|
}
|
||||||
|
Column(modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable { onClick.invoke() }) {
|
||||||
|
Text(text = stringResource(id = titleId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun PreviewSettingsItem() {
|
||||||
|
SettingsItem(R.string.about_app) {}
|
||||||
|
}
|
61
app/src/main/java/ru/nm17/narodmon/ui/elements/TileMap.kt
Normal file
61
app/src/main/java/ru/nm17/narodmon/ui/elements/TileMap.kt
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package ru.nm17.narodmon.ui.elements
|
||||||
|
|
||||||
|
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.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.engine.okhttp.OkHttp
|
||||||
|
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.api.onTouchDown
|
||||||
|
import ovh.plrapps.mapcompose.api.scale
|
||||||
|
import ovh.plrapps.mapcompose.api.setScroll
|
||||||
|
import ovh.plrapps.mapcompose.core.TileStreamProvider
|
||||||
|
import ovh.plrapps.mapcompose.ui.MapUI
|
||||||
|
import ovh.plrapps.mapcompose.ui.state.MapState
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
const val mapSize = 32768
|
||||||
|
|
||||||
|
val client = HttpClient(OkHttp)
|
||||||
|
val tileStreamProvider = TileStreamProvider { row, col, zoom ->
|
||||||
|
requestTile(row, col, zoom)
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TileMap(modifier: Modifier = Modifier, onTap: () -> Unit) {
|
||||||
|
val state by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
MapState(
|
||||||
|
levelCount = 8,
|
||||||
|
fullWidth = mapSize,
|
||||||
|
fullHeight = mapSize,
|
||||||
|
workerCount = 16,
|
||||||
|
).apply {
|
||||||
|
addLayer(tileStreamProvider)
|
||||||
|
onTouchDown {
|
||||||
|
onTap.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
// TODO: Подгружать сохранённую позицию
|
||||||
|
state.setScroll(Offset(28702.6F, 14787.6F))
|
||||||
|
state.scale = 1.4658884F
|
||||||
|
}
|
||||||
|
|
||||||
|
MapUI(modifier = modifier, state = state)
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
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,
|
||||||
|
)
|
|
@ -0,0 +1,11 @@
|
||||||
|
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),
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nm17.narodmon.ui.entities
|
||||||
|
|
||||||
|
|
||||||
|
data class SensorSortingUiEntity(
|
||||||
|
val stringRes: Int,
|
||||||
|
val sortingType: SortingTypes,
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
package ru.nm17.narodmon.ui.entities
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ru.nm17.narodmon.ui.entities
|
||||||
|
|
||||||
|
enum class SortingTypes {
|
||||||
|
DISTANCE,
|
||||||
|
DISTANCE_DESC,
|
||||||
|
TYPE,
|
||||||
|
TYPE_DESC,
|
||||||
|
UPD_TIME,
|
||||||
|
NAME,
|
||||||
|
NAME_DESC,
|
||||||
|
VALUE,
|
||||||
|
VALUE_DESC
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package ru.nm17.narodmon.ui.messagesScreen
|
||||||
|
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MessagesScreen() {
|
||||||
|
Text(text = "todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewMessagesScreen() {
|
||||||
|
MessagesScreen()
|
||||||
|
}
|
30
app/src/main/java/ru/nm17/narodmon/ui/navHost/AppNavHost.kt
Normal file
30
app/src/main/java/ru/nm17/narodmon/ui/navHost/AppNavHost.kt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package ru.nm17.narodmon.ui.navHost
|
||||||
|
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import ru.nm17.narodmon.ui.settings.SettingsNavigation
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun AppNavHost() {
|
||||||
|
val navController = rememberNavController()
|
||||||
|
NavHost(navController = navController, startDestination = "main") {
|
||||||
|
composable("main") {
|
||||||
|
MainScreen(navController)
|
||||||
|
}
|
||||||
|
composable("settings") {
|
||||||
|
SettingsNavigation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewAppNavHost() {
|
||||||
|
AppNavHost()
|
||||||
|
}
|
83
app/src/main/java/ru/nm17/narodmon/ui/navHost/MainScreen.kt
Normal file
83
app/src/main/java/ru/nm17/narodmon/ui/navHost/MainScreen.kt
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package ru.nm17.narodmon.ui.navHost
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.NavigationBar
|
||||||
|
import androidx.compose.material3.NavigationBarItem
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.NavGraph.Companion.findStartDestination
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import ru.nm17.narodmon.ui.sensorsScreen.SensorsScreen
|
||||||
|
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
||||||
|
import ru.nm17.narodmon.ui.webCamsScreen.WebCamsScreen
|
||||||
|
|
||||||
|
|
||||||
|
val items = listOf(
|
||||||
|
MainScreenSealed.Sensors,
|
||||||
|
MainScreenSealed.Webcams,
|
||||||
|
MainScreenSealed.Messages
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MainScreen(outerNavController: NavController) {
|
||||||
|
val navController = rememberNavController()
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
bottomBar = {
|
||||||
|
NavigationBar {
|
||||||
|
|
||||||
|
items.forEach { screen ->
|
||||||
|
NavigationBarItem(
|
||||||
|
selected = navController.currentDestination?.route == screen.route,
|
||||||
|
onClick = {
|
||||||
|
navController.navigate(screen.route) {
|
||||||
|
popUpTo(navController.graph.findStartDestination().id) {
|
||||||
|
saveState = true
|
||||||
|
}
|
||||||
|
launchSingleTop = true
|
||||||
|
restoreState = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label = { Text(text = stringResource(id = screen.resourceId)) },
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = screen.iconId),
|
||||||
|
contentDescription = ""
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
NavHost(
|
||||||
|
navController,
|
||||||
|
startDestination = MainScreenSealed.Sensors.route,
|
||||||
|
Modifier.padding(it)
|
||||||
|
) {
|
||||||
|
composable(MainScreenSealed.Sensors.route) {
|
||||||
|
SensorsScreen(outerNavController)
|
||||||
|
}
|
||||||
|
composable(MainScreenSealed.Webcams.route) { WebCamsScreen(navController) }
|
||||||
|
composable(MainScreenSealed.Messages.route) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewMainScreen() {
|
||||||
|
NarodMonTheme {
|
||||||
|
MainScreen(rememberNavController())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ru.nm17.narodmon.ui.navHost
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import ru.nm17.narodmon.R
|
||||||
|
|
||||||
|
sealed class MainScreenSealed(
|
||||||
|
val route: String,
|
||||||
|
@StringRes val resourceId: Int,
|
||||||
|
@DrawableRes val iconId: Int
|
||||||
|
) {
|
||||||
|
object Sensors : MainScreenSealed("sensors", R.string.sensors_page_title, R.drawable.ic_home)
|
||||||
|
object Webcams : MainScreenSealed("webcams", R.string.webcams, R.drawable.ic_webcam)
|
||||||
|
|
||||||
|
object Messages : MainScreenSealed("messages", R.string.messages, R.drawable.ic_message)
|
||||||
|
|
||||||
|
object Settings : MainScreenSealed("settings", R.string.settings, R.drawable.ic_settings)
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
package ru.nm17.narodmon.ui.pages
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material3.Divider
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.ModalDrawerSheet
|
|
||||||
import androidx.compose.material3.NavigationDrawerItem
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import ru.nm17.narodmon.Greeting
|
|
||||||
import ru.nm17.narodmon.R
|
|
||||||
import ru.nm17.narodmon.ui.elements.GenericNavScaffold
|
|
||||||
|
|
||||||
@ExperimentalMaterial3Api
|
|
||||||
@Composable
|
|
||||||
fun SensorsPage(navController: NavController) {
|
|
||||||
GenericNavScaffold(
|
|
||||||
title = { Text(text = stringResource(R.string.sensors_page_title))}
|
|
||||||
) {
|
|
||||||
Greeting(name = "world", modifier = Modifier.padding(it))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
package ru.nm17.narodmon.ui.sensorsScreen
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
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.LazyRow
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Settings
|
||||||
|
import androidx.compose.material.icons.rounded.Check
|
||||||
|
import androidx.compose.material3.BottomSheetScaffold
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.FilterChip
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.SearchBar
|
||||||
|
import androidx.compose.material3.SearchBarDefaults
|
||||||
|
import androidx.compose.material3.SheetValue
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
||||||
|
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.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import ru.nm17.narodmon.R
|
||||||
|
import ru.nm17.narodmon.db.entities.SensorType
|
||||||
|
import ru.nm17.narodmon.ui.dialogs.FilterSensorsDialog
|
||||||
|
import ru.nm17.narodmon.ui.dialogs.SortSensorsDialog
|
||||||
|
import ru.nm17.narodmon.ui.elements.SensorItem
|
||||||
|
import ru.nm17.narodmon.ui.elements.TileMap
|
||||||
|
import ru.nm17.narodmon.ui.entities.SensorEntity
|
||||||
|
import ru.nm17.narodmon.ui.entities.SensorSortingUiEntity
|
||||||
|
import ru.nm17.narodmon.ui.entities.SortingTypes
|
||||||
|
import ru.nm17.narodmon.ui.navHost.MainScreenSealed
|
||||||
|
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
||||||
|
import ru.nm17.narodmon.ui.toChipTitle
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun SensorsScreen(outerNavController: NavController) {
|
||||||
|
|
||||||
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
|
var searchActive by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val scaffoldState = rememberBottomSheetScaffoldState()
|
||||||
|
val sensorEntities = remember {
|
||||||
|
mutableListOf(
|
||||||
|
// TODO: загружать датчики с сервера. Этот список -- для макета
|
||||||
|
SensorEntity(
|
||||||
|
0,
|
||||||
|
SensorType(0, "temp", "C"),
|
||||||
|
"device0", 0,
|
||||||
|
"sensor0", favorite = true,
|
||||||
|
public = true, mine = false,
|
||||||
|
"Москва", 0.4,
|
||||||
|
20.0, "C", 1686142800,
|
||||||
|
),
|
||||||
|
SensorEntity(
|
||||||
|
1,
|
||||||
|
SensorType(4, "humidity", "%"),
|
||||||
|
"device1", 0,
|
||||||
|
"sensor1", favorite = true,
|
||||||
|
public = false, mine = false,
|
||||||
|
"Подмосковье", 1.1,
|
||||||
|
39.0, "%", 1686142800,
|
||||||
|
),
|
||||||
|
SensorEntity(
|
||||||
|
2,
|
||||||
|
SensorType(11, "wind speed", "m/s"),
|
||||||
|
"device2", 1,
|
||||||
|
"sensor2", favorite = false,
|
||||||
|
public = true, mine = true,
|
||||||
|
"Москва", 0.01,
|
||||||
|
3.2, "m/s", 1686142800,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterShow by remember { mutableStateOf(false) }
|
||||||
|
var filterMine by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
var sortingShow by remember { mutableStateOf(false) }
|
||||||
|
var sortingType by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
SensorSortingUiEntity(R.string.sort_by_distance, SortingTypes.DISTANCE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var sheetHeight by remember {
|
||||||
|
mutableStateOf(SheetHeight.ExtraExpanded)
|
||||||
|
}
|
||||||
|
|
||||||
|
BottomSheetScaffold(modifier = Modifier.fillMaxSize(), sheetPeekHeight = when (sheetHeight) {
|
||||||
|
SheetHeight.ExtraExpanded -> 256.dp
|
||||||
|
SheetHeight.Expanded -> 128.dp
|
||||||
|
SheetHeight.Hidden -> 0.dp
|
||||||
|
}, scaffoldState = scaffoldState, sheetContent = {
|
||||||
|
AnimatedVisibility(visible = scaffoldState.bottomSheetState.currentValue == SheetValue.Expanded) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = searchQuery,
|
||||||
|
onValueChange = { searchQuery = it },
|
||||||
|
placeholder = { Text(stringResource(R.string.search)) },
|
||||||
|
shape = SearchBarDefaults.inputFieldShape,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyRow(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
FilterChip(
|
||||||
|
selected = false,
|
||||||
|
onClick = { filterShow = true },
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_filter),
|
||||||
|
contentDescription = stringResource(id = R.string.sensors_filter)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
// Icon(
|
||||||
|
// Icons.Filled.ArrowDropDown,
|
||||||
|
// "",
|
||||||
|
// tint = MaterialTheme.colorScheme.onBackground
|
||||||
|
// )
|
||||||
|
},
|
||||||
|
|
||||||
|
label = { Text(text = stringResource(R.string.sensors_filter)) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
FilterChip(selected = sortingType.sortingType != SortingTypes.DISTANCE,
|
||||||
|
onClick = { sortingShow = true },
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_sort),
|
||||||
|
contentDescription = stringResource(id = R.string.sensors_sorting)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
// Icon(
|
||||||
|
// Icons.Filled.ArrowDropDown,
|
||||||
|
// "",
|
||||||
|
// tint = MaterialTheme.colorScheme.onBackground
|
||||||
|
// )
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
if (sortingType.sortingType == SortingTypes.DISTANCE) R.string.sensors_sorting
|
||||||
|
else sortingType.stringRes
|
||||||
|
).toChipTitle(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
FilterChip(
|
||||||
|
selected = filterMine,
|
||||||
|
onClick = { filterMine = !filterMine },
|
||||||
|
leadingIcon = {
|
||||||
|
if (filterMine) {
|
||||||
|
Icon(
|
||||||
|
Icons.Rounded.Check, contentDescription = ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label = { Text(text = stringResource(R.string.sensors_mine)) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxHeight(),
|
||||||
|
) {
|
||||||
|
items(sensorEntities) { sensor ->
|
||||||
|
SensorItem(sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
SearchBar(
|
||||||
|
query = searchQuery,
|
||||||
|
active = searchActive,
|
||||||
|
onActiveChange = { active ->
|
||||||
|
searchActive = active
|
||||||
|
sheetHeight = if (active) SheetHeight.Hidden else SheetHeight.ExtraExpanded
|
||||||
|
},
|
||||||
|
onQueryChange = { query -> searchQuery = query },
|
||||||
|
onSearch = { searchActive = false },
|
||||||
|
placeholder = { Text(stringResource(R.string.search_sensors)) },
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(onClick = { outerNavController.navigate(MainScreenSealed.Settings.route) }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Settings,
|
||||||
|
contentDescription = stringResource(R.string.settings)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(
|
||||||
|
horizontal = if (!searchActive) 8.dp else 0.dp,
|
||||||
|
)
|
||||||
|
) {}
|
||||||
|
|
||||||
|
TileMap(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
sheetHeight =
|
||||||
|
SheetHeight.Expanded // TODO придумать, чтобы менялось на SheetHeight.ExtraExpanded после взаимодействия с картой
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sortingShow) {
|
||||||
|
SortSensorsDialog(sortingType, onApply = {
|
||||||
|
sortingType = it
|
||||||
|
sortingShow = false
|
||||||
|
}, onDismissRequest = {
|
||||||
|
sortingShow = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (filterShow) {
|
||||||
|
FilterSensorsDialog(onApply = {
|
||||||
|
// TODO применение фильтров
|
||||||
|
filterShow = false
|
||||||
|
}, onDismissRequest = { filterShow = false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewNewSensors() {
|
||||||
|
NarodMonTheme {
|
||||||
|
SensorsScreen(rememberNavController())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nm17.narodmon.ui.sensorsScreen
|
||||||
|
|
||||||
|
enum class SheetHeight {
|
||||||
|
ExtraExpanded,
|
||||||
|
Expanded,
|
||||||
|
Hidden
|
||||||
|
}
|
12
app/src/main/java/ru/nm17/narodmon/ui/settings/Settings.kt
Normal file
12
app/src/main/java/ru/nm17/narodmon/ui/settings/Settings.kt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package ru.nm17.narodmon.ui.settings
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import ru.nm17.narodmon.R
|
||||||
|
|
||||||
|
sealed class Settings(val route: String, @StringRes val resourceId: Int) {
|
||||||
|
|
||||||
|
object Main : Settings("settings_main", R.string.settings)
|
||||||
|
object AboutApp : Settings("settings_about_app", R.string.about_app)
|
||||||
|
|
||||||
|
object Debug : Settings("settings_debug_menu", R.string.debug_menu)
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package ru.nm17.narodmon.ui.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun SettingsNavigation() {
|
||||||
|
val navController = rememberNavController()
|
||||||
|
Scaffold(topBar = {
|
||||||
|
TopAppBar(title = { Text(text = navController.currentDestination?.route ?: "") })
|
||||||
|
}) {
|
||||||
|
NavHost(
|
||||||
|
navController = navController,
|
||||||
|
startDestination = Settings.Main.route,
|
||||||
|
modifier = Modifier.padding(it)
|
||||||
|
) {
|
||||||
|
composable(Settings.Main.route) { SettingsScreen(navController) }
|
||||||
|
composable(Settings.AboutApp.route) { }
|
||||||
|
composable(Settings.Debug.route) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewSettingsNavigation() {
|
||||||
|
SettingsNavigation()
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package ru.nm17.narodmon.ui.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import ru.nm17.narodmon.R
|
||||||
|
import ru.nm17.narodmon.ui.elements.SettingsItem
|
||||||
|
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsScreen(navController: NavController) {
|
||||||
|
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||||
|
item {
|
||||||
|
SettingsItem(titleId = R.string.debug_menu) {
|
||||||
|
navController.navigate(Settings.Debug.route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
SettingsItem(R.string.about_app) {
|
||||||
|
navController.navigate(Settings.AboutApp.route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true, showSystemUi = false)
|
||||||
|
@Composable
|
||||||
|
fun PreviewSettingsScreen() {
|
||||||
|
NarodMonTheme {
|
||||||
|
SettingsScreen(rememberNavController())
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,15 +10,16 @@ import androidx.compose.material3.dynamicLightColorScheme
|
||||||
import androidx.compose.material3.lightColorScheme
|
import androidx.compose.material3.lightColorScheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
|
|
||||||
private val DarkColorScheme = darkColorScheme(
|
private val DarkColorScheme = darkColorScheme(
|
||||||
primary = Purple80,
|
primary = Purple80,
|
||||||
secondary = PurpleGrey80,
|
secondary = PurpleGrey80,
|
||||||
tertiary = Pink80
|
tertiary = Pink80
|
||||||
)
|
)
|
||||||
|
|
||||||
private val LightColorScheme = lightColorScheme(
|
private val LightColorScheme = lightColorScheme(
|
||||||
|
@ -26,23 +27,23 @@ private val LightColorScheme = lightColorScheme(
|
||||||
secondary = PurpleGrey80,
|
secondary = PurpleGrey80,
|
||||||
tertiary = Pink80
|
tertiary = Pink80
|
||||||
|
|
||||||
/* Other default colors to override
|
/* Other default colors to override
|
||||||
background = Color(0xFFFFFBFE),
|
background = Color(0xFFFFFBFE),
|
||||||
surface = Color(0xFFFFFBFE),
|
surface = Color(0xFFFFFBFE),
|
||||||
onPrimary = Color.White,
|
onPrimary = Color.White,
|
||||||
onSecondary = Color.White,
|
onSecondary = Color.White,
|
||||||
onTertiary = Color.White,
|
onTertiary = Color.White,
|
||||||
onBackground = Color(0xFF1C1B1F),
|
onBackground = Color(0xFF1C1B1F),
|
||||||
onSurface = Color(0xFF1C1B1F),
|
onSurface = Color(0xFF1C1B1F),
|
||||||
*/
|
*/
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NarodMonTheme(
|
fun NarodMonTheme(
|
||||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
// Dynamic color is available on Android 12+
|
// Dynamic color is available on Android 12+
|
||||||
dynamicColor: Boolean = true,
|
dynamicColor: Boolean = true,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
val colorScheme = when {
|
val colorScheme = when {
|
||||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||||
|
@ -57,14 +58,16 @@ fun NarodMonTheme(
|
||||||
if (!view.isInEditMode) {
|
if (!view.isInEditMode) {
|
||||||
SideEffect {
|
SideEffect {
|
||||||
val window = (view.context as Activity).window
|
val window = (view.context as Activity).window
|
||||||
window.statusBarColor = colorScheme.primary.toArgb()
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
window.statusBarColor = Color.Transparent.toArgb()
|
||||||
|
|
||||||
|
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialTheme(
|
MaterialTheme(
|
||||||
colorScheme = colorScheme,
|
colorScheme = colorScheme,
|
||||||
typography = Typography,
|
typography = Typography,
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package ru.nm17.narodmon.ui.webCamsScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
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.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
|
||||||
|
import com.bumptech.glide.integration.compose.GlideImage
|
||||||
|
import ru.nm17.narodmon.ui.iosevkaFamily
|
||||||
|
|
||||||
|
@OptIn(ExperimentalGlideComposeApi::class)
|
||||||
|
@Composable
|
||||||
|
fun WebCamItem(webCamEntity: WebCamUiEntity) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
|
contentAlignment = Alignment.BottomStart
|
||||||
|
) {
|
||||||
|
GlideImage(
|
||||||
|
model = webCamEntity.imageUrl,
|
||||||
|
contentDescription = webCamEntity.name,
|
||||||
|
contentScale = ContentScale.FillHeight,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.height(240.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(
|
||||||
|
RoundedCornerShape(bottomEnd = 8.dp, bottomStart = 8.dp)
|
||||||
|
)
|
||||||
|
.background(Color(0f, 0f, 0f, 0.55f))
|
||||||
|
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp, top = 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = webCamEntity.time,
|
||||||
|
color = Color.White,
|
||||||
|
fontFamily = iosevkaFamily
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = webCamEntity.name,
|
||||||
|
color = Color.White,
|
||||||
|
maxLines = 1,
|
||||||
|
fontFamily = iosevkaFamily
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = "${webCamEntity.distance} км",
|
||||||
|
color = Color.White,
|
||||||
|
fontFamily = iosevkaFamily,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textAlign = TextAlign.End
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ru.nm17.narodmon.ui.webCamsScreen
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
|
||||||
|
data class WebCamUiEntity(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val distance: Int,
|
||||||
|
val location: String,
|
||||||
|
val time: String,
|
||||||
|
val imageUrl: String
|
||||||
|
)
|
|
@ -0,0 +1,62 @@
|
||||||
|
package ru.nm17.narodmon.ui.webCamsScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
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.tooling.preview.Preview
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import ru.nm17.narodmon.ui.theme.NarodMonTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun WebCamsScreen(navController: NavController) {
|
||||||
|
|
||||||
|
var webCams by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
listOf(
|
||||||
|
WebCamUiEntity(
|
||||||
|
1,
|
||||||
|
"Крутая камера",
|
||||||
|
1,
|
||||||
|
"Улица Пушкина, дом Калатушкина, кватира под номером 5",
|
||||||
|
"12:45",
|
||||||
|
"https://images-webcams.windy.com/51/1559159251/current/preview/1559159251.jpg?1686320054"
|
||||||
|
),
|
||||||
|
WebCamUiEntity(
|
||||||
|
2,
|
||||||
|
"Крутая камера 2",
|
||||||
|
2,
|
||||||
|
"Улица Пушкина, дом Калатушкина, кватира под номером 5",
|
||||||
|
"12:45",
|
||||||
|
"https://images-webcams.windy.com/51/1559159251/current/preview/1559159251.jpg?1686320054"
|
||||||
|
),
|
||||||
|
WebCamUiEntity(
|
||||||
|
3,
|
||||||
|
"Крутая камера 3",
|
||||||
|
3,
|
||||||
|
"Улица Пушкина, дом Калатушкина, кватира под номером 5",
|
||||||
|
"12:45",
|
||||||
|
"https://images-webcams.windy.com/51/1559159251/current/preview/1559159251.jpg?1686320054"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} // TODO источник камер
|
||||||
|
|
||||||
|
LazyColumn() {
|
||||||
|
items(webCams) {
|
||||||
|
WebCamItem(webCamEntity = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewWebCams() {
|
||||||
|
NarodMonTheme {
|
||||||
|
WebCamsScreen(rememberNavController())
|
||||||
|
}
|
||||||
|
}
|
5
app/src/main/res/drawable/ic_filter.xml
Normal file
5
app/src/main/res/drawable/ic_filter.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<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>
|
5
app/src/main/res/drawable/ic_home.xml
Normal file
5
app/src/main/res/drawable/ic_home.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<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="M12,5.69l5,4.5V18h-2v-6H9v6H7v-7.81l5,-4.5M12,3L2,12h3v8h6v-6h2v6h6v-8h3L12,3z"/>
|
||||||
|
</vector>
|
5
app/src/main/res/drawable/ic_message.xml
Normal file
5
app/src/main/res/drawable/ic_message.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<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="M4,4h16v12L5.17,16L4,17.17L4,4m0,-2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2L4,2zM6,12h12v2L6,14v-2zM6,9h12v2L6,11L6,9zM6,6h12v2L6,8L6,6z"/>
|
||||||
|
</vector>
|
5
app/src/main/res/drawable/ic_settings.xml
Normal file
5
app/src/main/res/drawable/ic_settings.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<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="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
|
||||||
|
</vector>
|
5
app/src/main/res/drawable/ic_sort.xml
Normal file
5
app/src/main/res/drawable/ic_sort.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<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>
|
5
app/src/main/res/drawable/ic_webcam.xml
Normal file
5
app/src/main/res/drawable/ic_webcam.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<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="M15,8v8H5V8h10m1,-2H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4V7c0,-0.55 -0.45,-1 -1,-1z"/>
|
||||||
|
</vector>
|
BIN
app/src/main/res/font/iosevka.ttf
Normal file
BIN
app/src/main/res/font/iosevka.ttf
Normal file
Binary file not shown.
|
@ -1,14 +0,0 @@
|
||||||
<?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,7 +1,6 @@
|
||||||
<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">
|
||||||
|
@ -15,4 +14,48 @@
|
||||||
<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="search">Поиск</string>
|
||||||
|
<string name="sensors_filter">Тип датчиков</string>
|
||||||
|
<string name="sensors_sorting">Сортировка</string>
|
||||||
|
<string name="sensors_mine">Мои датчики</string>
|
||||||
|
<string name="filter_temp_dew_point">Температура точки росы</string>
|
||||||
|
<string name="filter_temp">Температура воздуха</string>
|
||||||
|
<string name="filter_temp_water">Температура воды</string>
|
||||||
|
<string name="filter_temp_ground">Температура почвы</string>
|
||||||
|
<string name="filter_humidity">Влажность</string>
|
||||||
|
<string name="filter_pressure">Давление</string>
|
||||||
|
<string name="filter_lightness">Освещённость</string>
|
||||||
|
<string name="filter_uv">УФ-индекс</string>
|
||||||
|
<string name="filter_radiation">Радиация</string>
|
||||||
|
<string name="filter_rainfall">Осадки</string>
|
||||||
|
<string name="filter_dust">Запылённость</string>
|
||||||
|
<string name="filter_wind_speed">Скорость ветра</string>
|
||||||
|
<string name="filter_wind_direction">Направление ветра</string>
|
||||||
|
<string name="filter_concentration">Концентрация</string>
|
||||||
|
<string name="filter_power">Мощность</string>
|
||||||
|
<string name="filter_voltage">Напряжение</string>
|
||||||
|
<string name="filter_amperage">Сила тока</string>
|
||||||
|
<string name="filter_energy">Энергия</string>
|
||||||
|
<string name="filter_battery">% батареи</string>
|
||||||
|
<string name="filter_rxtx">Rx/Tx трафик</string>
|
||||||
|
<string name="filter_signal">Сигнал в dBm</string>
|
||||||
|
<string name="filter_water_meter">Счётчик воды</string>
|
||||||
|
<string name="filter_time">Время работы</string>
|
||||||
|
<string name="sensors_filter_title">Тип датчиков</string>
|
||||||
|
<string name="sort_by_distance">От ближних к дальним</string>
|
||||||
|
<string name="sort_by_type">По типу (от А до Я)</string>
|
||||||
|
<string name="sort_by_type_desc">По типу (от Я до А)</string>
|
||||||
|
<string name="sort_by_name">По названию (от А до Я)</string>
|
||||||
|
<string name="sort_by_name_desc">По названию (от Я до А)</string>
|
||||||
|
<string name="sensors_sort_title">Сортировка датчиков</string>
|
||||||
|
<string name="sort_update_time">По времени обновления</string>
|
||||||
|
<string name="apply">Применить</string>
|
||||||
|
<string name="sort_by_distance_desc">От дальних к ближним</string>
|
||||||
|
<string name="cancel1">Отменить</string>
|
||||||
|
<string name="webcams">Веб-камеры</string>
|
||||||
|
<string name="messages">Сообщения</string>
|
||||||
|
<string name="settings">Настройки</string>
|
||||||
|
<string name="search_sensors">Поиск датчиков</string>
|
||||||
|
<string name="about_app">О приложении</string>
|
||||||
|
<string name="debug_menu">Debug-меню</string>
|
||||||
</resources>
|
</resources>
|
|
@ -1,5 +1,5 @@
|
||||||
[versions]
|
[versions]
|
||||||
agp = "8.2.0-alpha06"
|
agp = "8.2.0-alpha07"
|
||||||
kotlin = "1.8.10"
|
kotlin = "1.8.10"
|
||||||
core-ktx = "1.9.0"
|
core-ktx = "1.9.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
|
|
Loading…
Add table
Reference in a new issue