Added several tweaks to Screens, Dialogs and Layouts

develop
Arty Bishop 2024-12-07 16:15:03 +00:00
rodzic 674712509d
commit 1688b68c3c
8 zmienionych plików z 354 dodań i 201 usunięć

Wyświetl plik

@ -1,6 +1,5 @@
package com.rtbishop.look4sat.presentation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
@ -10,9 +9,8 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@ -20,16 +18,14 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.presentation.info.InfoScreen
import com.rtbishop.look4sat.presentation.map.MapScreen
import com.rtbishop.look4sat.presentation.passes.PassesScreen
import com.rtbishop.look4sat.presentation.passes.PassesViewModel
import com.rtbishop.look4sat.presentation.radar.RadarScreen
import com.rtbishop.look4sat.presentation.satellites.SatellitesScreen
import com.rtbishop.look4sat.presentation.satellites.SatellitesViewModel
import com.rtbishop.look4sat.presentation.settings.SettingsScreen
import com.rtbishop.look4sat.presentation.info.infoDestination
import com.rtbishop.look4sat.presentation.map.mapDestination
import com.rtbishop.look4sat.presentation.passes.passesDestination
import com.rtbishop.look4sat.presentation.radar.radarDestination
import com.rtbishop.look4sat.presentation.satellites.satellitesDestination
import com.rtbishop.look4sat.presentation.settings.settingsDestination
private sealed class Screen(var title: String, var icon: Int, var route: String) {
sealed class Screen(var title: String, var icon: Int, var route: String) {
data object Main : Screen("Main", R.drawable.ic_sputnik, "main")
data object Radar : Screen("Radar", R.drawable.ic_sputnik, "radar")
data object Satellites : Screen("Satellites", R.drawable.ic_sputnik, "satellites")
@ -42,46 +38,40 @@ private sealed class Screen(var title: String, var icon: Int, var route: String)
@Composable
fun MainScreen() {
val outerNavController: NavHostController = rememberNavController()
val radarRoute = "${Screen.Radar.route}?catNum={catNum}&aosTime={aosTime}"
val radarArgs = listOf(navArgument("catNum") { defaultValue = 0 },
navArgument("aosTime") { defaultValue = 0L })
val navToRadar = { catNum: Int, aosTime: Long ->
val navRoute = "${Screen.Radar.route}?catNum=${catNum}&aosTime=${aosTime}"
outerNavController.navigate(navRoute)
val navigateToRadar = { catNum: Int, aosTime: Long ->
val routeWithParams = "${Screen.Radar.route}?catNum=${catNum}&aosTime=${aosTime}"
outerNavController.navigate(routeWithParams)
}
val radarRoute = "${Screen.Radar.route}?catNum={catNum}&aosTime={aosTime}"
val radarArgs = listOf(
navArgument("catNum") { defaultValue = 0 },
navArgument("aosTime") { defaultValue = 0L }
)
NavHost(navController = outerNavController, startDestination = Screen.Main.route) {
composable(Screen.Main.route) { NavBarScreen(navToRadar) }
composable(radarRoute, radarArgs) { RadarScreen() }
mainDestination(navigateToRadar)
radarDestination(radarRoute, radarArgs)
}
}
private fun NavGraphBuilder.mainDestination(navigateToRadar: (Int, Long) -> Unit) {
composable(Screen.Main.route) { NavBarScreen(navigateToRadar) }
}
@Composable
private fun NavBarScreen(navToRadar: (Int, Long) -> Unit) {
private fun NavBarScreen(navigateToRadar: (Int, Long) -> Unit) {
val innerNavController: NavHostController = rememberNavController()
val navToPasses = { innerNavController.navigate(Screen.Passes.route) }
Scaffold(bottomBar = { MainNavBar(navController = innerNavController) }) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
NavHost(navController = innerNavController, startDestination = Screen.Passes.route) {
composable(Screen.Satellites.route) {
val viewModel = viewModel(
modelClass = SatellitesViewModel::class.java,
factory = SatellitesViewModel.Factory
)
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
SatellitesScreen(uiState, navToPasses)
}
composable(Screen.Passes.route) {
val viewModel = viewModel(
modelClass = PassesViewModel::class.java,
factory = PassesViewModel.Factory
)
val uiState = viewModel.uiState.value
PassesScreen(uiState, navToRadar)
}
composable(Screen.Map.route) { MapScreen() }
composable(Screen.Settings.route) { SettingsScreen() }
composable(Screen.Info.route) { InfoScreen() }
}
val navigateToPasses = { innerNavController.navigate(Screen.Passes.route) }
Scaffold(bottomBar = { MainNavBar(innerNavController) }) { innerPadding ->
NavHost(
navController = innerNavController,
startDestination = Screen.Passes.route,
modifier = Modifier.padding(innerPadding)
) {
satellitesDestination(navigateToPasses)
passesDestination(navigateToRadar)
mapDestination()
settingsDestination()
infoDestination()
}
}
}
@ -89,14 +79,13 @@ private fun NavBarScreen(navToRadar: (Int, Long) -> Unit) {
@Composable
private fun MainNavBar(navController: NavController) {
val items = listOf(Screen.Satellites, Screen.Passes, Screen.Map, Screen.Settings, Screen.Info)
val currentBackStackEntry = navController.currentBackStackEntryAsState()
val currentRoute = currentBackStackEntry.value?.destination?.route
val destinationRoute = navController.currentBackStackEntryAsState().value?.destination?.route
NavigationBar {
items.forEach { item ->
NavigationBarItem(
icon = { Icon(painterResource(item.icon), item.title) },
label = { Text(item.title) },
selected = currentRoute?.contains(item.route) ?: false,
selected = destinationRoute?.contains(item.route) ?: false,
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.startDestinationId) { saveState = false }

Wyświetl plik

@ -21,16 +21,23 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.presentation.MainTheme
import com.rtbishop.look4sat.presentation.Screen
import com.rtbishop.look4sat.presentation.components.CardButton
import com.rtbishop.look4sat.presentation.components.gotoUrl
private const val POLICY_URL = "https://sites.google.com/view/look4sat-privacy-policy/home"
private const val LICENSE_URL = "https://www.gnu.org/licenses/gpl-3.0.html"
fun NavGraphBuilder.infoDestination() {
composable(Screen.Info.route) { InfoScreen() }
}
@Composable
fun InfoScreen() {
private fun InfoScreen() {
LazyColumn(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
item { CardCredits() }
}

Wyświetl plik

@ -27,10 +27,13 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.OrbitalObject
import com.rtbishop.look4sat.domain.predict.OrbitalPos
import com.rtbishop.look4sat.presentation.Screen
import org.osmdroid.tileprovider.tilesource.XYTileSource
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.CustomZoomButtonsController
@ -61,8 +64,12 @@ private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
}
private val labelRect = Rect()
fun NavGraphBuilder.mapDestination() {
composable(Screen.Map.route) { MapScreen() }
}
@Composable
fun MapScreen() {
private fun MapScreen() {
val viewModel = viewModel(MapViewModel::class.java, factory = MapViewModel.Factory)
viewModel.selectDefaultSatellite(-1)
val stationPos = viewModel.stationPosition.collectAsState(initial = null)

Wyświetl plik

@ -23,7 +23,6 @@ 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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@ -32,16 +31,13 @@ import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.material3.Checkbox
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
@ -55,6 +51,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.presentation.MainTheme
import com.rtbishop.look4sat.presentation.components.CardButton
@ -73,80 +70,79 @@ private fun PassesDialogPreview() {
MainTheme { PassesDialog(24, 16.0, {}) { _, _ -> } }
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PassesDialog(hours: Int, elev: Double, dismiss: () -> Unit, save: (Int, Double) -> Unit) {
val maxWidthModifier = Modifier.fillMaxWidth()
val hoursValue = remember { mutableIntStateOf(hours) }
val elevationValue = remember { mutableIntStateOf(elev.toInt()) }
ModalBottomSheet(onDismissRequest = { dismiss() }) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(6.dp),
modifier = maxWidthModifier.padding(start = 16.dp, top = 0.dp, end = 16.dp, bottom = 32.dp)
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = maxWidthModifier
Dialog(onDismissRequest = { dismiss() }) {
ElevatedCard {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(6.dp),
modifier = maxWidthModifier.padding(16.dp)
) {
CardButton(onClick = { dismiss() }, text = stringResource(id = R.string.btn_cancel))
Text(text = "Passes", fontSize = 18.sp, color = MaterialTheme.colorScheme.primary)
CardButton(
onClick = {
save(hoursValue.intValue, elevationValue.intValue.toDouble())
dismiss()
}, text = stringResource(id = R.string.btn_accept)
Spacer(modifier = Modifier.height(8.dp))
Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.Bottom) {
Text(text = "Show passes above", fontSize = 16.sp, modifier = Modifier.weight(1f))
Icon(
painter = painterResource(id = R.drawable.ic_elevation),
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.size(20.dp)
.padding(bottom = 4.dp)
)
Text(
text = "${elevationValue.intValue}°",
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary
)
}
Slider(
value = elevationValue.intValue.toFloat(),
onValueChange = { elevationValue.intValue = it.toInt() },
valueRange = 0f..60f
)
Spacer(modifier = Modifier.height(8.dp))
Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.Bottom) {
Text(text = "Show passes within", fontSize = 16.sp, modifier = Modifier.weight(1f))
Icon(
painter = painterResource(id = R.drawable.ic_time),
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.size(20.dp)
.padding(bottom = 4.dp)
)
Text(
text = "${hoursValue.intValue}h",
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary
)
}
Slider(
value = hoursValue.intValue.toFloat(),
onValueChange = { hoursValue.intValue = it.toInt() },
valueRange = 1f..240f
)
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = maxWidthModifier
) {
CardButton(onClick = { dismiss() }, text = stringResource(id = R.string.btn_cancel))
CardButton(
onClick = {
save(hoursValue.intValue, elevationValue.intValue.toDouble())
dismiss()
}, text = stringResource(id = R.string.btn_accept)
)
}
}
Spacer(modifier = Modifier.height(8.dp))
Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.Bottom) {
Text(text = "Show passes above", fontSize = 16.sp, modifier = Modifier.weight(1f))
Icon(
painter = painterResource(id = R.drawable.ic_elevation),
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.size(20.dp)
.padding(bottom = 4.dp)
)
Text(
text = "${elevationValue.intValue}°",
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary
)
}
Slider(
value = elevationValue.intValue.toFloat(),
onValueChange = { elevationValue.intValue = it.toInt() },
valueRange = 0f..60f,
colors = SliderDefaults.colors(inactiveTrackColor = MaterialTheme.colorScheme.onSurfaceVariant)
)
Spacer(modifier = Modifier.height(8.dp))
Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.Bottom) {
Text(text = "Show passes within", fontSize = 16.sp, modifier = Modifier.weight(1f))
Icon(
painter = painterResource(id = R.drawable.ic_time),
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.size(20.dp)
.padding(bottom = 4.dp)
)
Text(
text = "${hoursValue.intValue}h",
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary
)
}
Slider(
value = hoursValue.intValue.toFloat(),
onValueChange = { hoursValue.intValue = it.toInt() },
valueRange = 1f..240f,
colors = SliderDefaults.colors(inactiveTrackColor = MaterialTheme.colorScheme.onSurfaceVariant)
)
}
}
}
@ -157,73 +153,69 @@ private fun RadiosDialogPreview() {
MainTheme { RadiosDialog(emptyList(), {}) { _ -> } }
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RadiosDialog(modes: List<String>, dismiss: () -> Unit, save: (List<String>) -> Unit) {
val maxWidthModifier = Modifier.fillMaxWidth(1f)
val selected = remember { mutableStateListOf<String>().apply { addAll(modes) } }
val select = { mode: String -> if (selected.contains(mode)) selected.remove(mode) else selected.add(mode) }
ModalBottomSheet(
onDismissRequest = { dismiss() },
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
modifier = Modifier.fillMaxHeight(0.80f)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(6.dp),
modifier = maxWidthModifier.padding(horizontal = 12.dp)
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = maxWidthModifier
Dialog(onDismissRequest = { dismiss() }) {
ElevatedCard {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = maxWidthModifier.padding(vertical = 16.dp)
) {
CardButton(onClick = { dismiss() }, text = stringResource(id = R.string.btn_cancel))
Text(text = "Radios", fontSize = 18.sp, color = MaterialTheme.colorScheme.primary)
CardButton(
onClick = {
save(selected.toList())
dismiss()
}, text = stringResource(id = R.string.btn_accept)
)
}
LazyVerticalGrid(
columns = GridCells.Fixed(1),
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.weight(1f),
horizontalArrangement = Arrangement.spacedBy(1.dp),
verticalArrangement = Arrangement.spacedBy(1.dp)
) {
item { HorizontalDivider(thickness = 0.dp, color = MaterialTheme.colorScheme.surface) }
itemsIndexed(allModes) { index, item ->
Surface {
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.background(MaterialTheme.colorScheme.surface)
.clickable { select(item) }) {
Text(
text = "$index).",
modifier = Modifier.padding(start = 8.dp, end = 6.dp),
fontWeight = FontWeight.Normal,
color = MaterialTheme.colorScheme.primary
)
Text(
text = item,
modifier = Modifier.weight(1f),
fontWeight = FontWeight.Medium,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Checkbox(
checked = selected.contains(item),
onCheckedChange = null,
modifier = Modifier.padding(8.dp)
)
LazyVerticalGrid(
columns = GridCells.Fixed(1),
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.weight(1f),
horizontalArrangement = Arrangement.spacedBy(1.dp),
verticalArrangement = Arrangement.spacedBy(1.dp)
) {
item { HorizontalDivider(thickness = 0.dp, color = MaterialTheme.colorScheme.surface) }
itemsIndexed(allModes) { index, item ->
Surface {
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.background(MaterialTheme.colorScheme.surface)
.clickable { select(item) }) {
Text(
text = "$index).",
modifier = Modifier.padding(start = 8.dp, end = 6.dp),
fontWeight = FontWeight.Normal,
color = MaterialTheme.colorScheme.primary
)
Text(
text = item,
modifier = Modifier.weight(1f),
fontWeight = FontWeight.Medium,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Checkbox(
checked = selected.contains(item),
onCheckedChange = null,
modifier = Modifier.padding(8.dp)
)
}
}
}
item { HorizontalDivider(thickness = 24.dp, color = MaterialTheme.colorScheme.surface) }
}
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = maxWidthModifier.padding(horizontal = 16.dp)
) {
CardButton(onClick = { dismiss() }, text = stringResource(id = R.string.btn_cancel))
CardButton(
onClick = {
save(selected.toList())
dismiss()
}, text = stringResource(id = R.string.btn_accept)
)
}
item { HorizontalDivider(thickness = 24.dp, color = MaterialTheme.colorScheme.surface) }
}
}
}

Wyświetl plik

@ -33,12 +33,16 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.predict.DeepSpaceObject
import com.rtbishop.look4sat.domain.predict.NearEarthObject
import com.rtbishop.look4sat.domain.predict.OrbitalData
import com.rtbishop.look4sat.domain.predict.OrbitalPass
import com.rtbishop.look4sat.presentation.MainTheme
import com.rtbishop.look4sat.presentation.Screen
import com.rtbishop.look4sat.presentation.components.CardIcon
import com.rtbishop.look4sat.presentation.components.NextPassRow
import com.rtbishop.look4sat.presentation.components.TimerBar
@ -50,8 +54,19 @@ import java.util.Locale
private val sdfDate = SimpleDateFormat("EEE dd MMM", Locale.ENGLISH)
private val sdfTime = SimpleDateFormat("HH:mm:ss", Locale.ENGLISH)
fun NavGraphBuilder.passesDestination(navigateToRadar: (Int, Long) -> Unit) {
composable(Screen.Passes.route) {
val viewModel = viewModel(
modelClass = PassesViewModel::class.java,
factory = PassesViewModel.Factory
)
val uiState = viewModel.uiState.value
PassesScreen(uiState, navigateToRadar)
}
}
@Composable
fun PassesScreen(uiState: PassesState, navToRadar: (Int, Long) -> Unit) {
private fun PassesScreen(uiState: PassesState, navigateToRadar: (Int, Long) -> Unit) {
val refreshPasses = { uiState.takeAction(PassesAction.RefreshPasses) }
val showPassesDialog = { uiState.takeAction(PassesAction.TogglePassesDialog) }
val showRadiosDialog = { uiState.takeAction(PassesAction.ToggleRadiosDialog) }
@ -72,7 +87,7 @@ fun PassesScreen(uiState: PassesState, navToRadar: (Int, Long) -> Unit) {
CardIcon(onClick = { showRadiosDialog() }, iconId = R.drawable.ic_satellite)
}
NextPassRow(pass = uiState.nextPass)
PassesList(uiState.isRefreshing, uiState.itemsList, navToRadar, refreshPasses)
PassesList(uiState.isRefreshing, uiState.itemsList, navigateToRadar, refreshPasses)
}
}
@ -81,7 +96,7 @@ fun PassesScreen(uiState: PassesState, navToRadar: (Int, Long) -> Unit) {
private fun PassesList(
isRefreshing: Boolean,
passes: List<OrbitalPass>,
navToRadar: (Int, Long) -> Unit,
navigateToRadar: (Int, Long) -> Unit,
refreshPasses: () -> Unit
) {
val refreshState = rememberPullToRefreshState()
@ -102,11 +117,19 @@ private fun PassesList(
) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(items = passes, key = { item -> item.catNum + item.aosTime }) { pass ->
PassItem(
pass = pass,
navToRadar = navToRadar,
modifier = Modifier.animateItem()
)
if (pass.isDeepSpace) {
DeepSpacePass(
pass = pass,
navigateToRadar = navigateToRadar,
modifier = Modifier.animateItem()
)
} else {
NearEarthPass(
pass = pass,
navigateToRadar = navigateToRadar,
modifier = Modifier.animateItem()
)
}
}
}
}
@ -121,7 +144,113 @@ private fun DeepSpacePassPreview() {
)
val satellite = DeepSpaceObject(data)
val pass = OrbitalPass(1L, 180.0, 10L, 360.0, 36650, 45.0, satellite, 0.5f)
MainTheme { PassItem(pass = pass, { _, _ -> }) }
MainTheme { DeepSpacePass(pass = pass, { _, _ -> }) }
}
@Composable
private fun DeepSpacePass(
pass: OrbitalPass,
navigateToRadar: (Int, Long) -> Unit,
modifier: Modifier = Modifier
) {
val passSatId = stringResource(id = R.string.pass_satId, pass.catNum)
Surface(color = MaterialTheme.colorScheme.background, modifier = modifier) {
Surface(modifier = Modifier
.padding(bottom = 2.dp)
.clickable { navigateToRadar(pass.catNum, pass.aosTime) }) {
Column(
verticalArrangement = Arrangement.spacedBy(1.dp),
modifier = Modifier
.background(color = MaterialTheme.colorScheme.surface)
.padding(horizontal = 6.dp, vertical = 4.dp)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = "$passSatId - ",
color = MaterialTheme.colorScheme.primary
)
Text(
text = pass.name,
modifier = Modifier
.weight(1f)
.padding(end = 6.dp),
fontWeight = FontWeight.Medium,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Icon(
painter = painterResource(id = R.drawable.ic_elevation),
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = "${pass.maxElevation}°",
color = MaterialTheme.colorScheme.primary
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow),
contentDescription = null,
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = "DeepSpace",
fontSize = 15.sp
)
}
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(id = R.drawable.ic_altitude),
contentDescription = null,
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = "${pass.altitude} km",
fontSize = 15.sp
)
}
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(id = R.drawable.ic_direction),
contentDescription = null,
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = stringResource(
id = R.string.pass_aosLos,
pass.aosAzimuth.toInt(),
pass.losAzimuth.toInt()
),
fontSize = 15.sp
)
}
}
}
}
}
}
@Preview(showBackground = true)
@ -132,16 +261,20 @@ private fun NearEarthPassPreview() {
)
val satellite = NearEarthObject(data)
val pass = OrbitalPass(1L, 180.0, 10L, 360.0, 36650, 45.0, satellite, 0.5f)
MainTheme { PassItem(pass = pass, { _, _ -> }) }
MainTheme { NearEarthPass(pass = pass, { _, _ -> }) }
}
@Composable
private fun PassItem(pass: OrbitalPass, navToRadar: (Int, Long) -> Unit, modifier: Modifier = Modifier) {
private fun NearEarthPass(
pass: OrbitalPass,
navigateToRadar: (Int, Long) -> Unit,
modifier: Modifier = Modifier
) {
val passSatId = stringResource(id = R.string.pass_satId, pass.catNum)
Surface(color = MaterialTheme.colorScheme.background, modifier = modifier) {
Surface(modifier = Modifier
.padding(bottom = 2.dp)
.clickable { navToRadar(pass.catNum, pass.aosTime) }) {
.clickable { navigateToRadar(pass.catNum, pass.aosTime) }) {
Column(
verticalArrangement = Arrangement.spacedBy(1.dp),
modifier = Modifier

Wyświetl plik

@ -26,11 +26,18 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.model.SatRadio
fun NavGraphBuilder.radarDestination(radarRoute: String, radarArgs: List<NamedNavArgument>) {
composable(radarRoute, radarArgs) { RadarScreen() }
}
@Composable
fun RadarScreen() {
private fun RadarScreen() {
val viewModel = viewModel(RadarViewModel::class.java, factory = RadarViewModel.Factory)
val currentPass = viewModel.getPass().collectAsState(null).value
val id = currentPass?.catNum ?: 99999

Wyświetl plik

@ -36,14 +36,30 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.presentation.MainTheme
import com.rtbishop.look4sat.presentation.Screen
import com.rtbishop.look4sat.presentation.components.CardIcon
import com.rtbishop.look4sat.presentation.components.CardLoadingIndicator
fun NavGraphBuilder.satellitesDestination(navigateToPasses: () -> Unit) {
composable(Screen.Satellites.route) {
val viewModel = viewModel(
modelClass = SatellitesViewModel::class.java,
factory = SatellitesViewModel.Factory
)
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
SatellitesScreen(uiState, navigateToPasses)
}
}
@Composable
fun SatellitesScreen(uiState: SatellitesState, navToPasses: () -> Unit) {
private fun SatellitesScreen(uiState: SatellitesState, navigateToPasses: () -> Unit) {
val toggleDialog = { uiState.takeAction(SatellitesAction.ToggleTypesDialog) }
if (uiState.isDialogShown) {
TypesDialog(items = uiState.typesList, selected = uiState.currentType, toggleDialog) {
@ -57,7 +73,7 @@ fun SatellitesScreen(uiState: SatellitesState, navToPasses: () -> Unit) {
uiState.takeAction(SatellitesAction.SearchFor(newQuery))
}, saveSelection = {
uiState.takeAction(SatellitesAction.SaveSelection)
navToPasses()
navigateToPasses()
})
MiddleBar(uiState.currentType, { toggleDialog() }, { unselectAll() }, { selectAll() })
ElevatedCard(modifier = Modifier.fillMaxSize()) {

Wyświetl plik

@ -33,10 +33,13 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.model.OtherSettings
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.presentation.MainTheme
import com.rtbishop.look4sat.presentation.Screen
import com.rtbishop.look4sat.presentation.components.CardButton
import com.rtbishop.look4sat.presentation.components.gotoUrl
import com.rtbishop.look4sat.presentation.components.showToast
@ -48,8 +51,12 @@ private const val GITHUB_URL = "https://github.com/rt-bishop/Look4Sat/"
private const val DONATE_URL = "https://ko-fi.com/rt_bishop"
private const val FDROID_URL = "https://f-droid.org/en/packages/com.rtbishop.look4sat/"
fun NavGraphBuilder.settingsDestination() {
composable(Screen.Settings.route) { SettingsScreen() }
}
@Composable
fun SettingsScreen() {
private fun SettingsScreen() {
val viewModel = viewModel(SettingsViewModel::class.java, factory = SettingsViewModel.Factory)
val context = LocalContext.current
@ -446,16 +453,11 @@ private fun setUpdateTime(updateTime: Long): String {
@Composable
private fun UpdateIndicator(isUpdating: Boolean, modifier: Modifier = Modifier) = if (isUpdating) {
LinearProgressIndicator(
modifier = modifier.padding(start = 6.dp),
// color = MaterialTheme.colorScheme.primary,
// trackColor = MaterialTheme.colorScheme.secondaryContainer
)
LinearProgressIndicator(modifier = modifier.padding(start = 6.dp))
} else {
LinearProgressIndicator(
progress = { 0f },
modifier = modifier.padding(start = 6.dp),
// color = MaterialTheme.colorScheme.primary,
// trackColor = MaterialTheme.colorScheme.secondaryContainer
drawStopIndicator = {},
modifier = modifier.padding(start = 6.dp)
)
}