Фикс #10 #15

Merged
nm17 merged 13 commits from issue-#10 into master 2023-06-22 11:18:11 +03:00
18 changed files with 467 additions and 253 deletions

View file

@ -74,63 +74,44 @@ dependencies {
debugImplementation(libs.ui.tooling)
debugImplementation(libs.ui.test.manifest)
//-- Navigation
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-ui-ktx:$nav_version")
// Feature module Support
implementation("androidx.navigation:navigation-dynamic-features-fragment:$nav_version")
// Testing Navigation
androidTestImplementation("androidx.navigation:navigation-testing:$nav_version")
// Jetpack Compose Integration
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)
//kapt("androidx.room:room-compiler:$room_version")
// To use Kotlin Symbol Processing (KSP)
val room_version = "2.5.1"
ksp("androidx.room:room-compiler:$room_version")
// optional - Kotlin Extensions and Coroutines support for Room
annotationProcessor("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-runtime:$room_version")
implementation("androidx.room:room-ktx:$room_version")
// optional - Guava support for Room, including Optional and ListenableFuture
implementation("androidx.room:room-guava:$room_version")
// optional - Test helpers
testImplementation("androidx.room:room-testing:$room_version")
// optional - Paging 3 Integration
implementation("androidx.room:room-paging:$room_version")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
// Ktor
//-- 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("dev.forkhandles:result4k")
implementation("io.ktor:ktor-client-core:2.3.1")
implementation("io.ktor:ktor-client-okhttp:2.3.1")
implementation("androidx.security:security-crypto-ktx:1.1.0-alpha06")
// For Identity Credential APIs
implementation("androidx.security:security-identity-credential:1.0.0-alpha03")
@ -143,10 +124,14 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
// Map Compose library
//-- Map Compose library
implementation("ovh.plrapps:mapcompose:2.7.1")
// Glide
implementation ("com.github.bumptech.glide:glide:4.14.2")
//-- Glide
implementation("com.github.bumptech.glide:glide:4.14.2")
implementation("com.github.bumptech.glide:compose:1.0.0-alpha.1")
}
}

View file

@ -1,27 +1,16 @@
@file:OptIn(
ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class,
ExperimentalMaterial3Api::class
)
package ru.nm17.narodmon
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.Menu
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -33,64 +22,17 @@ import androidx.compose.runtime.rememberCoroutineScope
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.unit.dp
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.room.Room
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKeys
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import ru.nm17.narodmon.db.AppDatabase
import ru.nm17.narodmon.db.entities.KVSetting
import ru.nm17.narodmon.ui.dialogs.AgreementDialog
import ru.nm17.narodmon.ui.sensorsScreen.SensorsScreen
import ru.nm17.narodmon.ui.navHost.AppNavHost
import ru.nm17.narodmon.ui.theme.NarodMonTheme
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppNavHost() {
val navController = rememberNavController()
val coScope = rememberCoroutineScope()
NavHost(navController = navController, startDestination = "sensors") {
composable("agreement") {
}
composable("sensors") {
Scaffold(bottomBar = {
BottomAppBar(actions = {
Image(
Icons.Rounded.Menu,
contentDescription = null
)
}, floatingActionButton = {
FloatingActionButton(onClick = { /*TODO*/ }) {
Image(
Icons.Rounded.Add,
contentDescription = ""
)
}
},
contentPadding = PaddingValues(start = 16.dp)
)
}) {
Column(modifier = Modifier.padding(it)) {
SensorsScreen(navController)
}
}
}
}
/*...*/
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -153,11 +95,7 @@ class MainActivity : ComponentActivity() {
}
} else {
AppNavHost()
}
// A surface container using the 'background' color from the theme
}
}
}

View file

@ -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) {}
}

View file

@ -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()
}

View 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()
}

View 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())
}
}

View file

@ -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(
DarkCat09 marked this conversation as resolved
Review

Интересное решение

Интересное решение
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)
}

View file

@ -1,8 +1,6 @@
package ru.nm17.narodmon.ui.sensorsScreen
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
@ -13,29 +11,23 @@ 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.filled.ArrowDropDown
import androidx.compose.material.icons.rounded.ArrowDropDown
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.rounded.Check
import androidx.compose.material.icons.rounded.Person
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
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.TextField
import androidx.compose.material3.TextFieldColors
import androidx.compose.material3.TextFieldDefaults
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.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -45,28 +37,23 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import ovh.plrapps.mapcompose.core.debounce
import ru.nm17.narodmon.R
import ru.nm17.narodmon.db.entities.SensorType
import ru.nm17.narodmon.ui.dialogs.FilterSensorsDialog
import ru.nm17.narodmon.ui.elements.SensorItem
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, ExperimentalAnimationApi::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SensorsScreen(navController: NavController) {
val coroutineScope = rememberCoroutineScope()
fun SensorsScreen(outerNavController: NavController) {
var searchQuery by remember { mutableStateOf("") }
var searchActive by remember { mutableStateOf(false) }
@ -119,108 +106,100 @@ fun SensorsScreen(navController: NavController) {
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),
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 = 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
// )
},
.padding(horizontal = 8.dp, vertical = 8.dp)
)
}
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 = {
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(
if (sortingType.sortingType == SortingTypes.DISTANCE) R.string.sensors_sorting
else sortingType.stringRes
).toChipTitle(),
},
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 = ""
)
}
)
}
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)
}
},
label = { Text(text = stringResource(R.string.sensors_mine)) },
)
}
}
) {
LazyColumn(
modifier = Modifier.fillMaxHeight(),
) {
items(sensorEntities) { sensor ->
SensorItem(sensor)
}
}
}) {
Box(modifier = Modifier.fillMaxSize()) {
SearchBar(
query = searchQuery,
@ -231,18 +210,24 @@ fun SensorsScreen(navController: NavController) {
},
onQueryChange = { query -> searchQuery = query },
onSearch = { searchActive = false },
placeholder = { Text(stringResource(R.string.search)) },
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,
vertical = if (!searchActive) 16.dp else 0.dp
)
) {}
TileMap(
modifier = Modifier
.fillMaxSize()
modifier = Modifier.fillMaxSize()
) {
sheetHeight =
SheetHeight.Expanded // TODO придумать, чтобы менялось на SheetHeight.ExtraExpanded после взаимодействия с картой
@ -251,25 +236,18 @@ fun SensorsScreen(navController: NavController) {
}
}
if (sortingShow) {
SortSensorsDialog(
sortingType,
onApply = {
sortingType = it
sortingShow = false
},
onDismissRequest = {
sortingShow = false
}
)
SortSensorsDialog(sortingType, onApply = {
sortingType = it
sortingShow = false
}, onDismissRequest = {
sortingShow = false
})
}
if (filterShow) {
FilterSensorsDialog(
onApply = {
// TODO применение фильтров
filterShow = false
},
onDismissRequest = { filterShow = false }
)
FilterSensorsDialog(onApply = {
// TODO применение фильтров
filterShow = false
}, onDismissRequest = { filterShow = false })
}
}

