v4.1.0 - Remote freq control for Hamlib/SDR++, by londre7

This commit is contained in:
Arty Bishop committed 2026-02-22 13:51:58 +00:00
1 parent e717d75324
commit de99e09f5e
15 files changed
+42 -40

No files matched your search

+2 -2
View File
@@ -13,8 +13,8 @@ android {
defaultConfig { defaultConfig {
applicationId = "com.rtbishop.look4sat" applicationId = "com.rtbishop.look4sat"
minSdk = 24 minSdk = 24
versionCode = 404 versionCode = 410
versionName = "4.0.4" versionName = "4.1.0"
} }
buildFeatures { buildFeatures {
compose = true compose = true
@@ -299,7 +299,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.large val padding = LocalSpacing.current.large
Dialog(onDismissRequest = onDismiss) { Dialog(onDismissRequest = {}) {
ElevatedCard { ElevatedCard {
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
@@ -110,12 +110,12 @@ private fun PassesScreen(uiState: PassesState, navigateToRadar: (Int, Long) -> U
uiState.takeAction(PassesAction.FilterRadios(modes)) uiState.takeAction(PassesAction.FilterRadios(modes))
} }
} }
if (uiState.shouldSeeWelcome) { if (uiState.shouldSeeWhatsNew) {
InfoDialog( InfoDialog(
title = stringResource(R.string.pass_welcome_title), title = stringResource(R.string.pass_whatsnew_title),
text = stringResource(R.string.pass_welcome_message) text = stringResource(R.string.pass_whatsnew_message)
) { ) {
uiState.takeAction(PassesAction.DismissWelcome) uiState.takeAction(PassesAction.DismissWhatsNew)
} }
} }
val gridState = rememberLazyGridState() val gridState = rememberLazyGridState()
@@ -31,12 +31,12 @@ data class PassesState(
val elevation: Double, val elevation: Double,
val modes: List<String>, val modes: List<String>,
val itemsList: List<OrbitalPass>, val itemsList: List<OrbitalPass>,
val shouldSeeWelcome: Boolean, val shouldSeeWhatsNew: Boolean,
val takeAction: (PassesAction) -> Unit val takeAction: (PassesAction) -> Unit
) )
sealed class PassesAction { sealed class PassesAction {
data object DismissWelcome : PassesAction() data object DismissWhatsNew : PassesAction()
data class FilterPasses(val hoursAhead: Int, val minElevation: Double) : PassesAction() data class FilterPasses(val hoursAhead: Int, val minElevation: Double) : PassesAction()
data class FilterRadios(val modes: List<String>) : PassesAction() data class FilterRadios(val modes: List<String>) : PassesAction()
data object RefreshPasses : PassesAction() data object RefreshPasses : PassesAction()
@@ -40,7 +40,8 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class PassesViewModel( class PassesViewModel(
private val satelliteRepo: ISatelliteRepo, private val settingsRepo: ISettingsRepo private val satelliteRepo: ISatelliteRepo,
private val settingsRepo: ISettingsRepo
) : ViewModel() { ) : ViewModel() {
private val _uiState = MutableStateFlow( private val _uiState = MutableStateFlow(
@@ -56,7 +57,7 @@ class PassesViewModel(
elevation = settingsRepo.passesSettings.value.minElevation, elevation = settingsRepo.passesSettings.value.minElevation,
modes = settingsRepo.passesSettings.value.selectedModes, modes = settingsRepo.passesSettings.value.selectedModes,
itemsList = emptyList(), itemsList = emptyList(),
shouldSeeWelcome = settingsRepo.otherSettings.value.shouldSeeWelcome, shouldSeeWhatsNew = settingsRepo.otherSettings.value.shouldSeeWhatsNew,
takeAction = ::handleAction takeAction = ::handleAction
) )
) )
@@ -81,14 +82,14 @@ class PassesViewModel(
} }
viewModelScope.launch { viewModelScope.launch {
settingsRepo.otherSettings.collectLatest { settings -> settingsRepo.otherSettings.collectLatest { settings ->
_uiState.update { it.copy(shouldSeeWelcome = settings.shouldSeeWelcome) } _uiState.update { it.copy(shouldSeeWhatsNew = settings.shouldSeeWhatsNew) }
} }
} }
} }
private fun handleAction(action: PassesAction) { private fun handleAction(action: PassesAction) {
when (action) { when (action) {
PassesAction.DismissWelcome -> settingsRepo.setWelcomeDismissed() PassesAction.DismissWhatsNew -> settingsRepo.setWhatsNewDismissed()
is PassesAction.FilterPasses -> applyFilter(action.hoursAhead, action.minElevation, uiState.value.modes) is PassesAction.FilterPasses -> applyFilter(action.hoursAhead, action.minElevation, uiState.value.modes)
is PassesAction.FilterRadios -> applyFilter(uiState.value.hours, uiState.value.elevation, action.modes) is PassesAction.FilterRadios -> applyFilter(uiState.value.hours, uiState.value.elevation, action.modes)
PassesAction.RefreshPasses -> refreshPasses() PassesAction.RefreshPasses -> refreshPasses()
@@ -472,7 +472,7 @@ private fun OtherCardPreview() = MainTheme {
stateOfUtc = false, stateOfUtc = false,
stateOfLightTheme = false, stateOfLightTheme = false,
shouldSeeWarning = false, shouldSeeWarning = false,
shouldSeeWelcome = false shouldSeeWhatsNew = false
) )
OtherCard(settings = values, {}, {}, {}, {}) OtherCard(settings = values, {}, {}, {}, {})
} }
@@ -46,8 +46,7 @@ class SettingsViewModel(
private val databaseRepo: IDatabaseRepo, private val databaseRepo: IDatabaseRepo,
private val satelliteRepo: ISatelliteRepo, private val satelliteRepo: ISatelliteRepo,
private val settingsRepo: ISettingsRepo, private val settingsRepo: ISettingsRepo,
private val showToast: IShowToast, private val showToast: IShowToast
appVersionName: String
) : ViewModel() { ) : ViewModel() {
private val defaultPosSettings = PositionSettings(false, settingsRepo.stationPosition.value, 0) private val defaultPosSettings = PositionSettings(false, settingsRepo.stationPosition.value, 0)
@@ -63,7 +62,7 @@ class SettingsViewModel(
nextTime = "00:00:00", nextTime = "00:00:00",
isNextTimeAos = true, isNextTimeAos = true,
nextPass = getDefaultPass(), nextPass = getDefaultPass(),
appVersionName = appVersionName, appVersionName = settingsRepo.appVersionName,
positionSettings = defaultPosSettings, positionSettings = defaultPosSettings,
dataSettings = defaultDataSettings, dataSettings = defaultDataSettings,
otherSettings = settingsRepo.otherSettings.value, otherSettings = settingsRepo.otherSettings.value,
@@ -297,8 +296,7 @@ class SettingsViewModel(
container.databaseRepo, container.databaseRepo,
container.satelliteRepo, container.satelliteRepo,
container.settingsRepo, container.settingsRepo,
container.provideShowToast(), container.provideShowToast()
container.provideAppVersionName()
) )
} }
} }
+5
View File
@@ -46,6 +46,11 @@
<string name="pass_welcome_message"> <string name="pass_welcome_message">
Make sure to set your position via GPS, Lat/Lon or QTH in Settings. 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> \n\nPlease update the database at least weekly to get accurate predictions.</string>
<string name="pass_whatsnew_title" translatable="false">What\'s new in Look4Sat</string>
<string name="pass_whatsnew_message" translatable="false">
• Londre7 added a remote frequency control feature (Hamlib/SDR++) by sending compatible messages via Network/BT.
Enable it in Settings and tap the transceiver (Radar Screen).
</string>
<!-- Radar screen --> <!-- Radar screen -->
<string name="radar_back">Back</string> <string name="radar_back">Back</string>
@@ -61,10 +61,6 @@ class MainContainer(private val context: Context) {
val satelliteRepo = provideSatelliteRepo() val satelliteRepo = provideSatelliteRepo()
val databaseRepo = provideDatabaseRepo() val databaseRepo = provideDatabaseRepo()
fun provideAppVersionName(): String {
return context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "4.0.0"
}
fun provideAddToCalendar(): IAddToCalendar = AddToCalendar(context) fun provideAddToCalendar(): IAddToCalendar = AddToCalendar(context)
fun provideShowToast(): IShowToast = ShowToast(context) fun provideShowToast(): IShowToast = ShowToast(context)
@@ -111,6 +107,7 @@ class MainContainer(private val context: Context) {
val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val appPrefsFileName = "${context.packageName}_preferences" val appPrefsFileName = "${context.packageName}_preferences"
val appPreferences = context.getSharedPreferences(appPrefsFileName, Context.MODE_PRIVATE) val appPreferences = context.getSharedPreferences(appPrefsFileName, Context.MODE_PRIVATE)
return SettingsRepo(manager, appPreferences) val appVersionName = context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "4.0.4"
return SettingsRepo(manager, appPreferences, appVersionName)
} }
} }
@@ -39,7 +39,8 @@ import kotlinx.coroutines.flow.update
class SettingsRepo( class SettingsRepo(
private val locationManager: LocationManager, private val locationManager: LocationManager,
private val preferences: SharedPreferences private val preferences: SharedPreferences,
override val appVersionName: String
) : ISettingsRepo, LocationListenerCompat { ) : ISettingsRepo, LocationListenerCompat {
private val keyBluetoothRotatorAddress = "bluetoothAddress" private val keyBluetoothRotatorAddress = "bluetoothAddress"
@@ -76,7 +77,7 @@ class SettingsRepo(
private val keyStationTimestamp = "stationTimestamp" private val keyStationTimestamp = "stationTimestamp"
private val keyUpdateTimestamp = "updateTimestamp" private val keyUpdateTimestamp = "updateTimestamp"
private val keyShouldSeeWarning = "shouldSeeWarning" private val keyShouldSeeWarning = "shouldSeeWarning"
private val keyShouldSeeWelcome = "shouldSeeWelcome" private val keyShouldSeeWhatsNew = "shouldSeeWhatsNew_v$appVersionName"
private val keyUseCustomTle = "useCustomTle" private val keyUseCustomTle = "useCustomTle"
private val keyUseCustomTransceivers = "useCustomTransceivers" private val keyUseCustomTransceivers = "useCustomTransceivers"
private val keyTleUrl = "tleUrl" private val keyTleUrl = "tleUrl"
@@ -376,9 +377,9 @@ class SettingsRepo(
_otherSettings.update { it.copy(shouldSeeWarning = false) } _otherSettings.update { it.copy(shouldSeeWarning = false) }
} }
override fun setWelcomeDismissed() { override fun setWhatsNewDismissed() {
preferences.edit { putBoolean(keyShouldSeeWelcome, false) } preferences.edit { putBoolean(keyShouldSeeWhatsNew, false) }
_otherSettings.update { it.copy(shouldSeeWelcome = false) } _otherSettings.update { it.copy(shouldSeeWhatsNew = false) }
} }
private fun getOtherSettings(): OtherSettings = OtherSettings( private fun getOtherSettings(): OtherSettings = OtherSettings(
@@ -388,7 +389,7 @@ class SettingsRepo(
stateOfUtc = preferences.getBoolean(keyStateOfUtc, false), stateOfUtc = preferences.getBoolean(keyStateOfUtc, false),
stateOfLightTheme = preferences.getBoolean(keyStateOfLightTheme, false), stateOfLightTheme = preferences.getBoolean(keyStateOfLightTheme, false),
shouldSeeWarning = preferences.getBoolean(keyShouldSeeWarning, true), shouldSeeWarning = preferences.getBoolean(keyShouldSeeWarning, true),
shouldSeeWelcome = preferences.getBoolean(keyShouldSeeWelcome, true) shouldSeeWhatsNew = preferences.getBoolean(keyShouldSeeWhatsNew, true)
) )
//endregion //endregion
@@ -54,7 +54,7 @@ data class OtherSettings(
val stateOfUtc: Boolean, val stateOfUtc: Boolean,
val stateOfLightTheme: Boolean, val stateOfLightTheme: Boolean,
val shouldSeeWarning: Boolean, val shouldSeeWarning: Boolean,
val shouldSeeWelcome: Boolean val shouldSeeWhatsNew: Boolean
) )
data class DataSourcesSettings( data class DataSourcesSettings(
@@ -27,6 +27,8 @@ import kotlinx.coroutines.flow.StateFlow
interface ISettingsRepo { interface ISettingsRepo {
val appVersionName: String
//region # Satellites selection settings //region # Satellites selection settings
val selectedIds: StateFlow<List<Int>> val selectedIds: StateFlow<List<Int>>
val selectedTypes: StateFlow<List<String>> val selectedTypes: StateFlow<List<String>>
@@ -70,7 +72,6 @@ interface ISettingsRepo {
fun setFrequencyPort(value: String) fun setFrequencyPort(value: String)
fun setFrequencyState(value: Boolean) fun setFrequencyState(value: Boolean)
fun setFrequencyFormat(value: String) fun setFrequencyFormat(value: String)
//endregion //endregion
//region # Other settings //region # Other settings
@@ -81,7 +82,7 @@ interface ISettingsRepo {
fun setStateOfUtc(value: Boolean) fun setStateOfUtc(value: Boolean)
fun setStateOfLightTheme(value: Boolean) fun setStateOfLightTheme(value: Boolean)
fun setWarningDismissed() fun setWarningDismissed()
fun setWelcomeDismissed() fun setWhatsNewDismissed()
//endregion //endregion
//region # Transceivers settings //region # Transceivers settings
@@ -1,2 +1,3 @@
Added fixes for Chinese translation, by Mubi-Baihua #194 Added What's New dialog to announce changes and features
Bumped R4UAB source priority for Sat names consistency Added remote frequency control feature, by londre7 #195
Updated the Chinese translation, by wty2019wty #196
@@ -1,2 +1,3 @@
Added fixes for Chinese translation, by Mubi-Baihua #194 Added What's New dialog to announce changes and features
Bumped R4UAB source priority for Sat names consistency Added remote frequency control feature, by londre7 #195
Updated the Chinese translation, by wty2019wty #196
-3
View File
@@ -5,9 +5,6 @@ pluginManagement {
gradlePluginPortal() gradlePluginPortal()
} }
} }
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}
dependencyResolutionManagement { dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories { repositories {