mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Tried using floating app bar layout for screen navigation
This commit is contained in:
1 parent
82f41940c7
commit
42aa4deb0d
11 files changed
+135
-144
No files matched your search
@@ -1,75 +1,53 @@
|
|||||||
package com.rtbishop.look4sat.presentation
|
package com.rtbishop.look4sat.presentation
|
||||||
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteDefaults
|
|
||||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
|
|
||||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.rtbishop.look4sat.R
|
|
||||||
import com.rtbishop.look4sat.presentation.common.isVerticalLayout
|
|
||||||
import com.rtbishop.look4sat.presentation.map.mapDestination
|
import com.rtbishop.look4sat.presentation.map.mapDestination
|
||||||
import com.rtbishop.look4sat.presentation.passes.passesDestination
|
import com.rtbishop.look4sat.presentation.passes.passesDestination
|
||||||
import com.rtbishop.look4sat.presentation.radar.radarDestination
|
import com.rtbishop.look4sat.presentation.radar.radarDestination
|
||||||
import com.rtbishop.look4sat.presentation.satellites.satellitesDestination
|
import com.rtbishop.look4sat.presentation.satellites.satellitesDestination
|
||||||
import com.rtbishop.look4sat.presentation.settings.settingsDestination
|
import com.rtbishop.look4sat.presentation.settings.settingsDestination
|
||||||
|
|
||||||
sealed class Screen(val title: String, val icon: Int, val route: String) {
|
sealed class Screen(val route: String) {
|
||||||
data object Satellites : Screen("Satellites", R.drawable.ic_sputnik, "satellites")
|
data object Satellites : Screen("satellites")
|
||||||
data object Passes : Screen("Passes", R.drawable.ic_passes, "passes")
|
data object Passes : Screen("passes")
|
||||||
data object Radar : Screen("Radar", R.drawable.ic_satellite, "radar")
|
data object Radar : Screen("radar")
|
||||||
data object Map : Screen("Map", R.drawable.ic_map, "map")
|
data object Map : Screen("map")
|
||||||
data object Settings : Screen("Settings", R.drawable.ic_settings, "settings")
|
data object Settings : Screen("settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val startDestination = Screen.Passes.route
|
data class NavActions(
|
||||||
|
val openSatellites: () -> Unit,
|
||||||
|
val openRadar: (Int, Long) -> Unit,
|
||||||
|
val openMap: () -> Unit,
|
||||||
|
val openSettings: () -> Unit
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainScreen(navController: NavHostController = rememberNavController()) {
|
fun MainScreen(navController: NavHostController = rememberNavController()) {
|
||||||
val items = listOf(Screen.Satellites, Screen.Passes, Screen.Radar, Screen.Map, Screen.Settings)
|
val navActions = NavActions(
|
||||||
val destinationRoute = navController.currentBackStackEntryAsState().value?.destination?.route
|
openSatellites = { navController.navigate(Screen.Satellites.route) },
|
||||||
NavigationSuiteScaffold(
|
openRadar = { catNum: Int, aosTime: Long ->
|
||||||
navigationSuiteItems = {
|
|
||||||
items.forEach {
|
|
||||||
item(
|
|
||||||
icon = { Icon(painterResource(it.icon), it.title) },
|
|
||||||
label = { Text(it.title) },
|
|
||||||
selected = destinationRoute?.contains(it.route) ?: false,
|
|
||||||
onClick = {
|
|
||||||
if (destinationRoute?.contains(it.route) ?: false) return@item
|
|
||||||
navController.navigate(it.route) {
|
|
||||||
popUpTo(startDestination) { saveState = false }
|
|
||||||
launchSingleTop = true
|
|
||||||
restoreState = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, navigationSuiteColors = NavigationSuiteDefaults.colors(
|
|
||||||
navigationRailContainerColor = MaterialTheme.colorScheme.surfaceContainer
|
|
||||||
), layoutType = when {
|
|
||||||
isVerticalLayout() -> NavigationSuiteType.NavigationBar
|
|
||||||
else -> NavigationSuiteType.NavigationRail
|
|
||||||
}
|
|
||||||
) { MainNavHost(navController) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun MainNavHost(navController: NavHostController) {
|
|
||||||
val navigateToRadar = { catNum: Int, aosTime: Long ->
|
|
||||||
val routeWithParams = "${Screen.Radar.route}?catNum=${catNum}&aosTime=${aosTime}"
|
val routeWithParams = "${Screen.Radar.route}?catNum=${catNum}&aosTime=${aosTime}"
|
||||||
navController.navigate(routeWithParams)
|
navController.navigate(routeWithParams)
|
||||||
}
|
},
|
||||||
NavHost(navController = navController, startDestination = startDestination) {
|
openMap = { navController.navigate(Screen.Map.route) },
|
||||||
|
openSettings = { navController.navigate(Screen.Settings.route) }
|
||||||
|
)
|
||||||
|
NavHost(
|
||||||
|
navController = navController,
|
||||||
|
startDestination = Screen.Passes.route,
|
||||||
|
modifier = Modifier.background(color = MaterialTheme.colorScheme.background)
|
||||||
|
) {
|
||||||
satellitesDestination { navController.navigateUp() }
|
satellitesDestination { navController.navigateUp() }
|
||||||
passesDestination(navigateToRadar)
|
passesDestination(navActions)
|
||||||
radarDestination { navController.navigateUp() }
|
radarDestination { navController.navigateUp() }
|
||||||
mapDestination()
|
mapDestination { navController.navigateUp() }
|
||||||
settingsDestination()
|
settingsDestination { navController.navigateUp() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,23 +22,14 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
|
|
||||||
val LocalSpacing = compositionLocalOf { Spacing }
|
val LocalSpacing = compositionLocalOf { Spacing }
|
||||||
//val MaterialTheme.spacing: Spacing
|
|
||||||
// @Composable @ReadOnlyComposable get() = Spacing
|
|
||||||
|
|
||||||
data object SpacingDefaults {
|
|
||||||
internal const val EXTRA_SMALL = 4
|
|
||||||
internal const val SMALL = 6
|
|
||||||
internal const val MEDIUM = 8
|
|
||||||
internal const val LARGE = 12
|
|
||||||
internal const val EXTRA_LARGE = 16
|
|
||||||
}
|
|
||||||
|
|
||||||
data object Spacing {
|
data object Spacing {
|
||||||
val extraSmall = SpacingDefaults.EXTRA_SMALL.dp
|
val extraExtraSmall = 4.dp
|
||||||
val small = SpacingDefaults.SMALL.dp
|
val extraSmall = 6.dp
|
||||||
val medium = SpacingDefaults.MEDIUM.dp
|
val small = 8.dp
|
||||||
val large = SpacingDefaults.LARGE.dp
|
val medium = 12.dp
|
||||||
val extraLarge = SpacingDefaults.EXTRA_LARGE.dp
|
val large = 16.dp
|
||||||
|
val extraLarge = 24.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -17,21 +17,22 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ElevatedButton
|
import androidx.compose.material3.ElevatedButton
|
||||||
import androidx.compose.material3.ElevatedCard
|
import androidx.compose.material3.ElevatedCard
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.res.vectorResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@@ -56,9 +57,9 @@ private val sdfTime = SimpleDateFormat("HH:mm:ss", Locale.ENGLISH)
|
|||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
private fun TopBarPreview() = MainTheme {
|
private fun TopBarPreview() = MainTheme {
|
||||||
TopBar {
|
TopBar {
|
||||||
IconCard(onClick = {}, iconId = R.drawable.ic_filter)
|
IconCard(action = {}, resId = R.drawable.ic_filter)
|
||||||
TimerRow(timeString = "88:88:88", isTimeAos = true)
|
TimerRow(timeString = "88:88:88", isTimeAos = true)
|
||||||
IconCard(onClick = {}, iconId = R.drawable.ic_satellite)
|
IconCard(action = {}, resId = R.drawable.ic_satellite)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,12 +201,13 @@ fun CardButton(onClick: () -> Unit, text: String, modifier: Modifier = Modifier)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun IconCard(onClick: () -> Unit, iconId: Int, modifier: Modifier = Modifier) {
|
fun IconCard(action: () -> Unit, resId: Int, modifier: Modifier = Modifier, main: Boolean = false) {
|
||||||
val clickableModifier = Modifier.clickable { onClick() }
|
val clickableMod = Modifier.clickable { action() }
|
||||||
val iconRes = ImageVector.vectorResource(iconId)
|
val defaultC = CardDefaults.elevatedCardColors()
|
||||||
ElevatedCard(modifier = Modifier.size(48.dp)) {
|
val mainC = CardDefaults.elevatedCardColors(containerColor = MaterialTheme.colorScheme.primary)
|
||||||
Box(modifier = clickableModifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
ElevatedCard(modifier = Modifier.size(48.dp), colors = if (main) mainC else defaultC, shape = CircleShape) {
|
||||||
Icon(imageVector = iconRes, contentDescription = null, modifier = modifier)
|
Box(modifier = clickableMod.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
|
Icon(painter = painterResource(resId), contentDescription = null, modifier = modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,7 +243,7 @@ fun getDefaultPass(): OrbitalPass {
|
|||||||
fun SharedDialog(
|
fun SharedDialog(
|
||||||
title: String, onCancel: () -> Unit, onAccept: () -> Unit, content: @Composable () -> Unit
|
title: String, onCancel: () -> Unit, onAccept: () -> Unit, content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
val padding = LocalSpacing.current.extraLarge
|
val padding = LocalSpacing.current.large
|
||||||
Dialog(onDismissRequest = { onCancel() }) {
|
Dialog(onDismissRequest = { onCancel() }) {
|
||||||
ElevatedCard {
|
ElevatedCard {
|
||||||
Column(
|
Column(
|
||||||
@@ -268,7 +270,7 @@ fun SharedDialog(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun InfoDialog(title: String, text: String, onDismiss: () -> Unit) {
|
fun InfoDialog(title: String, text: String, onDismiss: () -> Unit) {
|
||||||
val padding = LocalSpacing.current.extraLarge
|
val padding = LocalSpacing.current.large
|
||||||
Dialog(onDismissRequest = onDismiss) {
|
Dialog(onDismissRequest = onDismiss) {
|
||||||
ElevatedCard {
|
ElevatedCard {
|
||||||
Column(
|
Column(
|
||||||
@@ -290,7 +292,10 @@ fun InfoDialog(title: String, text: String, onDismiss: () -> Unit) {
|
|||||||
)
|
)
|
||||||
Row(modifier = Modifier.padding(start = padding, bottom = padding, end = padding)) {
|
Row(modifier = Modifier.padding(start = padding, bottom = padding, end = padding)) {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
CardButton(onClick = onDismiss, text = stringResource(id = R.string.btn_understand))
|
CardButton(
|
||||||
|
onClick = onDismiss,
|
||||||
|
text = stringResource(id = R.string.btn_understand)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,9 +316,41 @@ fun Modifier.infiniteMarquee(): Modifier {
|
|||||||
@Composable
|
@Composable
|
||||||
fun Modifier.layoutPadding(): Modifier {
|
fun Modifier.layoutPadding(): Modifier {
|
||||||
val statusBarMod = this.statusBarsPadding()
|
val statusBarMod = this.statusBarsPadding()
|
||||||
val spacing = LocalSpacing.current.small
|
val spacing = LocalSpacing.current.extraSmall
|
||||||
return when {
|
return statusBarMod.padding(start = spacing, top = 0.dp, end = spacing, bottom = spacing)
|
||||||
isVerticalLayout() -> statusBarMod.padding(horizontal = spacing)
|
}
|
||||||
else -> statusBarMod.padding(start = 0.dp, top = 0.dp, end = spacing, bottom = spacing)
|
|
||||||
|
@Composable
|
||||||
|
fun ScreenColumn(floatingBar: @Composable () -> Unit = {}, content: @Composable (Boolean) -> Unit) {
|
||||||
|
Box(contentAlignment = Alignment.BottomCenter) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.layoutPadding(),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(LocalSpacing.current.extraSmall)
|
||||||
|
) { content(isVerticalLayout()) }
|
||||||
|
floatingBar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun FloatingBar(
|
||||||
|
startAction: () -> Unit, startIconResId: Int,
|
||||||
|
centerAction: () -> Unit, centerIconResId: Int,
|
||||||
|
endAction: () -> Unit, endIconResId: Int
|
||||||
|
) {
|
||||||
|
val spacing = LocalSpacing.current
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background,
|
||||||
|
shape = CircleShape,
|
||||||
|
modifier = Modifier.padding(bottom = spacing.large)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(spacing.medium),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.padding(spacing.medium)
|
||||||
|
) {
|
||||||
|
IconCard(action = startAction, resId = startIconResId)
|
||||||
|
IconCard(action = centerAction, resId = centerIconResId, main = true)
|
||||||
|
IconCard(action = endAction, resId = endIconResId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
|||||||
}
|
}
|
||||||
private val labelRect = Rect()
|
private val labelRect = Rect()
|
||||||
|
|
||||||
fun NavGraphBuilder.mapDestination() {
|
fun NavGraphBuilder.mapDestination(function: () -> Boolean) {
|
||||||
composable(Screen.Map.route) {
|
composable(Screen.Map.route) {
|
||||||
val viewModel = viewModel(MapViewModel::class.java, factory = MapViewModel.Factory)
|
val viewModel = viewModel(MapViewModel::class.java, factory = MapViewModel.Factory)
|
||||||
val uiState = viewModel.uiState.collectAsStateWithLifecycle()
|
val uiState = viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
@@ -110,17 +110,17 @@ private fun MapScreen(uiState: State<MapState>, mapView: MapView) {
|
|||||||
Column(modifier = Modifier.layoutPadding(), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
Column(modifier = Modifier.layoutPadding(), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
if (isVerticalLayout()) {
|
if (isVerticalLayout()) {
|
||||||
TopBar {
|
TopBar {
|
||||||
IconCard(onClick = selectPrev, iconId = R.drawable.ic_arrow, modifier = rotateMod)
|
IconCard(action = selectPrev, resId = R.drawable.ic_arrow, modifier = rotateMod)
|
||||||
TimerRow(timeString = timeString, isTimeAos = isTimeAos)
|
TimerRow(timeString = timeString, isTimeAos = isTimeAos)
|
||||||
IconCard(onClick = selectNext, iconId = R.drawable.ic_arrow)
|
IconCard(action = selectNext, resId = R.drawable.ic_arrow)
|
||||||
}
|
}
|
||||||
NextPassRow(pass = uiState.value.orbitalPass)
|
NextPassRow(pass = uiState.value.orbitalPass)
|
||||||
} else {
|
} else {
|
||||||
TopBar {
|
TopBar {
|
||||||
IconCard(onClick = selectPrev, iconId = R.drawable.ic_arrow, modifier = rotateMod)
|
IconCard(action = selectPrev, resId = R.drawable.ic_arrow, modifier = rotateMod)
|
||||||
TimerRow(timeString = timeString, isTimeAos = isTimeAos)
|
TimerRow(timeString = timeString, isTimeAos = isTimeAos)
|
||||||
NextPassRow(pass = uiState.value.orbitalPass, modifier = Modifier.weight(1f))
|
NextPassRow(pass = uiState.value.orbitalPass, modifier = Modifier.weight(1f))
|
||||||
IconCard(onClick = selectNext, iconId = R.drawable.ic_arrow)
|
IconCard(action = selectNext, resId = R.drawable.ic_arrow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ElevatedCard(modifier = Modifier.weight(1f)) {
|
ElevatedCard(modifier = Modifier.weight(1f)) {
|
||||||
|
|||||||
@@ -102,11 +102,11 @@ private fun SliderRow(
|
|||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(LocalSpacing.current.medium),
|
verticalArrangement = Arrangement.spacedBy(LocalSpacing.current.small),
|
||||||
modifier = Modifier.padding(horizontal = LocalSpacing.current.extraLarge)
|
modifier = Modifier.padding(horizontal = LocalSpacing.current.large)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(LocalSpacing.current.medium),
|
horizontalArrangement = Arrangement.spacedBy(LocalSpacing.current.small),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -44,16 +44,18 @@ import com.rtbishop.look4sat.domain.predict.NearEarthObject
|
|||||||
import com.rtbishop.look4sat.domain.predict.OrbitalData
|
import com.rtbishop.look4sat.domain.predict.OrbitalData
|
||||||
import com.rtbishop.look4sat.domain.predict.OrbitalPass
|
import com.rtbishop.look4sat.domain.predict.OrbitalPass
|
||||||
import com.rtbishop.look4sat.presentation.MainTheme
|
import com.rtbishop.look4sat.presentation.MainTheme
|
||||||
|
import com.rtbishop.look4sat.presentation.NavActions
|
||||||
import com.rtbishop.look4sat.presentation.Screen
|
import com.rtbishop.look4sat.presentation.Screen
|
||||||
import com.rtbishop.look4sat.presentation.common.EmptyListCard
|
import com.rtbishop.look4sat.presentation.common.EmptyListCard
|
||||||
|
import com.rtbishop.look4sat.presentation.common.FloatingBar
|
||||||
import com.rtbishop.look4sat.presentation.common.IconCard
|
import com.rtbishop.look4sat.presentation.common.IconCard
|
||||||
import com.rtbishop.look4sat.presentation.common.InfoDialog
|
import com.rtbishop.look4sat.presentation.common.InfoDialog
|
||||||
import com.rtbishop.look4sat.presentation.common.NextPassRow
|
import com.rtbishop.look4sat.presentation.common.NextPassRow
|
||||||
|
import com.rtbishop.look4sat.presentation.common.ScreenColumn
|
||||||
import com.rtbishop.look4sat.presentation.common.TimerRow
|
import com.rtbishop.look4sat.presentation.common.TimerRow
|
||||||
import com.rtbishop.look4sat.presentation.common.TopBar
|
import com.rtbishop.look4sat.presentation.common.TopBar
|
||||||
import com.rtbishop.look4sat.presentation.common.infiniteMarquee
|
import com.rtbishop.look4sat.presentation.common.infiniteMarquee
|
||||||
import com.rtbishop.look4sat.presentation.common.isVerticalLayout
|
import com.rtbishop.look4sat.presentation.common.isVerticalLayout
|
||||||
import com.rtbishop.look4sat.presentation.common.layoutPadding
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -61,20 +63,20 @@ import java.util.Locale
|
|||||||
private val sdfDate = SimpleDateFormat("EEE dd MMM", Locale.ENGLISH)
|
private val sdfDate = SimpleDateFormat("EEE dd MMM", Locale.ENGLISH)
|
||||||
private val sdfTime = SimpleDateFormat("HH:mm:ss", Locale.ENGLISH)
|
private val sdfTime = SimpleDateFormat("HH:mm:ss", Locale.ENGLISH)
|
||||||
|
|
||||||
fun NavGraphBuilder.passesDestination(navigateToRadar: (Int, Long) -> Unit) {
|
fun NavGraphBuilder.passesDestination(navActions: NavActions) {
|
||||||
composable(Screen.Passes.route) {
|
composable(Screen.Passes.route) {
|
||||||
val viewModel = viewModel(
|
val viewModel = viewModel(
|
||||||
modelClass = PassesViewModel::class.java,
|
modelClass = PassesViewModel::class.java,
|
||||||
factory = PassesViewModel.Factory
|
factory = PassesViewModel.Factory
|
||||||
)
|
)
|
||||||
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
|
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
|
||||||
PassesScreen(uiState, navigateToRadar)
|
PassesScreen(uiState, navActions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun PassesScreen(uiState: PassesState, navigateToRadar: (Int, Long) -> Unit) {
|
private fun PassesScreen(uiState: PassesState, navActions: NavActions) {
|
||||||
val refreshPasses = { uiState.takeAction(PassesAction.RefreshPasses) }
|
val refreshList = { uiState.takeAction(PassesAction.RefreshPasses) }
|
||||||
val showPassesDialog = { uiState.takeAction(PassesAction.TogglePassesDialog) }
|
val showPassesDialog = { uiState.takeAction(PassesAction.TogglePassesDialog) }
|
||||||
val showRadiosDialog = { uiState.takeAction(PassesAction.ToggleRadiosDialog) }
|
val showRadiosDialog = { uiState.takeAction(PassesAction.ToggleRadiosDialog) }
|
||||||
if (uiState.isPassesDialogShown) {
|
if (uiState.isPassesDialogShown) {
|
||||||
@@ -95,26 +97,35 @@ private fun PassesScreen(uiState: PassesState, navigateToRadar: (Int, Long) -> U
|
|||||||
uiState.takeAction(PassesAction.DismissWelcome)
|
uiState.takeAction(PassesAction.DismissWelcome)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Column(modifier = Modifier.layoutPadding(), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
ScreenColumn(floatingBar = { PassesFloatingBar(navActions) }) { isVerticalLayout ->
|
||||||
if (isVerticalLayout()) {
|
if (isVerticalLayout) {
|
||||||
TopBar {
|
TopBar {
|
||||||
IconCard(onClick = { showPassesDialog() }, iconId = R.drawable.ic_filter)
|
IconCard(action = { showPassesDialog() }, resId = R.drawable.ic_filter)
|
||||||
TimerRow(timeString = uiState.nextTime, isTimeAos = uiState.isNextTimeAos)
|
TimerRow(timeString = uiState.nextTime, isTimeAos = uiState.isNextTimeAos)
|
||||||
IconCard(onClick = { showRadiosDialog() }, iconId = R.drawable.ic_satellite)
|
IconCard(action = { showRadiosDialog() }, resId = R.drawable.ic_satellite)
|
||||||
}
|
}
|
||||||
NextPassRow(pass = uiState.nextPass)
|
NextPassRow(pass = uiState.nextPass)
|
||||||
} else {
|
} else {
|
||||||
TopBar {
|
TopBar {
|
||||||
IconCard(onClick = { showPassesDialog() }, iconId = R.drawable.ic_filter)
|
IconCard(action = { showPassesDialog() }, resId = R.drawable.ic_filter)
|
||||||
TimerRow(timeString = uiState.nextTime, isTimeAos = uiState.isNextTimeAos)
|
TimerRow(timeString = uiState.nextTime, isTimeAos = uiState.isNextTimeAos)
|
||||||
NextPassRow(pass = uiState.nextPass, modifier = Modifier.weight(1f))
|
NextPassRow(pass = uiState.nextPass, modifier = Modifier.weight(1f))
|
||||||
IconCard(onClick = { showRadiosDialog() }, iconId = R.drawable.ic_satellite)
|
IconCard(action = { showRadiosDialog() }, resId = R.drawable.ic_satellite)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PassesList(uiState.isRefreshing, uiState.itemsList, navigateToRadar, refreshPasses)
|
PassesList(uiState.isRefreshing, uiState.itemsList, navActions.openRadar, refreshList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PassesFloatingBar(navActions: NavActions) {
|
||||||
|
FloatingBar(
|
||||||
|
startAction = navActions.openSettings, startIconResId = R.drawable.ic_settings,
|
||||||
|
centerAction = navActions.openSatellites, centerIconResId = R.drawable.ic_sputnik,
|
||||||
|
endAction = navActions.openMap, endIconResId = R.drawable.ic_map
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun PassesList(
|
private fun PassesList(
|
||||||
|
|||||||
@@ -84,17 +84,17 @@ private fun RadarScreen(uiState: RadarState, navigateUp: () -> Unit) {
|
|||||||
Column(modifier = Modifier.layoutPadding(), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
Column(modifier = Modifier.layoutPadding(), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
if (isVerticalLayout()) {
|
if (isVerticalLayout()) {
|
||||||
TopBar {
|
TopBar {
|
||||||
IconCard(onClick = navigateUp, iconId = R.drawable.ic_back)
|
IconCard(action = navigateUp, resId = R.drawable.ic_back)
|
||||||
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isCurrentTimeAos)
|
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isCurrentTimeAos)
|
||||||
IconCard(onClick = addToCalendar, iconId = R.drawable.ic_calendar)
|
IconCard(action = addToCalendar, resId = R.drawable.ic_calendar)
|
||||||
}
|
}
|
||||||
NextPassRow(pass = upcomingPass)
|
NextPassRow(pass = upcomingPass)
|
||||||
} else {
|
} else {
|
||||||
TopBar {
|
TopBar {
|
||||||
IconCard(onClick = navigateUp, iconId = R.drawable.ic_back)
|
IconCard(action = navigateUp, resId = R.drawable.ic_back)
|
||||||
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isCurrentTimeAos)
|
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isCurrentTimeAos)
|
||||||
NextPassRow(pass = upcomingPass, modifier = Modifier.weight(1f))
|
NextPassRow(pass = upcomingPass, modifier = Modifier.weight(1f))
|
||||||
IconCard(onClick = addToCalendar, iconId = R.drawable.ic_calendar)
|
IconCard(action = addToCalendar, resId = R.drawable.ic_calendar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(isVerticalLayout()) {
|
if(isVerticalLayout()) {
|
||||||
|
|||||||
@@ -92,16 +92,16 @@ private fun SatellitesScreen(uiState: SatellitesState, navigateUp: () -> Unit) {
|
|||||||
}
|
}
|
||||||
TopBar {
|
TopBar {
|
||||||
SearchBar(setQuery = { setQuery(it) }, modifier = Modifier.weight(1f))
|
SearchBar(setQuery = { setQuery(it) }, modifier = Modifier.weight(1f))
|
||||||
IconCard(onClick = unselectAll, iconId = R.drawable.ic_check_off)
|
IconCard(action = unselectAll, resId = R.drawable.ic_check_off)
|
||||||
IconCard(onClick = selectAll, iconId = R.drawable.ic_check_on)
|
IconCard(action = selectAll, resId = R.drawable.ic_check_on)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TopBar {
|
TopBar {
|
||||||
SaveButton(saveSelection = saveSelection, modifier = Modifier.height(48.dp))
|
SaveButton(saveSelection = saveSelection, modifier = Modifier.height(48.dp))
|
||||||
TypeCard(types = uiState.currentTypes, toggleDialog, modifier = Modifier.weight(1f))
|
TypeCard(types = uiState.currentTypes, toggleDialog, modifier = Modifier.weight(1f))
|
||||||
SearchBar(setQuery = { setQuery(it) }, modifier = Modifier.weight(1f))
|
SearchBar(setQuery = { setQuery(it) }, modifier = Modifier.weight(1f))
|
||||||
IconCard(onClick = unselectAll, iconId = R.drawable.ic_check_off)
|
IconCard(action = unselectAll, resId = R.drawable.ic_check_off)
|
||||||
IconCard(onClick = selectAll, iconId = R.drawable.ic_check_on)
|
IconCard(action = selectAll, resId = R.drawable.ic_check_on)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import java.text.SimpleDateFormat
|
|||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
fun NavGraphBuilder.settingsDestination() {
|
fun NavGraphBuilder.settingsDestination(function: () -> Boolean) {
|
||||||
composable(Screen.Settings.route) {
|
composable(Screen.Settings.route) {
|
||||||
val viewModel = viewModel(
|
val viewModel = viewModel(
|
||||||
modelClass = SettingsViewModel::class.java,
|
modelClass = SettingsViewModel::class.java,
|
||||||
@@ -348,7 +348,7 @@ private fun DataCard(
|
|||||||
Spacer(modifier = Modifier.width(6.dp))
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
CardButton(
|
CardButton(
|
||||||
onClick = { updateFromFile() },
|
onClick = { updateFromFile() },
|
||||||
text = stringResource(id = R.string.btn_file),
|
text = stringResource(id = R.string.btn_import),
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(6.dp))
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<style name="Theme.Look4Sat.SplashScreen" parent="Theme.SplashScreen">
|
|
||||||
<item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
|
|
||||||
<item name="postSplashScreenTheme">@style/Theme.Look4Sat.Main</item>
|
|
||||||
<item name="windowSplashScreenBackground">@color/background</item>
|
|
||||||
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_splash</item>
|
|
||||||
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="Theme.Look4Sat.Main" parent="Theme.Material3.Dark.NoActionBar">
|
|
||||||
<item name="colorAccent">@color/accent</item>
|
|
||||||
<item name="colorControlNormal">@color/textMain</item>
|
|
||||||
<item name="colorPrimary">@color/accent</item>
|
|
||||||
<item name="colorSecondary">@color/accent</item>
|
|
||||||
<item name="colorOnPrimaryContainer">@color/background</item>
|
|
||||||
<item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
|
|
||||||
<item name="android:listDivider">@drawable/item_divider</item>
|
|
||||||
<item name="android:navigationBarColor">@color/background</item>
|
|
||||||
<item name="android:textColorPrimary">@color/textMain</item>
|
|
||||||
<item name="android:statusBarColor">@color/background</item>
|
|
||||||
<item name="android:windowBackground">@color/background</item>
|
|
||||||
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
android-gradle-plugin = "8.12.1"
|
android-gradle-plugin = "8.12.2"
|
||||||
google-ksp = "2.2.10-2.0.2"
|
google-ksp = "2.2.10-2.0.2"
|
||||||
kotlin = "2.2.10"
|
kotlin = "2.2.10"
|
||||||
|
|
||||||
@@ -7,9 +7,9 @@ androidx-core-ktx = "1.17.0"
|
|||||||
androidx-core-splashscreen = "1.0.1"
|
androidx-core-splashscreen = "1.0.1"
|
||||||
androidx-room = "2.7.2"
|
androidx-room = "2.7.2"
|
||||||
|
|
||||||
compose-bom = "2025.08.00"
|
compose-bom = "2025.08.01"
|
||||||
compose-activity = "1.10.1"
|
compose-activity = "1.10.1"
|
||||||
compose-lifecycle = "2.9.2"
|
compose-lifecycle = "2.9.3"
|
||||||
compose-navigation = "2.9.3"
|
compose-navigation = "2.9.3"
|
||||||
|
|
||||||
other-coroutines = "1.10.2"
|
other-coroutines = "1.10.2"
|
||||||
@@ -33,7 +33,7 @@ androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "
|
|||||||
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
|
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
|
||||||
compose-animation = { group = "androidx.compose.animation", name = "animation" }
|
compose-animation = { group = "androidx.compose.animation", name = "animation" }
|
||||||
compose-material3 = { group = "androidx.compose.material3", name = "material3" }
|
compose-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
compose-material3-navigation = { group = "androidx.compose.material3", name = "material3-adaptive-navigation-suite" }
|
compose-material3-adaptive = { group = "androidx.compose.material3.adaptive", name = "adaptive" }
|
||||||
compose-runtime = { group = "androidx.compose.runtime", name = "runtime" }
|
compose-runtime = { group = "androidx.compose.runtime", name = "runtime" }
|
||||||
compose-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
compose-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
|||||||
[bundles]
|
[bundles]
|
||||||
composeAll = [
|
composeAll = [
|
||||||
"compose-animation", "compose-runtime", "compose-tooling", "compose-activity",
|
"compose-animation", "compose-runtime", "compose-tooling", "compose-activity",
|
||||||
"compose-lifecycle", "compose-material3", "compose-material3-navigation",
|
"compose-lifecycle", "compose-material3", "compose-material3-adaptive",
|
||||||
"compose-navigation", "compose-viewmodel"
|
"compose-navigation", "compose-viewmodel"
|
||||||
]
|
]
|
||||||
composeDebug = ["compose-debug-manifest", "compose-debug-tooling"]
|
composeDebug = ["compose-debug-manifest", "compose-debug-tooling"]
|
||||||
|
|||||||
Reference in new issue
Block a user