View 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)
}

View file

@ -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()
}

View file

@ -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())
}
}

View file

@ -10,15 +10,16 @@ import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
@ -26,23 +27,23 @@ private val LightColorScheme = lightColorScheme(
secondary = PurpleGrey80,
tertiary = Pink80
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
fun NarodMonTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
@ -57,14 +58,16 @@ fun NarodMonTheme(
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.statusBarColor = colorScheme.primary.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
WindowCompat.setDecorFitsSystemWindows(window, false)
window.statusBarColor = Color.Transparent.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
}
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
colorScheme = colorScheme,
typography = Typography,
content = content
)
}

View file

@ -1,6 +1,5 @@
package ru.nm17.narodmon.ui.webCamsScreen
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
@ -8,13 +7,13 @@ 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.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import ru.nm17.narodmon.ui.theme.NarodMonTheme
@Composable
fun WebCamsScreen() {
fun WebCamsScreen(navController: NavController) {
nm17 marked this conversation as resolved
Review

Также тут под вопросом вынос контроллера.

Также тут под вопросом вынос контроллера.
Review

В студии подсвечивается как unused. Да, это в твоём коде экрана датчиков было, мы и копируем))

В студии подсвечивается как unused. Да, это в твоём коде экрана датчиков было, мы и копируем))
Review

Он вынесен, чтобы можно было из веб-камер уйти в полноэкранное меню просмотра камеры

Он вынесен, чтобы можно было из веб-камер уйти в полноэкранное меню просмотра камеры
var webCams by remember {
mutableStateOf(
@ -58,6 +57,6 @@ fun WebCamsScreen() {
@Composable
fun PreviewWebCams() {
NarodMonTheme {
WebCamsScreen()
WebCamsScreen(rememberNavController())
}
}

View 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"/>
nm17 marked this conversation as resolved
Review

А в Material Icon Library нет этих иконок? Было бы супер, если бы мы могли без своих обойтись

https://developer.android.com/jetpack/compose/graphics/images/material
https://developer.android.com/reference/kotlin/androidx/compose/material/icons/package-summary

А в Material Icon Library нет этих иконок? Было бы супер, если бы мы могли без своих обойтись https://developer.android.com/jetpack/compose/graphics/images/material https://developer.android.com/reference/kotlin/androidx/compose/material/icons/package-summary
Review

А в Material Icon Library нет этих иконок? Было бы супер, если бы мы могли без своих обойтись

Официальный список — https://fonts.google.com/icons
При выборе иконки там даже есть код для Compose.

Сейчас посмотрел, все нужные иконки имеются.

> А в Material Icon Library нет этих иконок? Было бы супер, если бы мы могли без своих обойтись Официальный список — https://fonts.google.com/icons При выборе иконки там даже есть код для Compose. Сейчас посмотрел, все нужные иконки имеются.
Review

Дак я оттуда и брал))0)

Дак я оттуда и брал))0)
Review

Дак я оттуда и брал))0)

А, вижу. Раньше была вкладка с Jetpack Compose, убрали походу.

Вот так надо: https://developer.android.com/reference/kotlin/androidx/compose/material/icons/Icons.Outlined

Icons.Outlined.Home

вместо использования своей SVGшки.

Там нет как минимум иконки камеры

Прям во всех стилях (Filled, Outlined, Rounded) нету? Проверить сейчас негде.
Если так, то печально.
Можем посмотреть альтернативные библиотеки для Compose с теми же материал-диазайновыми иконками.

> Дак я оттуда и брал))0) А, вижу. Раньше была вкладка с Jetpack Compose, убрали походу. Вот так надо: https://developer.android.com/reference/kotlin/androidx/compose/material/icons/Icons.Outlined ```kotlin Icons.Outlined.Home ``` вместо использования своей SVGшки. > Там нет как минимум иконки камеры Прям во всех стилях (Filled, Outlined, Rounded) нету? Проверить сейчас негде. Если так, то печально. Можем посмотреть альтернативные библиотеки для Compose с теми же материал-диазайновыми иконками.
</vector>

View 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>

View 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>

View 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>

View file

@ -52,4 +52,10 @@
<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>