Added Selection Warning and App Welcome Dialogs

This commit is contained in:
Arty Bishop committed 2025-12-27 15:01:47 +00:00
1 parent fcec36ec68
commit bffb4842b1
13 files changed
+122 -19

No files matched your search

@@ -229,7 +229,7 @@ fun gotoUrl(context: Context, url: String) {
}
fun getDefaultPass(): OrbitalPass {
val orbitalData = OrbitalData("Next Satellite", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0)
val orbitalData = OrbitalData("No Future Passes", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0)
val satellite = NearEarthObject(orbitalData)
return OrbitalPass(0L, 0.0, 0L, 0.0, 0, 0.0, satellite, 0f)
}
@@ -248,6 +248,7 @@ fun SharedDialog(
Text(
text = title,
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(start = padding, top = padding, end = padding)
)
@@ -262,6 +263,33 @@ fun SharedDialog(
}
}
//fun Modifier.onClick(onClick: () -> Unit): Modifier = composed {
// clickable(remember { MutableInteractionSource() }, null) { onClick() }
//}
@Composable
fun InfoDialog(title: String, text: String, onDismiss: () -> Unit) {
val padding = LocalSpacing.current.extraLarge
Dialog(onDismissRequest = onDismiss) {
ElevatedCard {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(padding)
) {
Text(
text = title,
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(start = padding, top = padding, end = padding)
)
Text(
text = text,
fontSize = 16.sp,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.padding(horizontal = padding)
)
Row(modifier = Modifier.padding(start = padding, bottom = padding, end = padding)) {
Spacer(modifier = Modifier.weight(1f))
CardButton(onClick = onDismiss, text = stringResource(id = R.string.btn_understand))
}
}
}
}
}
@@ -45,6 +45,7 @@ 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.InfoDialog
import com.rtbishop.look4sat.presentation.components.NextPassRow
import com.rtbishop.look4sat.presentation.components.TimerBar
import com.rtbishop.look4sat.presentation.components.TimerRow
@@ -81,6 +82,14 @@ private fun PassesScreen(uiState: PassesState, navigateToRadar: (Int, Long) -> U
uiState.takeAction(PassesAction.FilterRadios(modes))
}
}
if (uiState.shouldSeeWelcome) {
InfoDialog(
stringResource(R.string.passes_welcome_title),
stringResource(R.string.passes_welcome_message)
) {
uiState.takeAction(PassesAction.DismissWelcome)
}
}
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
TimerRow {
CardIcon(onClick = { showPassesDialog() }, iconId = R.drawable.ic_filter)
@@ -14,10 +14,12 @@ data class PassesState(
val elevation: Double,
val modes: List<String>,
val itemsList: List<OrbitalPass>,
val shouldSeeWelcome: Boolean,
val takeAction: (PassesAction) -> Unit
)
sealed class PassesAction {
data object DismissWelcome : PassesAction()
data class FilterPasses(val hoursAhead: Int, val minElevation: Double) : PassesAction()
data class FilterRadios(val modes: List<String>) : PassesAction()
data object RefreshPasses : PassesAction()
@@ -34,6 +34,7 @@ import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
@@ -55,6 +56,7 @@ class PassesViewModel(
elevation = settingsRepo.passesSettings.value.minElevation,
modes = settingsRepo.passesSettings.value.selectedModes,
itemsList = emptyList(),
shouldSeeWelcome = settingsRepo.otherSettings.value.shouldSeeWelcome,
takeAction = ::handleAction
)
)
@@ -63,7 +65,7 @@ class PassesViewModel(
init {
viewModelScope.launch {
satelliteRepo.passes.collect { passes ->
satelliteRepo.passes.collectLatest { passes ->
processing?.cancelAndJoin()
processing = viewModelScope.launch {
while (isActive) {
@@ -76,10 +78,16 @@ class PassesViewModel(
}
}
}
viewModelScope.launch {
settingsRepo.otherSettings.collectLatest { settings ->
_uiState.update { it.copy(shouldSeeWelcome = settings.shouldSeeWelcome) }
}
}
}
private fun handleAction(action: PassesAction) {
when (action) {
PassesAction.DismissWelcome -> settingsRepo.setWelcomeDismissed()
is PassesAction.FilterPasses -> applyFilter(action.hoursAhead, action.minElevation, uiState.value.modes)
is PassesAction.FilterRadios -> applyFilter(uiState.value.hours, uiState.value.elevation, action.modes)
PassesAction.RefreshPasses -> refreshPasses()
@@ -159,7 +159,8 @@ private fun RadarScreen(uiState: RadarState, navigateBack: () -> Unit) {
Text(
text = "This satellite doesn't have any known transcievers...",
textAlign = TextAlign.Center,
fontSize = 18.sp
fontSize = 18.sp,
modifier = Modifier.padding(16.dp)
)
}
} else {
@@ -48,6 +48,7 @@ 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
import com.rtbishop.look4sat.presentation.components.InfoDialog
fun NavGraphBuilder.satellitesDestination(navigateToPasses: () -> Unit) {
composable(Screen.Satellites.route) {
@@ -68,6 +69,14 @@ private fun SatellitesScreen(uiState: SatellitesState, navigateToPasses: () -> U
uiState.takeAction(SatellitesAction.SelectTypes(it))
}
}
if (uiState.shouldSeeWarning) {
InfoDialog(
stringResource(R.string.satellites_warning_title),
stringResource(R.string.satellites_warning_message)
) {
uiState.takeAction(SatellitesAction.DismissWarning)
}
}
val unselectAll = { uiState.takeAction(SatellitesAction.UnselectAll) }
val selectAll = { uiState.takeAction(SatellitesAction.SelectAll) }
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
@@ -5,6 +5,7 @@ import com.rtbishop.look4sat.domain.model.SatItem
data class SatellitesState(
val isDialogShown: Boolean,
val isLoading: Boolean,
val shouldSeeWarning: Boolean,
val itemsList: List<SatItem>,
val currentTypes: List<String>,
val typesList: List<String>,
@@ -12,6 +13,7 @@ data class SatellitesState(
)
sealed class SatellitesAction {
data object DismissWarning : SatellitesAction()
data object SaveSelection : SatellitesAction()
data class SearchFor(val query: String) : SatellitesAction()
data object SelectAll : SatellitesAction()
@@ -24,18 +24,25 @@ import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.rtbishop.look4sat.MainApplication
import com.rtbishop.look4sat.domain.repository.ISelectionRepo
import com.rtbishop.look4sat.domain.repository.ISettingsRepo
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
class SatellitesViewModel(private val selectionRepo: ISelectionRepo) : ViewModel() {
class SatellitesViewModel(
private val selectionRepo: ISelectionRepo,
private val settingsRepo: ISettingsRepo
) : ViewModel() {
private val defaultTypes = selectionRepo.getCurrentTypes()
private val _uiState = MutableStateFlow(
SatellitesState(
isDialogShown = false,
isLoading = true,
shouldSeeWarning = settingsRepo.otherSettings.value.shouldSeeWarning,
itemsList = emptyList(),
currentTypes = defaultTypes,
typesList = selectionRepo.getTypesList(),
@@ -48,14 +55,20 @@ class SatellitesViewModel(private val selectionRepo: ISelectionRepo) : ViewModel
viewModelScope.launch {
delay(1000)
selectionRepo.setTypes(defaultTypes)
selectionRepo.getEntriesFlow().collect { items ->
_uiState.value = _uiState.value.copy(isLoading = false, itemsList = items)
selectionRepo.getEntriesFlow().collectLatest { items ->
_uiState.update { it.copy(isLoading = false, itemsList = items) }
}
}
viewModelScope.launch {
settingsRepo.otherSettings.collectLatest { settings ->
_uiState.update { it.copy(shouldSeeWarning = settings.shouldSeeWarning) }
}
}
}
private fun handleAction(action: SatellitesAction) {
when (action) {
SatellitesAction.DismissWarning -> settingsRepo.setWarningDismissed()
SatellitesAction.SaveSelection -> saveSelection()
is SatellitesAction.SearchFor -> searchFor(action.query)
SatellitesAction.SelectAll -> selectAll(true)
@@ -93,7 +106,7 @@ class SatellitesViewModel(private val selectionRepo: ISelectionRepo) : ViewModel
val applicationKey = ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY
initializer {
val container = (this[applicationKey] as MainApplication).container
SatellitesViewModel(container.selectionRepo)
SatellitesViewModel(container.selectionRepo, container.settingsRepo)
}
}
}
@@ -406,7 +406,9 @@ private fun OtherCardPreview() = MainTheme {
stateOfSensors = true,
stateOfSweep = true,
stateOfUtc = false,
stateOfLightTheme = false
stateOfLightTheme = false,
shouldSeeWarning = false,
shouldSeeWelcome = false
)
OtherCard(settings = values, {}, {}, {}, {}, {})
}
+12
View File
@@ -15,6 +15,7 @@
<string name="btn_add">Add</string>
<string name="btn_accept">Accept</string>
<string name="btn_understand" translatable="false">I Understand</string>
<string name="btn_cancel">Cancel</string>
<string name="btn_back">Back</string>
<string name="btn_modes">Modes</string>
@@ -43,6 +44,17 @@
<!--Dialogs-->
<string name="satellites_warning_title" translatable="false">Warning\!</string>
<string name="satellites_warning_message" translatable="false">
There are over 9000 satellites listed in this app.
It makes no sense to track them all at the same time.
\n\nAlways try to narrow down the list to only the ones
you\'re interested in via search and types selector.</string>
<string name="passes_welcome_title" translatable="false">Welcome to Look4Sat\!</string>
<string name="passes_welcome_message" translatable="false">
Make sure to set your position via GPS, Lat/Lon or QTH in Settings.
\n\nPlease update the database at least weekly to get accurate predictions.</string>
<string name="filter_title">Filter passes</string>
<string name="filter_hours_hint">Hours ahead</string>
<string name="filter_hours_text">Show passes that occur within X hours</string>
@@ -61,6 +61,8 @@ class SettingsRepo(private val manager: LocationManager, private val preferences
private val keyStationQth = "stationQth"
private val keyStationTimestamp = "stationTimestamp"
private val keyUpdateTimestamp = "updateTimestamp"
private val keyShouldSeeWarning = "shouldSeeWarning"
private val keyShouldSeeWelcome = "shouldSeeWelcome"
private val separatorComma = ","
//region # Satellites selection settings
@@ -250,14 +252,25 @@ class SettingsRepo(private val manager: LocationManager, private val preferences
_otherSettings.value = otherSettings.value.copy(stateOfLightTheme = value)
}
private fun getOtherSettings(): OtherSettings {
val stateOfAutoUpdate = preferences.getBoolean(keyStateOfAutoUpdate, true)
val stateOfSensors = preferences.getBoolean(keyStateOfSensors, true)
val stateOfSweep = preferences.getBoolean(keyStateOfSweep, true)
val stateOfUtc = preferences.getBoolean(keyStateOfUtc, false)
val stateOfLightTheme = preferences.getBoolean(keyStateOfLightTheme,false)
return OtherSettings(stateOfAutoUpdate, stateOfSensors, stateOfSweep, stateOfUtc, stateOfLightTheme)
override fun setWarningDismissed() {
preferences.edit { putBoolean(keyShouldSeeWarning, false) }
_otherSettings.value = otherSettings.value.copy(shouldSeeWarning = false)
}
override fun setWelcomeDismissed() {
preferences.edit { putBoolean(keyShouldSeeWelcome, false) }
_otherSettings.value = otherSettings.value.copy(shouldSeeWelcome = false)
}
private fun getOtherSettings(): OtherSettings = OtherSettings(
stateOfAutoUpdate = preferences.getBoolean(keyStateOfAutoUpdate, true),
stateOfSensors = preferences.getBoolean(keyStateOfSensors, true),
stateOfSweep = preferences.getBoolean(keyStateOfSweep, true),
stateOfUtc = preferences.getBoolean(keyStateOfUtc, false),
stateOfLightTheme = preferences.getBoolean(keyStateOfLightTheme, false),
shouldSeeWarning = preferences.getBoolean(keyShouldSeeWarning, true),
shouldSeeWelcome = preferences.getBoolean(keyShouldSeeWelcome, true)
)
//endregion
//region # Undefined settings
@@ -17,5 +17,7 @@ data class OtherSettings(
val stateOfSensors: Boolean,
val stateOfSweep: Boolean,
val stateOfUtc: Boolean,
val stateOfLightTheme: Boolean
val stateOfLightTheme: Boolean,
val shouldSeeWarning: Boolean,
val shouldSeeWelcome: Boolean
)
@@ -58,6 +58,8 @@ interface ISettingsRepo {
fun setStateOfSweep(value: Boolean)
fun setStateOfUtc(value: Boolean)
fun setStateOfLightTheme(value: Boolean)
fun setWarningDismissed()
fun setWelcomeDismissed()
//endregion
//region # Undefined settings