mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Added more tweaks to components and dependencies
This commit is contained in:
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)
|
||||
|
||||
@@ -5,16 +5,16 @@ kotlin = "2.2.20"
|
||||
|
||||
androidx-core-ktx = "1.17.0"
|
||||
androidx-core-splashscreen = "1.0.1"
|
||||
androidx-room = "2.8.1"
|
||||
androidx-room = "2.8.2"
|
||||
|
||||
compose-bom = "2025.09.01"
|
||||
compose-bom = "2025.10.00"
|
||||
compose-activity = "1.11.0"
|
||||
compose-lifecycle = "2.9.4"
|
||||
compose-navigation = "2.9.5"
|
||||
|
||||
other-coroutines = "1.10.2"
|
||||
other-json = "20250517"
|
||||
other-okhttp = "5.1.0"
|
||||
other-okhttp = "5.2.1"
|
||||
other-osmdroid = "6.1.20"
|
||||
|
||||
test-junit4 = "4.13.2"
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#Sat Oct 11 13:47:56 BST 2025
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
Reference in new issue
Block a user