Migrated to Compose Navigation3, updated dependencies

This commit is contained in:
Arty Bishop committed 2026-04-24 17:20:23 +01:00
1 parent fb2cd85b11
commit 7d5bca300d
14 files changed
+252 -220

No files matched your search

@@ -60,15 +60,12 @@ import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.rtbishop.look4sat.core.domain.predict.GeoPos
import com.rtbishop.look4sat.core.domain.predict.OrbitalObject
import com.rtbishop.look4sat.core.domain.predict.OrbitalPos
import com.rtbishop.look4sat.core.presentation.IconCard
import com.rtbishop.look4sat.core.presentation.NextPassRow
import com.rtbishop.look4sat.core.presentation.R
import com.rtbishop.look4sat.core.presentation.Screen
import com.rtbishop.look4sat.core.presentation.TimerRow
import com.rtbishop.look4sat.core.presentation.TopBar
import com.rtbishop.look4sat.core.presentation.isVerticalLayout
@@ -110,13 +107,15 @@ private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
}
private val iconCache = LruCache<String, Drawable>(128)
fun NavGraphBuilder.mapDestination() {
composable(Screen.Map.route) {
val viewModel = viewModel(MapViewModel::class.java, factory = MapViewModel.Factory)
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val mapView = rememberMapViewWithLifecycle()
MapScreen(uiState, viewModel::onAction, mapView)
}
@Composable
fun MapDestination() {
val viewModel = viewModel(
modelClass = MapViewModel::class.java,
factory = MapViewModel.Factory
)
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val mapView = rememberMapViewWithLifecycle()
MapScreen(uiState, viewModel::onAction, mapView)
}
@Composable
@@ -56,8 +56,6 @@ 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.core.domain.predict.DeepSpaceObject
import com.rtbishop.look4sat.core.domain.predict.NearEarthObject
import com.rtbishop.look4sat.core.domain.predict.OrbitalData
@@ -68,7 +66,6 @@ import com.rtbishop.look4sat.core.presentation.InfoDialog
import com.rtbishop.look4sat.core.presentation.MainTheme
import com.rtbishop.look4sat.core.presentation.NextPassRow
import com.rtbishop.look4sat.core.presentation.R
import com.rtbishop.look4sat.core.presentation.Screen
import com.rtbishop.look4sat.core.presentation.ScreenColumn
import com.rtbishop.look4sat.core.presentation.TimerRow
import com.rtbishop.look4sat.core.presentation.TopBar
@@ -79,15 +76,14 @@ import java.util.Date
import java.util.Locale
import java.util.TimeZone
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.collectAsStateWithLifecycle().value
PassesScreen(uiState, viewModel::onAction, navigateToRadar)
}
@Composable
fun PassesDestination(navigateToRadar: (Int, Long) -> Unit) {
val viewModel = viewModel(
modelClass = PassesViewModel::class.java,
factory = PassesViewModel.Factory
)
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
PassesScreen(uiState, viewModel::onAction, navigateToRadar)
}
@Composable
@@ -42,6 +42,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -58,9 +59,6 @@ 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 androidx.navigation.navArgument
import com.rtbishop.look4sat.core.domain.model.SatRadio
import com.rtbishop.look4sat.core.domain.predict.OrbitalPos
import com.rtbishop.look4sat.core.domain.utility.toDegrees
@@ -69,7 +67,6 @@ import com.rtbishop.look4sat.core.presentation.IconCard
import com.rtbishop.look4sat.core.presentation.MainTheme
import com.rtbishop.look4sat.core.presentation.NextPassRow
import com.rtbishop.look4sat.core.presentation.R
import com.rtbishop.look4sat.core.presentation.Screen
import com.rtbishop.look4sat.core.presentation.TimerRow
import com.rtbishop.look4sat.core.presentation.TopBar
import com.rtbishop.look4sat.core.presentation.getDefaultPass
@@ -77,20 +74,20 @@ import com.rtbishop.look4sat.core.presentation.infiniteMarquee
import com.rtbishop.look4sat.core.presentation.isVerticalLayout
import com.rtbishop.look4sat.core.presentation.layoutPadding
fun NavGraphBuilder.radarDestination(
@Composable
fun RadarDestination(
catNum: Int = 0,
aosTime: Long = 0L,
navigateUp: () -> Unit,
navigateToRadioControl: (Int, Long) -> Unit = { _, _ -> }
) {
val radarRoute = "${Screen.Radar.route}?catNum={catNum}&aosTime={aosTime}"
val radarArgs = listOf(
navArgument("catNum") { defaultValue = 0 },
navArgument("aosTime") { defaultValue = 0L }
val viewModel = viewModel(
modelClass = RadarViewModel::class.java,
key = "$catNum-$aosTime",
factory = RadarViewModel.factory(catNum, aosTime)
)
composable(radarRoute, radarArgs) {
val viewModel = viewModel(RadarViewModel::class.java, factory = RadarViewModel.Factory)
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
RadarScreen(uiState, viewModel::onAction, navigateUp, navigateToRadioControl)
}
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
RadarScreen(uiState, viewModel::onAction, navigateUp, navigateToRadioControl)
}
@Composable
@@ -101,7 +98,7 @@ private fun RadarScreen(
navigateToRadioControl: (Int, Long) -> Unit
) {
val upcomingPass = uiState.currentPass ?: getDefaultPass()
if (upcomingPass.losTime < System.currentTimeMillis()) navigateUp()
LaunchedEffect(uiState.isLos) { if (uiState.isLos) navigateUp() }
val addToCalendar: () -> Unit = {
uiState.currentPass?.let { pass ->
@@ -123,14 +120,14 @@ private fun RadarScreen(
if (isVertical) {
TopBar {
IconCard(action = addToCalendar, resId = R.drawable.ic_calendar)
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isCurrentTimeAos)
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isTimeAos)
IconCard(action = openRadioControl, resId = R.drawable.ic_radios)
}
TopBar { NextPassRow(pass = upcomingPass, isUtc = uiState.isUtc) }
} else {
TopBar {
IconCard(action = addToCalendar, resId = R.drawable.ic_calendar)
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isCurrentTimeAos)
TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isTimeAos)
NextPassRow(pass = upcomingPass, modifier = Modifier.weight(1f), isUtc = uiState.isUtc)
IconCard(action = openRadioControl, resId = R.drawable.ic_radios)
}
@@ -24,7 +24,8 @@ import com.rtbishop.look4sat.core.domain.predict.OrbitalPos
data class RadarState(
val currentPass: OrbitalPass? = null,
val currentTime: String = "00:00:00",
val isCurrentTimeAos: Boolean = true,
val isTimeAos: Boolean = true,
val isLos: Boolean = false,
val isUtc: Boolean = false,
val orientationValues: Pair<Float, Float> = 0f to 0f,
val orbitalPos: OrbitalPos? = null,
@@ -17,10 +17,8 @@
*/
package com.rtbishop.look4sat.feature.radar
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
@@ -45,7 +43,8 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
class RadarViewModel(
private val savedStateHandle: SavedStateHandle,
private val catNum: Int,
private val aosTime: Long,
private val bluetoothReporter: IReporter,
private val networkReporter: IReporter,
private val satelliteRepo: ISatelliteRepo,
@@ -85,8 +84,6 @@ class RadarViewModel(
}
// Resolve which pass we're tracking and start the tick loop
viewModelScope.launch {
val catNum = savedStateHandle.get<Int>("catNum") ?: 0
val aosTime = savedStateHandle.get<Long>("aosTime") ?: 0L
val passes = satelliteRepo.passes.value
val currentPass = passes.find { it.catNum == catNum && it.aosTime == aosTime }
?: passes.firstOrNull()
@@ -105,7 +102,8 @@ class RadarViewModel(
val timeNow = System.currentTimeMillis()
val pos = satelliteRepo.getPosition(satPass.orbitalObject, stationPos, timeNow)
val (time, isAos) = computeTimer(satPass.isDeepSpace, satPass.aosTime, satPass.losTime, timeNow)
_uiState.update { it.copy(currentTime = time, isCurrentTimeAos = isAos, orbitalPos = pos) }
val isLos = !satPass.isDeepSpace && timeNow > satPass.losTime
_uiState.update { it.copy(currentTime = time, isTimeAos = isAos, isLos = isLos, orbitalPos = pos) }
processRadios(transmitters, satPass.orbitalObject, timeNow)
sendPassData(pos)
delay(1000)
@@ -204,18 +202,19 @@ class RadarViewModel(
}
companion object {
val Factory: ViewModelProvider.Factory = viewModelFactory {
fun factory(catNum: Int, aosTime: Long): ViewModelProvider.Factory = viewModelFactory {
val applicationKey = ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY
initializer {
val container = (this[applicationKey] as IContainerProvider).getMainContainer()
RadarViewModel(
createSavedStateHandle(),
container.provideBluetoothReporter(),
container.provideNetworkReporter(),
container.satelliteRepo,
container.settingsRepo,
container.provideSensorsRepo(),
container.provideAddToCalendar()
catNum = catNum,
aosTime = aosTime,
bluetoothReporter = container.provideBluetoothReporter(),
networkReporter = container.provideNetworkReporter(),
satelliteRepo = container.satelliteRepo,
settingsRepo = container.settingsRepo,
sensorsRepo = container.provideSensorsRepo(),
addToCalendar = container.provideAddToCalendar()
)
}
}
@@ -51,15 +51,11 @@ 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 androidx.navigation.navArgument
import com.rtbishop.look4sat.core.domain.model.SatRadio
import com.rtbishop.look4sat.core.presentation.CardButton
import com.rtbishop.look4sat.core.presentation.IconCard
import com.rtbishop.look4sat.core.presentation.NextPassRow
import com.rtbishop.look4sat.core.presentation.R
import com.rtbishop.look4sat.core.presentation.Screen
import com.rtbishop.look4sat.core.presentation.TimerRow
import com.rtbishop.look4sat.core.presentation.TopBar
import com.rtbishop.look4sat.core.presentation.getDefaultPass
@@ -67,17 +63,15 @@ import com.rtbishop.look4sat.core.presentation.isVerticalLayout
import com.rtbishop.look4sat.core.presentation.layoutPadding
import java.util.Locale
fun NavGraphBuilder.radioControlDestination(navigateUp: () -> Unit) {
val route = "${Screen.RadioControl.route}?catNum={catNum}&aosTime={aosTime}"
val args = listOf(
navArgument("catNum") { defaultValue = 0 },
navArgument("aosTime") { defaultValue = 0L }
@Composable
fun RadioControlDestination(catNum: Int = 0, aosTime: Long = 0L, navigateUp: () -> Unit) {
val viewModel = viewModel(
modelClass = RadioControlViewModel::class.java,
key = "$catNum-$aosTime",
factory = RadioControlViewModel.factory(catNum, aosTime)
)
composable(route, args) {
val viewModel = viewModel(RadioControlViewModel::class.java, factory = RadioControlViewModel.Factory)
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
RadioControlScreen(uiState, viewModel::onAction, navigateUp)
}
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
RadioControlScreen(uiState, viewModel::onAction, navigateUp)
}
@Composable
@@ -17,10 +17,8 @@
*/
package com.rtbishop.look4sat.feature.radiocontrol
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
@@ -41,7 +39,8 @@ import kotlinx.coroutines.launch
import java.util.Locale
class RadioControlViewModel(
savedStateHandle: SavedStateHandle,
private val catNum: Int,
private val aosTime: Long,
private val trackingService: IRadioTrackingService,
private val satelliteRepo: ISatelliteRepo,
settingsRepo: ISettingsRepo
@@ -72,9 +71,6 @@ class RadioControlViewModel(
val uiState: StateFlow<RadioControlState> = _uiState
init {
val catNum = savedStateHandle.get<Int>("catNum") ?: 0
val aosTime = savedStateHandle.get<Long>("aosTime") ?: 0L
// Resolve pass and load transponders
viewModelScope.launch {
val passes = satelliteRepo.passes.value
@@ -190,15 +186,16 @@ class RadioControlViewModel(
return String.format(Locale.ENGLISH, "%d.%03d.%03d", mhz, khz, hz)
}
val Factory: ViewModelProvider.Factory = viewModelFactory {
fun factory(catNum: Int, aosTime: Long): ViewModelProvider.Factory = viewModelFactory {
val applicationKey = ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY
initializer {
val container = (this[applicationKey] as IContainerProvider).getMainContainer()
RadioControlViewModel(
createSavedStateHandle(),
container.radioTrackingService,
container.satelliteRepo,
container.settingsRepo
catNum = catNum,
aosTime = aosTime,
trackingService = container.radioTrackingService,
satelliteRepo = container.satelliteRepo,
settingsRepo = container.settingsRepo
)
}
}
@@ -56,8 +56,6 @@ 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.core.domain.model.SatItem
import com.rtbishop.look4sat.core.presentation.CardLoadingIndicator
import com.rtbishop.look4sat.core.presentation.EmptyListCard
@@ -66,20 +64,19 @@ import com.rtbishop.look4sat.core.presentation.InfoDialog
import com.rtbishop.look4sat.core.presentation.MainTheme
import com.rtbishop.look4sat.core.presentation.PrimaryIconCard
import com.rtbishop.look4sat.core.presentation.R
import com.rtbishop.look4sat.core.presentation.Screen
import com.rtbishop.look4sat.core.presentation.TopBar
import com.rtbishop.look4sat.core.presentation.infiniteMarquee
import com.rtbishop.look4sat.core.presentation.isVerticalLayout
import com.rtbishop.look4sat.core.presentation.layoutPadding
fun NavGraphBuilder.satellitesDestination(navigateUp: () -> Unit) {
composable(Screen.Satellites.route) {
val viewModel = viewModel(
modelClass = SatellitesViewModel::class.java, factory = SatellitesViewModel.Factory
)
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
SatellitesScreen(uiState, viewModel::onAction, navigateUp)
}
@Composable
fun SatellitesDestination(navigateUp: () -> Unit) {
val viewModel = viewModel(
modelClass = SatellitesViewModel::class.java,
factory = SatellitesViewModel.Factory
)
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
SatellitesScreen(uiState, viewModel::onAction, navigateUp)
}
@Composable
@@ -60,8 +60,6 @@ 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.core.domain.model.OtherSettings
import com.rtbishop.look4sat.core.domain.predict.GeoPos
import com.rtbishop.look4sat.core.presentation.CardButton
@@ -69,7 +67,6 @@ import com.rtbishop.look4sat.core.presentation.IconCard
import com.rtbishop.look4sat.core.presentation.MainTheme
import com.rtbishop.look4sat.core.presentation.PrimaryIconCard
import com.rtbishop.look4sat.core.presentation.R
import com.rtbishop.look4sat.core.presentation.Screen
import com.rtbishop.look4sat.core.presentation.ScreenColumn
import com.rtbishop.look4sat.core.presentation.TopBar
import com.rtbishop.look4sat.core.presentation.infiniteMarquee
@@ -78,15 +75,14 @@ import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
fun NavGraphBuilder.settingsDestination() {
composable(Screen.Settings.route) {
val viewModel = viewModel(
modelClass = SettingsViewModel::class.java,
factory = SettingsViewModel.Factory
)
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
SettingsScreen(uiState, viewModel::onAction)
}
@Composable
fun SettingsDestination() {
val viewModel = viewModel(
modelClass = SettingsViewModel::class.java,
factory = SettingsViewModel.Factory
)
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
SettingsScreen(uiState, viewModel::onAction)
}
@Composable