Added more tweaks to components and dependencies

This commit is contained in:
Arty Bishop committed 2025-12-27 15:02:14 +00:00
1 parent fb8053ef60
commit 266fbfed1f
7 files changed
+135 -90

No files matched your search

@@ -1,9 +1,6 @@
package com.rtbishop.look4sat.presentation
import androidx.compose.foundation.background
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
@@ -39,11 +36,7 @@ fun MainScreen(navController: NavHostController = rememberNavController()) {
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)
) {
NavHost(navController = navController, startDestination = Screen.Passes.route) {
satellitesDestination { navController.navigateUp() }
passesDestination(navActions)
radarDestination { navController.navigateUp() }
@@ -1,9 +1,12 @@
package com.rtbishop.look4sat.presentation.common
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.MarqueeSpacing
import androidx.compose.foundation.background
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -18,12 +21,15 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
@@ -98,17 +104,17 @@ fun RowScope.TimerRow(timeString: String, isTimeAos: Boolean) {
@Composable
@Preview(showBackground = true)
private fun NextPassRowPreview() = MainTheme {
NextPassRow(pass = getDefaultPass())
TopBar { NextPassRow(pass = getDefaultPass()) }
}
@Composable
fun NextPassRow(pass: OrbitalPass, modifier: Modifier = Modifier) {
ElevatedCard(modifier = modifier.height(48.dp)) {
fun RowScope.NextPassRow(pass: OrbitalPass, modifier: Modifier = Modifier) {
ElevatedCard(modifier = modifier.height(48.dp).weight(1f)) {
Column(
verticalArrangement = Arrangement.spacedBy((-2).dp),
modifier = Modifier
.fillMaxSize()
.background(color = MaterialTheme.colorScheme.surface)
// .background(color = MaterialTheme.colorScheme.background)
.padding(start = 6.dp, top = 1.dp, end = 6.dp, bottom = 0.dp)
) {
val passSatId = stringResource(id = R.string.pass_satId, pass.catNum)
@@ -319,58 +325,86 @@ fun Modifier.layoutPadding(): Modifier {
}
@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 PrimaryButton(action: () -> Unit, resId: Int, modifier: Modifier = Modifier) {
val clickableMod = modifier.clickable { action() }
val colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primary)
ElevatedCard(modifier = Modifier.size(96.dp, 48.dp), colors = colors, shape = MaterialTheme.shapes.large) {
Box(modifier = clickableMod.fillMaxSize(), contentAlignment = Alignment.Center) {
Icon(painter = painterResource(resId), contentDescription = null)
fun ScreenColumn(
topBar: @Composable (Boolean) -> Unit = {},
floatingBar: @Composable () -> Unit = {},
content: @Composable (Boolean) -> Unit = {}
) {
val surfaceCorners = LocalSpacing.current.large
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
val isVerticalLayout = windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT
Surface(color = MaterialTheme.colorScheme.background) {
Box(modifier = Modifier.layoutPadding(), contentAlignment = Alignment.BottomCenter) {
Column(verticalArrangement = Arrangement.spacedBy(LocalSpacing.current.extraSmall)) {
topBar(isVerticalLayout)
Surface(
modifier = Modifier.fillMaxSize(),
shape = RoundedCornerShape(topStart = surfaceCorners, topEnd = surfaceCorners),
color = MaterialTheme.colorScheme.surfaceContainer
) { content(isVerticalLayout) }
}
floatingBar()
}
}
}
@Composable
fun SecondaryButton(action: () -> Unit, resId: Int, modifier: Modifier = Modifier) {
val clickableMod = modifier.clickable { action() }
ElevatedCard(modifier = Modifier.size(48.dp), shape = MaterialTheme.shapes.large) {
Box(modifier = clickableMod.fillMaxSize(), contentAlignment = Alignment.Center) {
Icon(painter = painterResource(resId), contentDescription = null)
}
fun TopBar(
isVerticalLayout: Boolean,
startAction: @Composable () -> Unit,
topInfo: @Composable (RowScope.() -> Unit),
bottomInfo: @Composable (RowScope.() -> Unit),
endAction: @Composable () -> Unit
) {
val topBarRow = @Composable { content: @Composable RowScope.() -> Unit ->
Row(
modifier = Modifier.height(48.dp),
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalAlignment = Alignment.CenterVertically
) { content() }
}
if (isVerticalLayout) {
topBarRow { startAction().also { topInfo() }.also { endAction() } }
topBarRow { bottomInfo() }
} else {
topBarRow { startAction().also { topInfo() }.also { bottomInfo() }.also { endAction() } }
}
}
@Composable
fun FloatingBar(
startAction: () -> Unit, startIconResId: Int,
centerAction: () -> Unit, centerIconResId: Int,
endAction: () -> Unit, endIconResId: Int
visible: Boolean,
startAction: @Composable () -> Unit,
centerAction: @Composable () -> Unit,
endAction: @Composable () -> Unit
) {
val spacing = LocalSpacing.current
Surface(
color = MaterialTheme.colorScheme.background,
shape = MaterialTheme.shapes.extraLarge,
modifier = Modifier.padding(bottom = spacing.medium)
.border(width = 1.dp, color = MaterialTheme.colorScheme.surfaceVariant, shape = MaterialTheme.shapes.extraLarge)
) {
Row(
horizontalArrangement = Arrangement.spacedBy(spacing.medium),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(horizontal = spacing.large, vertical = spacing.medium)
AnimatedVisibility(visible = visible, enter = fadeIn(tween(250)), exit = fadeOut(tween(250))) {
Surface(
modifier = Modifier.padding(bottom = spacing.large),
shape = CircleShape,
color = MaterialTheme.colorScheme.background,
border = BorderStroke(width = 1.dp, color = MaterialTheme.colorScheme.surfaceVariant)
) {
SecondaryButton(action = startAction, resId = startIconResId)
PrimaryButton(action = centerAction, resId = centerIconResId)
SecondaryButton(action = endAction, resId = endIconResId)
Row(
modifier = Modifier.padding(horizontal = spacing.medium, vertical = spacing.small),
horizontalArrangement = Arrangement.spacedBy(spacing.extraSmall),
verticalAlignment = Alignment.CenterVertically
) { startAction().also { centerAction() }.also { endAction() } }
}
}
}
@Composable
fun PrimaryAction(action: () -> Unit, resId: Int, descResId: Int) {
FilledIconButton(onClick = action, modifier = Modifier.width(72.dp)) {
Icon(painterResource(resId), stringResource(descResId))
}
}
@Composable
fun SecondaryAction(action: () -> Unit, resId: Int, descResId: Int) {
IconButton(onClick = action) {
Icon(painterResource(resId), stringResource(descResId))
}
}
@@ -114,7 +114,7 @@ private fun MapScreen(uiState: State<MapState>, mapView: MapView) {
TimerRow(timeString = timeString, isTimeAos = isTimeAos)
IconCard(action = selectNext, resId = R.drawable.ic_arrow)
}
NextPassRow(pass = uiState.value.orbitalPass)
TopBar { NextPassRow(pass = uiState.value.orbitalPass) }
} else {
TopBar {
IconCard(action = selectPrev, resId = R.drawable.ic_arrow, modifier = rotateMod)
@@ -1,9 +1,5 @@
package com.rtbishop.look4sat.presentation.passes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
@@ -59,7 +55,9 @@ import com.rtbishop.look4sat.presentation.common.FloatingBar
import com.rtbishop.look4sat.presentation.common.IconCard
import com.rtbishop.look4sat.presentation.common.InfoDialog
import com.rtbishop.look4sat.presentation.common.NextPassRow
import com.rtbishop.look4sat.presentation.common.PrimaryAction
import com.rtbishop.look4sat.presentation.common.ScreenColumn
import com.rtbishop.look4sat.presentation.common.SecondaryAction
import com.rtbishop.look4sat.presentation.common.TimerRow
import com.rtbishop.look4sat.presentation.common.TopBar
import com.rtbishop.look4sat.presentation.common.infiniteMarquee
@@ -88,7 +86,11 @@ private fun PassesScreen(uiState: PassesState, navActions: NavActions) {
val showPassesDialog = { uiState.takeAction(PassesAction.TogglePassesDialog) }
val showRadiosDialog = { uiState.takeAction(PassesAction.ToggleRadiosDialog) }
if (uiState.isPassesDialogShown) {
PassesDialog(hours = uiState.hours, elevation = uiState.elevation, cancel = showPassesDialog) { hours, elevation ->
PassesDialog(
hours = uiState.hours,
elevation = uiState.elevation,
cancel = showPassesDialog
) { hours, elevation ->
uiState.takeAction(PassesAction.FilterPasses(hours, elevation))
}
}
@@ -107,36 +109,51 @@ private fun PassesScreen(uiState: PassesState, navActions: NavActions) {
}
val gridState = rememberLazyGridState()
ScreenColumn(
floatingBar = { PassesFloatingBar(gridState.isScrolling(), navActions) }
) { isVerticalLayout ->
if (isVerticalLayout) {
TopBar {
IconCard(action = { showPassesDialog() }, resId = R.drawable.ic_filter)
TimerRow(timeString = uiState.nextTime, isTimeAos = uiState.isNextTimeAos)
IconCard(action = { showRadiosDialog() }, resId = R.drawable.ic_satellite)
}
NextPassRow(pass = uiState.nextPass)
} else {
TopBar {
IconCard(action = { showPassesDialog() }, resId = R.drawable.ic_filter)
TimerRow(timeString = uiState.nextTime, isTimeAos = uiState.isNextTimeAos)
NextPassRow(pass = uiState.nextPass, modifier = Modifier.weight(1f))
IconCard(action = { showRadiosDialog() }, resId = R.drawable.ic_satellite)
}
topBar = { isVerticalLayout ->
TopBar(
isVerticalLayout = isVerticalLayout,
startAction = {
IconCard(action = showPassesDialog, resId = R.drawable.ic_filter)
},
topInfo = {
TimerRow(timeString = uiState.nextTime, isTimeAos = uiState.isNextTimeAos)
},
bottomInfo = {
NextPassRow(pass = uiState.nextPass)
},
endAction = {
IconCard(action = showRadiosDialog, resId = R.drawable.ic_satellite)
}
)
},
floatingBar = {
PassesFloatingBar(visible = gridState.isScrolling(), actions = navActions)
}
PassesList(uiState.isRefreshing, uiState.itemsList, navActions.openRadar, refreshList, gridState)
) { isVerticalLayout ->
PassesList(
isRefreshing = uiState.isRefreshing,
passes = uiState.itemsList,
navigateToRadar = navActions.openRadar,
refreshPasses = refreshList,
gridState = gridState
)
}
}
@Composable
private fun PassesFloatingBar(visible: Boolean, navActions: NavActions) {
AnimatedVisibility(visible = visible, enter = fadeIn(tween(250)), exit = fadeOut(tween(250))) {
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
)
}
private fun PassesFloatingBar(visible: Boolean, actions: NavActions) {
FloatingBar(
visible = visible,
startAction = {
SecondaryAction(actions.openSettings, R.drawable.ic_settings, R.string.btn_settings)
},
centerAction = {
PrimaryAction(actions.openSatellites, R.drawable.ic_sputnik, R.string.btn_satellites)
},
endAction = {
SecondaryAction(actions.openMap, R.drawable.ic_map, R.string.btn_map)
}
)
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -88,7 +88,7 @@ private fun RadarScreen(uiState: RadarState, navigateUp: () -> Unit) {
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isCurrentTimeAos)
IconCard(action = addToCalendar, resId = R.drawable.ic_calendar)
}
NextPassRow(pass = upcomingPass)
TopBar { NextPassRow(pass = upcomingPass) }
} else {
TopBar {
IconCard(action = navigateUp, resId = R.drawable.ic_back)