mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-04 11:37:22 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99158e74fa | ||
|
|
8265b73d75 | ||
|
|
d2b3184084 |
No files matched your search
@@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineDispatcher
|
|||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
@@ -45,6 +46,9 @@ class SatelliteRepo(
|
|||||||
private val _passes = MutableStateFlow<List<OrbitalPass>>(emptyList())
|
private val _passes = MutableStateFlow<List<OrbitalPass>>(emptyList())
|
||||||
override val passes: StateFlow<List<OrbitalPass>> = _passes
|
override val passes: StateFlow<List<OrbitalPass>> = _passes
|
||||||
|
|
||||||
|
private val _isCalculating = MutableStateFlow(false)
|
||||||
|
override val isCalculating: StateFlow<Boolean> = _isCalculating
|
||||||
|
|
||||||
private val _satellites = MutableStateFlow<List<OrbitalObject>>(emptyList())
|
private val _satellites = MutableStateFlow<List<OrbitalObject>>(emptyList())
|
||||||
override val satellites: StateFlow<List<OrbitalObject>> = _satellites
|
override val satellites: StateFlow<List<OrbitalObject>> = _satellites
|
||||||
|
|
||||||
@@ -53,7 +57,7 @@ class SatelliteRepo(
|
|||||||
override suspend fun initRepository() = withContext(dispatcher) {
|
override suspend fun initRepository() = withContext(dispatcher) {
|
||||||
settingsRepo.selectedIds.collect { selectedIds ->
|
settingsRepo.selectedIds.collect { selectedIds ->
|
||||||
_satellites.update { localStorage.getEntriesWithIds(selectedIds) }
|
_satellites.update { localStorage.getEntriesWithIds(selectedIds) }
|
||||||
val (hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value
|
val (_, hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value
|
||||||
calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,11 +99,11 @@ class SatelliteRepo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun calculatePasses(time: Long, hoursAhead: Int, minElevation: Double, modes: List<String>) {
|
override suspend fun calculatePasses(time: Long, hoursAhead: Int, minElevation: Double, modes: List<String>) {
|
||||||
|
_isCalculating.value = true
|
||||||
// Normalize to the start of the current minute so that coarse 60-second stepping
|
// Normalize to the start of the current minute so that coarse 60-second stepping
|
||||||
// in getLeoPass always begins from the same phase, producing stable AOS/LOS times
|
// in getLeoPass always begins from the same phase, producing stable AOS/LOS times
|
||||||
val normalizedTime = time / 60_000L * 60_000L
|
val normalizedTime = time / 60_000L * 60_000L
|
||||||
val currentSatellites = _satellites.value
|
val currentSatellites = _satellites.value
|
||||||
if (currentSatellites.isNotEmpty()) {
|
|
||||||
withContext(dispatcher) {
|
withContext(dispatcher) {
|
||||||
val idsWithModes = localStorage.getIdsWithModes(modes)
|
val idsWithModes = localStorage.getIdsWithModes(modes)
|
||||||
val stationPos = settingsRepo.stationPosition.value
|
val stationPos = settingsRepo.stationPosition.value
|
||||||
@@ -125,11 +129,10 @@ class SatelliteRepo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
newPasses.sortBy { it.aosTime }
|
newPasses.sortBy { it.aosTime }
|
||||||
|
delay(1000) // Simulate loading time for better UX
|
||||||
_passes.update { newPasses }
|
_passes.update { newPasses }
|
||||||
}
|
}
|
||||||
} else {
|
_isCalculating.value = false
|
||||||
_passes.update { emptyList() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun OrbitalObject.getPasses(pos: GeoPos, time: Long, hours: Int): List<OrbitalPass> {
|
private fun OrbitalObject.getPasses(pos: GeoPos, time: Long, hours: Int): List<OrbitalPass> {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ class SettingsRepo(
|
|||||||
private val keyBluetoothFrequencyState = "bluetoothFrequencyState"
|
private val keyBluetoothFrequencyState = "bluetoothFrequencyState"
|
||||||
private val keyBluetoothFrequencyAddress = "bluetoothFrequencyAddress"
|
private val keyBluetoothFrequencyAddress = "bluetoothFrequencyAddress"
|
||||||
private val keyBluetoothFrequencyFormat = "bluetoothFrequencyFormat"
|
private val keyBluetoothFrequencyFormat = "bluetoothFrequencyFormat"
|
||||||
|
private val keyFilterShowDeepSpace = "filterShowDeepSpace"
|
||||||
private val keyFilterHoursAhead = "filterHoursAhead"
|
private val keyFilterHoursAhead = "filterHoursAhead"
|
||||||
private val keyFilterMinElevation = "filterMinElevation"
|
private val keyFilterMinElevation = "filterMinElevation"
|
||||||
private val keyNumberOfRadios = "numberOfRadios"
|
private val keyNumberOfRadios = "numberOfRadios"
|
||||||
@@ -121,6 +122,7 @@ class SettingsRepo(
|
|||||||
override val passesSettings: StateFlow<PassesSettings> = _passesSettings
|
override val passesSettings: StateFlow<PassesSettings> = _passesSettings
|
||||||
|
|
||||||
override fun setPassesSettings(settings: PassesSettings) = preferences.edit {
|
override fun setPassesSettings(settings: PassesSettings) = preferences.edit {
|
||||||
|
putBoolean(keyFilterShowDeepSpace, settings.showDeepSpace)
|
||||||
putInt(keyFilterHoursAhead, settings.hoursAhead)
|
putInt(keyFilterHoursAhead, settings.hoursAhead)
|
||||||
putLong(keyFilterMinElevation, settings.minElevation.toRawBits())
|
putLong(keyFilterMinElevation, settings.minElevation.toRawBits())
|
||||||
putString(keySelectedModes, settings.selectedModes.joinToString(separatorComma))
|
putString(keySelectedModes, settings.selectedModes.joinToString(separatorComma))
|
||||||
@@ -128,11 +130,12 @@ class SettingsRepo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getPassesSettings(): PassesSettings {
|
private fun getPassesSettings(): PassesSettings {
|
||||||
|
val showDeepSpace = preferences.getBoolean(keyFilterShowDeepSpace, true)
|
||||||
val hoursAhead = preferences.getInt(keyFilterHoursAhead, 24)
|
val hoursAhead = preferences.getInt(keyFilterHoursAhead, 24)
|
||||||
val minElevation = Double.fromBits(preferences.getLong(keyFilterMinElevation, 16.0.toRawBits()))
|
val minElevation = Double.fromBits(preferences.getLong(keyFilterMinElevation, 16.0.toRawBits()))
|
||||||
val selectedModesString = preferences.getString(keySelectedModes, null)
|
val selectedModesString = preferences.getString(keySelectedModes, null)
|
||||||
val selectedModes = selectedModesString?.split(separatorComma)?.sorted() ?: emptyList()
|
val selectedModes = selectedModesString?.split(separatorComma)?.sorted() ?: emptyList()
|
||||||
return PassesSettings(hoursAhead, minElevation, selectedModes)
|
return PassesSettings(showDeepSpace, hoursAhead, minElevation, selectedModes)
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ data class DatabaseState(
|
|||||||
)
|
)
|
||||||
|
|
||||||
data class PassesSettings(
|
data class PassesSettings(
|
||||||
|
val showDeepSpace: Boolean = true,
|
||||||
val hoursAhead: Int,
|
val hoursAhead: Int,
|
||||||
val minElevation: Double,
|
val minElevation: Double,
|
||||||
val selectedModes: List<String>
|
val selectedModes: List<String>
|
||||||
|
|||||||
+3
@@ -31,6 +31,9 @@ interface ISatelliteRepo {
|
|||||||
/** Raw calculated passes (without live progress). Updated on selection/filter change. */
|
/** Raw calculated passes (without live progress). Updated on selection/filter change. */
|
||||||
val passes: StateFlow<List<OrbitalPass>>
|
val passes: StateFlow<List<OrbitalPass>>
|
||||||
|
|
||||||
|
/** Whether the repo is currently calculating passes. */
|
||||||
|
val isCalculating: StateFlow<Boolean>
|
||||||
|
|
||||||
/** Load satellite objects from DB based on the current selection. */
|
/** Load satellite objects from DB based on the current selection. */
|
||||||
suspend fun initRepository()
|
suspend fun initRepository()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Commmon -->
|
||||||
|
<string name="app_name" translatable="false">Look4Sat</string>
|
||||||
|
<string name="btn_accept">Kabul et</string>
|
||||||
|
<string name="btn_cancel">İptal</string>
|
||||||
|
<string name="empty_list_message">Gösterilecek veri bulunamadı</string>
|
||||||
|
|
||||||
|
<!-- Navigation -->
|
||||||
|
<string name="nav_sat">Uydular</string>
|
||||||
|
<string name="nav_pass">Geçişler</string>
|
||||||
|
<string name="nav_radar">Radar</string>
|
||||||
|
<string name="nav_map">Harita</string>
|
||||||
|
<string name="nav_prefs">Ayarlar</string>
|
||||||
|
|
||||||
|
<!-- Satellites screen -->
|
||||||
|
<string name="sat_type_hint">Uydu türü: %s</string>
|
||||||
|
<string name="sat_type_title">Uydu türü seçin</string>
|
||||||
|
<string name="sat_search_hint">Id - Ad</string>
|
||||||
|
<string name="sat_search_clear">Temizle</string>
|
||||||
|
<string name="sat_clear_all">Tümünü temizle</string>
|
||||||
|
<string name="sat_select_all">Tümünü seç</string>
|
||||||
|
<string name="sat_empty_list_message">"Arama sorgunuzun doğru olduğundan ve veritabanının güncellendiğinden emin olun"</string>
|
||||||
|
<string name="sat_warning_title">Uyarı\!</string>
|
||||||
|
<string name="sat_warning_message">
|
||||||
|
Bu uygulamada 9000\'den fazla uydu listelenmiştir.
|
||||||
|
Hepsini aynı anda takip etmek anlamsızdır.
|
||||||
|
\n\nListeyi yalnızca ilgilendiğiniz uydularla
|
||||||
|
daraltmak için arama ve tür seçiciyi kullanın.</string>
|
||||||
|
|
||||||
|
<!-- Passes screen -->
|
||||||
|
<string name="pass_filter_title">Geçişleri filtrele</string>
|
||||||
|
<string name="pass_filter_elev">Minimum yükseklik açısı</string>
|
||||||
|
<string name="pass_filter_hours">İlerideki saatler</string>
|
||||||
|
<string name="pass_time_placeholder" translatable="false"> -- : -- : -- </string>
|
||||||
|
<string name="pass_modes_title">Modulasyon türü seçin</string>
|
||||||
|
<string name="pass_satId" translatable="false">%05d</string>
|
||||||
|
<string name="pass_elevation">Yükseklik açısı: %.1f°</string>
|
||||||
|
<string name="pass_deep_space" translatable="false">DeepSpace</string>
|
||||||
|
<string name="pass_altitude">İrtifa: %d km</string>
|
||||||
|
<string name="pass_aosLos" translatable="false">%03d° - %03d°</string>
|
||||||
|
<string name="pass_empty_list_message">
|
||||||
|
Filtrelerinizin doğru olduğundan ve uydu seçtiğinizden emin olun</string>
|
||||||
|
<string name="pass_error_message">Gösterilecek yaklaşan uydu geçişi bulunmuyor</string>
|
||||||
|
<string name="pass_welcome_title">Look4Sat\'a hoş geldiniz\!</string>
|
||||||
|
<string name="pass_welcome_message">
|
||||||
|
Ayarlar\'dan GPS, Enlem/Boylam veya QTH kullanarak konumunuzu belirlediğinizden emin olun.
|
||||||
|
\n\nDoğru tahminler alabilmek için veritabanını en az haftada bir güncelleyin.</string>
|
||||||
|
<string name="pass_whatsnew_title" translatable="false">What\'s new in Look4Sat</string>
|
||||||
|
<string name="pass_whatsnew_message" translatable="false">
|
||||||
|
* Switched to short-form commands in NetworkReporter, by theojalba
|
||||||
|
\n* Added CAT radio control for full-duplex SAT operation, by jcmerg
|
||||||
|
\n* Added normalized time for passes AOS/LOS, fixed refresh state bug
|
||||||
|
\n* Added multiple performance tweaks, improved passes calculation
|
||||||
|
\n* Fixed UTC pass time problem mentioned in issue #201
|
||||||
|
</string>
|
||||||
|
|
||||||
|
<!-- Radar screen -->
|
||||||
|
<string name="radar_back">Geri</string>
|
||||||
|
<string name="radar_notify">Bildir</string>
|
||||||
|
<string name="radar_az_text">Azimut</string>
|
||||||
|
<string name="radar_az_value" translatable="false">%.1f°</string>
|
||||||
|
<string name="radar_el_text">Yükseklik açısı</string>
|
||||||
|
<string name="radar_el_value" translatable="false">%.1f°</string>
|
||||||
|
<string name="radar_alt_text">İrtifa</string>
|
||||||
|
<string name="radar_alt_value" translatable="false">%.0f km</string>
|
||||||
|
<string name="radar_dist_text">Mesafe</string>
|
||||||
|
<string name="radar_dist_value" translatable="false">%.0f km</string>
|
||||||
|
<string name="radar_eclipsed">Tutulumda</string>
|
||||||
|
<string name="radar_downlink">Downlink</string>
|
||||||
|
<string name="radar_uplink">Uplink</string>
|
||||||
|
<string name="radar_link_low" translatable="false">%.4f</string>
|
||||||
|
<string name="radar_link_lowHigh" translatable="false">%.4f - %.4f</string>
|
||||||
|
<string name="radar_no_link" translatable="false">- - . - -</string>
|
||||||
|
<string name="radar_no_data">Bu uyduda transceiver bulunmuyor</string>
|
||||||
|
<string name="radar_add">Ekle</string>
|
||||||
|
<string name="radar_data">Uydu transceiver\'ları:</string>
|
||||||
|
<string name="radar_inverted">Ters çevrilmiş: %s</string>
|
||||||
|
<string name="radar_mode">Modülasyon: %s</string>
|
||||||
|
<string name="radar_string_no">Hayır</string>
|
||||||
|
<string name="radar_string_yes">Evet</string>
|
||||||
|
<string name="radar_visible">Görünür</string>
|
||||||
|
|
||||||
|
<!-- Map screen -->
|
||||||
|
<string name="map_prev">Önceki</string>
|
||||||
|
<string name="map_next">Sonraki</string>
|
||||||
|
<string name="map_copyright" translatable="false">© OpenStreetMap contributors</string>
|
||||||
|
<string name="map_azimuth">Azimut: %.1f°</string>
|
||||||
|
<string name="map_elevation">Yükseklik açısı: %.1f°</string>
|
||||||
|
<string name="map_altitude">İrtifa: %.0f km</string>
|
||||||
|
<string name="map_distance">Mesafe: %.0f km</string>
|
||||||
|
<string name="map_latitude">Enlem: %.1f°</string>
|
||||||
|
<string name="map_longitude">Boylam: %.1f°</string>
|
||||||
|
<string name="map_qth" translatable="false">QTH: %s</string>
|
||||||
|
<string name="map_phase">Faz: %.1f°</string>
|
||||||
|
<string name="map_eclipsed">Tutulumda</string>
|
||||||
|
<string name="map_period">Periyot: %.0f dk</string>
|
||||||
|
<string name="map_velocity">Hız: %.2f km/s</string>
|
||||||
|
<string name="map_visibility">Görünürlük: %s</string>
|
||||||
|
<string name="map_visible">Görünür</string>
|
||||||
|
|
||||||
|
<!-- Settings screen -->
|
||||||
|
<string name="prefs_app_title" translatable="false">Look4Sat v%s</string>
|
||||||
|
<string name="prefs_app_url" translatable="false">https://play.google.com/store/apps/details?id=com.rtbishop.look4sat</string>
|
||||||
|
<string name="prefs_donate_title">Bağış yap</string>
|
||||||
|
<string name="prefs_donate_url" translatable="false">https://ko-fi.com/rt_bishop</string>
|
||||||
|
<string name="prefs_fdroid_title" translatable="false">F-Droid</string>
|
||||||
|
<string name="prefs_fdroid_url" translatable="false">https://f-droid.org/en/packages/com.rtbishop.look4sat/</string>
|
||||||
|
<string name="prefs_github_title" translatable="false">GitHub</string>
|
||||||
|
<string name="prefs_github_url" translatable="false">https://github.com/rt-bishop/Look4Sat/</string>
|
||||||
|
<string name="prefs_license_title" translatable="false">GPLv3</string>
|
||||||
|
<string name="prefs_license_url" translatable="false">https://www.gnu.org/licenses/gpl-3.0.html</string>
|
||||||
|
<string name="prefs_privacy_title">Gizlilik Politikası</string>
|
||||||
|
<string name="prefs_privacy_url" translatable="false">https://sites.google.com/view/look4sat-privacy-policy/home</string>
|
||||||
|
|
||||||
|
<string name="prefs_updated_title">Güncellendi: %s</string>
|
||||||
|
<string name="prefs_updated_time">d MMM yyyy - HH:mm:ss</string>
|
||||||
|
|
||||||
|
<string name="prefs_loc_title">İstasyon konumu</string>
|
||||||
|
<string name="prefs_loc_gps_title">GPS</string>
|
||||||
|
<string name="prefs_loc_gps_error">Konum izinlerinizi kontrol edin</string>
|
||||||
|
<string name="prefs_loc_input_title">Manuel giriş</string>
|
||||||
|
<string name="prefs_loc_input_error">Geçersiz konum girildi</string>
|
||||||
|
<string name="prefs_loc_qth_title">QTH</string>
|
||||||
|
<string name="prefs_loc_qth_error">Geçersiz QTH konumlandırıcısı</string>
|
||||||
|
<string name="prefs_loc_success">Konum başarıyla güncellendi</string>
|
||||||
|
<string name="prefs_station_title">İstasyon konumu ayarları</string>
|
||||||
|
<string name="prefs_station_lat_text">Yer istasyonunuzun enlemini girin</string>
|
||||||
|
<string name="prefs_station_lon_text">Yer istasyonunuzun boylamını girin</string>
|
||||||
|
<string name="prefs_locator_title">QTH konumlandırıcı ayarları</string>
|
||||||
|
<string name="prefs_locator_text">İstasyon konumunu konumlandırıcı ile ayarlayın</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_title">Uydu verisi</string>
|
||||||
|
<string name="prefs_data_entries">Uydular: %s</string>
|
||||||
|
<string name="prefs_data_radios">Transceiver\'lar: %s</string>
|
||||||
|
<string name="prefs_data_update">Güncelle</string>
|
||||||
|
<string name="prefs_data_import">İçe aktar</string>
|
||||||
|
<string name="prefs_data_clear">Temizle</string>
|
||||||
|
<string name="prefs_data_clear_success">Veriler başarıyla temizlendi</string>
|
||||||
|
<string name="prefs_data_update_success">Güncelleme başarıyla tamamlandı</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_sources_title">Özel veri kaynakları</string>
|
||||||
|
<string name="prefs_data_sources_tle_switch">Özel TLE URL</string>
|
||||||
|
<string name="prefs_data_sources_transceivers_switch">Özel transceiver URL</string>
|
||||||
|
<string name="prefs_data_sources_url_title" translatable="false">URL (HTTPS)</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_output_title">Veri aktarımı</string>
|
||||||
|
<string name="prefs_net_output">Ağ</string>
|
||||||
|
<string name="prefs_bt_output">Bluetooth</string>
|
||||||
|
<string name="prefs_cat_output">CAT</string>
|
||||||
|
|
||||||
|
<!-- Radio Control -->
|
||||||
|
<string name="nav_radiocontrol">Radyo Kontrolü</string>
|
||||||
|
<string name="rc_settings_title">CAT Radyo Kontrolü</string>
|
||||||
|
<string name="rc_radio_model">Radyo Modeli</string>
|
||||||
|
<string name="rc_tx_device_hint">TX Radyo BT Adresi</string>
|
||||||
|
<string name="rc_rx_device_hint">RX Radyo BT Adresi</string>
|
||||||
|
<string name="rc_tx_name_hint">TX Radyo Adı</string>
|
||||||
|
<string name="rc_rx_name_hint">RX Radyo Adı</string>
|
||||||
|
<string name="rc_enable_switch">CAT Kontrolünü Etkinleştir</string>
|
||||||
|
|
||||||
|
<string name="prefs_net_title">Ağ veri çıkışı</string>
|
||||||
|
<string name="prefs_net_rotator_switch">Döndürme çıkışını etkinleştir</string>
|
||||||
|
<string name="prefs_net_rotator_address_hint">IP:Port</string>
|
||||||
|
<string name="prefs_net_rotator_format_hint">Biçim</string>
|
||||||
|
<string name="prefs_net_frequency_switch">Frekans çıkışını etkinleştir</string>
|
||||||
|
<string name="prefs_net_frequency_address_hint">IP:Port</string>
|
||||||
|
<string name="prefs_net_frequency_format_hint">Biçim</string>
|
||||||
|
|
||||||
|
<string name="prefs_bt_title">Bluetooth veri çıkışı</string>
|
||||||
|
<string name="prefs_bt_rotator_switch">Döndürme çıkışını etkinleştir</string>
|
||||||
|
<string name="prefs_bt_rotator_device_hint">Cihaz kimliği</string>
|
||||||
|
<string name="prefs_bt_rotator_output_hint">Veri biçimi</string>
|
||||||
|
<string name="prefs_bt_frequency_switch">Frekans çıkışını etkinleştir</string>
|
||||||
|
<string name="prefs_bt_frequency_device_hint">Cihaz kimliği</string>
|
||||||
|
<string name="prefs_bt_frequency_output_hint">Veri biçimi</string>
|
||||||
|
<string name="prefs_bt_perm_error">Bluetooth izninizi kontrol edin</string>
|
||||||
|
|
||||||
|
<string name="prefs_other_title">Diğer ayarlar</string>
|
||||||
|
<string name="prefs_other_switch_utc">Geçiş saatini UTC olarak göster</string>
|
||||||
|
<string name="prefs_other_switch_update">Otomatik veri güncellemeyi etkinleştir</string>
|
||||||
|
<string name="prefs_other_switch_sweep">Radar taramasını etkinleştir</string>
|
||||||
|
<string name="prefs_other_switch_sensors">Radar görünümünü döndürmek için sensörleri kullan</string>
|
||||||
|
|
||||||
|
<string name="prefs_outro_title">Teşekkür etmek istiyorum</string>
|
||||||
|
<string name="prefs_outro_thanks" translatable="false">
|
||||||
|
• Look4Sat users and contributors!
|
||||||
|
\n• David A. B. Johnson (predict4java)
|
||||||
|
\n• Dave Moten (predict4java)
|
||||||
|
\n• Alexandru Csete (Gpredict)
|
||||||
|
\n• Dr T.S. Kelso (Celestrak)
|
||||||
|
\n• Libre Space Foundation (SatNOGS)</string>
|
||||||
|
<string name="prefs_outro_license">Bu uygulama herhangi bir garanti sunmaz</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
<string name="pass_filter_title">Filter passes</string>
|
<string name="pass_filter_title">Filter passes</string>
|
||||||
<string name="pass_filter_elev">Minimal elevation</string>
|
<string name="pass_filter_elev">Minimal elevation</string>
|
||||||
<string name="pass_filter_hours">Hours ahead</string>
|
<string name="pass_filter_hours">Hours ahead</string>
|
||||||
|
<string name="pass_filter_deep_space">DeepSpace (period >225min)</string>
|
||||||
<string name="pass_time_placeholder" translatable="false"> -- : -- : -- </string>
|
<string name="pass_time_placeholder" translatable="false"> -- : -- : -- </string>
|
||||||
<string name="pass_modes_title">Select modulation type</string>
|
<string name="pass_modes_title">Select modulation type</string>
|
||||||
<string name="pass_satId" translatable="false">%05d</string>
|
<string name="pass_satId" translatable="false">%05d</string>
|
||||||
@@ -48,11 +49,10 @@
|
|||||||
\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_title" translatable="false">What\'s new in Look4Sat</string>
|
||||||
<string name="pass_whatsnew_message" translatable="false">
|
<string name="pass_whatsnew_message" translatable="false">
|
||||||
* Switched to short-form commands in NetworkReporter, by theojalba
|
* Added Turkish translation, by Emre Can Akdaş (TA3ECR)
|
||||||
\n* Added CAT radio control for full-duplex SAT operation, by jcmerg
|
\n* Added DeepSpace passes filter option to the dialog
|
||||||
\n* Added normalized time for passes AOS/LOS, fixed refresh state bug
|
\n* Fixed the radar blip disappearing while eclipsed
|
||||||
\n* Added multiple performance tweaks, improved passes calculation
|
\n* Fixed (hopefully) the refresh indicator being stuck
|
||||||
\n* Fixed UTC pass time problem mentioned in issue #201
|
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
<!-- Radar screen -->
|
<!-- Radar screen -->
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
* Switched to short-form commands in NetworkReporter (#206) by theojalba
|
* Added Turkish translation, by Emre Can Akdaş (TA3ECR)
|
||||||
* Added CAT radio control for full-duplex SAT operation (#207) by jcmerg
|
* Added DeepSpace passes filter option to the dialog
|
||||||
* Added normalized time for passes AOS/LOS, fixed refresh state bug
|
* Fixed the radar blip disappearing while eclipsed
|
||||||
* Added multiple performance tweaks, improved passes calculation
|
* Fixed (hopefully) the refresh indicator being stuck
|
||||||
* Simplified data output code, aligned with HamLib defaults
|
|
||||||
* Fixed UTC pass time problem mentioned in issue #201
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
* Switched to short-form commands in NetworkReporter (#206) by theojalba
|
* Added Turkish translation, by Emre Can Akdaş (TA3ECR)
|
||||||
* Added CAT radio control for full-duplex SAT operation (#207) by jcmerg
|
* Added DeepSpace passes filter option to the dialog
|
||||||
* Added normalized time for passes AOS/LOS, fixed refresh state bug
|
* Fixed the radar blip disappearing while eclipsed
|
||||||
* Added multiple performance tweaks, improved passes calculation
|
* Fixed (hopefully) the refresh indicator being stuck
|
||||||
* Simplified data output code, aligned with HamLib defaults
|
|
||||||
* Fixed UTC pass time problem mentioned in issue #201
|
|
||||||
@@ -32,12 +32,15 @@ import androidx.compose.material3.Checkbox
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Slider
|
import androidx.compose.material3.Slider
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableDoubleStateOf
|
import androidx.compose.runtime.mutableDoubleStateOf
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
@@ -65,17 +68,29 @@ private val hourSteps = listOf(1, 2, 4, 8, 12, 24, 48, 72, 96, 120, 144, 168, 19
|
|||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun PassesDialogPreview() {
|
private fun PassesDialogPreview() {
|
||||||
MainTheme { PassesDialog(24, 16.0, {}) { _, _ -> } }
|
MainTheme { PassesDialog(24, 16.0, true, {}) { _, _, _ -> } }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun PassesDialog(hours: Int, elevation: Double, cancel: () -> Unit, accept: (Int, Double) -> Unit) {
|
internal fun PassesDialog(
|
||||||
|
hours: Int,
|
||||||
|
elevation: Double,
|
||||||
|
showDeepSpace: Boolean,
|
||||||
|
cancel: () -> Unit,
|
||||||
|
accept: (Int, Double, Boolean) -> Unit
|
||||||
|
) {
|
||||||
val hoursIndex = remember { mutableIntStateOf(hourSteps.indexOfFirst { it >= hours }.coerceAtLeast(0)) }
|
val hoursIndex = remember { mutableIntStateOf(hourSteps.indexOfFirst { it >= hours }.coerceAtLeast(0)) }
|
||||||
val elevationValueNew = remember { mutableDoubleStateOf(elevation) }
|
val elevationValueNew = remember { mutableDoubleStateOf(elevation) }
|
||||||
|
var deepSpaceEnabled by remember { mutableStateOf(showDeepSpace) }
|
||||||
val onAccept = {
|
val onAccept = {
|
||||||
accept(hourSteps[hoursIndex.intValue], elevationValueNew.doubleValue).also { cancel() }
|
accept(hourSteps[hoursIndex.intValue], elevationValueNew.doubleValue, deepSpaceEnabled).also { cancel() }
|
||||||
}
|
}
|
||||||
SharedDialog(title = stringResource(R.string.pass_filter_title), onCancel = cancel, onAccept = onAccept) {
|
SharedDialog(title = stringResource(R.string.pass_filter_title), onCancel = cancel, onAccept = onAccept) {
|
||||||
|
ToggleRow(
|
||||||
|
title = stringResource(R.string.pass_filter_deep_space),
|
||||||
|
checked = deepSpaceEnabled,
|
||||||
|
onCheckedChange = { deepSpaceEnabled = it }
|
||||||
|
)
|
||||||
SliderRow(
|
SliderRow(
|
||||||
title = stringResource(R.string.pass_filter_elev),
|
title = stringResource(R.string.pass_filter_elev),
|
||||||
value = elevationValueNew.doubleValue,
|
value = elevationValueNew.doubleValue,
|
||||||
@@ -188,3 +203,20 @@ internal fun RadiosDialog(modes: List<String>, cancel: () -> Unit, accept: (List
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ToggleRow(title: String, checked: Boolean, onCheckedChange: (Boolean) -> Unit) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.padding(horizontal = LocalSpacing.current.large)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
Switch(checked = checked, onCheckedChange = onCheckedChange)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,9 +100,10 @@ private fun PassesScreen(
|
|||||||
PassesDialog(
|
PassesDialog(
|
||||||
hours = uiState.hours,
|
hours = uiState.hours,
|
||||||
elevation = uiState.elevation,
|
elevation = uiState.elevation,
|
||||||
|
showDeepSpace = uiState.showDeepSpace,
|
||||||
cancel = { onAction(PassesAction.TogglePassesDialog) }
|
cancel = { onAction(PassesAction.TogglePassesDialog) }
|
||||||
) { hours, elevation ->
|
) { hours, elevation, showDeepSpace ->
|
||||||
onAction(PassesAction.FilterPasses(hours, elevation))
|
onAction(PassesAction.FilterPasses(hours, elevation, showDeepSpace))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (uiState.isRadiosDialogShown) {
|
if (uiState.isRadiosDialogShown) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ data class PassesState(
|
|||||||
val isNextTimeAos: Boolean = true,
|
val isNextTimeAos: Boolean = true,
|
||||||
val hours: Int = 24,
|
val hours: Int = 24,
|
||||||
val elevation: Double = 16.0,
|
val elevation: Double = 16.0,
|
||||||
|
val showDeepSpace: Boolean = true,
|
||||||
val modes: List<String> = emptyList(),
|
val modes: List<String> = emptyList(),
|
||||||
val itemsList: List<OrbitalPass> = emptyList(),
|
val itemsList: List<OrbitalPass> = emptyList(),
|
||||||
val shouldSeeWhatsNew: Boolean = false
|
val shouldSeeWhatsNew: Boolean = false
|
||||||
@@ -36,7 +37,7 @@ data class PassesState(
|
|||||||
|
|
||||||
sealed interface PassesAction {
|
sealed interface PassesAction {
|
||||||
data object DismissWhatsNew : PassesAction
|
data object DismissWhatsNew : PassesAction
|
||||||
data class FilterPasses(val hoursAhead: Int, val minElevation: Double) : PassesAction
|
data class FilterPasses(val hoursAhead: Int, val minElevation: Double, val showDeepSpace: Boolean) : 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
|
||||||
data object TogglePassesDialog : PassesAction
|
data object TogglePassesDialog : PassesAction
|
||||||
|
|||||||
+29
-30
@@ -34,7 +34,6 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.drop
|
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -51,6 +50,7 @@ class PassesViewModel(
|
|||||||
nextPass = defaultPass,
|
nextPass = defaultPass,
|
||||||
hours = settingsRepo.passesSettings.value.hoursAhead,
|
hours = settingsRepo.passesSettings.value.hoursAhead,
|
||||||
elevation = settingsRepo.passesSettings.value.minElevation,
|
elevation = settingsRepo.passesSettings.value.minElevation,
|
||||||
|
showDeepSpace = settingsRepo.passesSettings.value.showDeepSpace,
|
||||||
modes = settingsRepo.passesSettings.value.selectedModes,
|
modes = settingsRepo.passesSettings.value.selectedModes,
|
||||||
shouldSeeWhatsNew = settingsRepo.otherSettings.value.shouldSeeWhatsNew
|
shouldSeeWhatsNew = settingsRepo.otherSettings.value.shouldSeeWhatsNew
|
||||||
)
|
)
|
||||||
@@ -58,29 +58,20 @@ class PassesViewModel(
|
|||||||
val uiState: StateFlow<PassesState> = _uiState
|
val uiState: StateFlow<PassesState> = _uiState
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Show refreshing indicator whenever the selected satellites list changes
|
// Refresh indicator: mirrors the repo's isCalculating state
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
settingsRepo.selectedIds.collectLatest { selectedIds ->
|
satelliteRepo.isCalculating.collect { calculating ->
|
||||||
_uiState.update { it.copy(isRefreshing = true) }
|
_uiState.update { it.copy(isRefreshing = calculating) }
|
||||||
if (selectedIds.isEmpty()) {
|
|
||||||
// No satellites selected — show indicator briefly, then stop
|
|
||||||
delay(1000)
|
|
||||||
_uiState.update { it.copy(isRefreshing = false) }
|
|
||||||
}
|
|
||||||
// For non-empty selections, the passes collector below will clear isRefreshing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Stop refreshing whenever new passes arrive (from initial load, selection change, or filter)
|
|
||||||
viewModelScope.launch {
|
|
||||||
satelliteRepo.passes.drop(1).collect { _ ->
|
|
||||||
_uiState.update { it.copy(isRefreshing = false) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Local tick loop — computes pass progress and countdown timer every second
|
// Local tick loop — computes pass progress and countdown timer every second
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
val timeNow = System.currentTimeMillis()
|
val timeNow = System.currentTimeMillis()
|
||||||
val processed = computePassProgress(satelliteRepo.passes.value, timeNow)
|
val showDeepSpace = _uiState.value.showDeepSpace
|
||||||
|
val allPasses = satelliteRepo.passes.value
|
||||||
|
val filtered = if (showDeepSpace) allPasses else allPasses.filter { !it.isDeepSpace }
|
||||||
|
val processed = computePassProgress(filtered, timeNow)
|
||||||
val (nextPass, nextTime, isAos) = resolveNextPass(processed, timeNow)
|
val (nextPass, nextTime, isAos) = resolveNextPass(processed, timeNow)
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
@@ -108,11 +99,17 @@ class PassesViewModel(
|
|||||||
fun onAction(action: PassesAction) {
|
fun onAction(action: PassesAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
PassesAction.DismissWhatsNew -> settingsRepo.setWhatsNewDismissed()
|
PassesAction.DismissWhatsNew -> settingsRepo.setWhatsNewDismissed()
|
||||||
is PassesAction.FilterPasses -> applyFilter(action.hoursAhead, action.minElevation, _uiState.value.modes)
|
is PassesAction.FilterPasses ->
|
||||||
is PassesAction.FilterRadios -> applyFilter(_uiState.value.hours, _uiState.value.elevation, action.modes)
|
applyFilter(action.hoursAhead, action.minElevation, action.showDeepSpace, _uiState.value.modes)
|
||||||
|
|
||||||
|
is PassesAction.FilterRadios ->
|
||||||
|
applyFilter(_uiState.value.hours, _uiState.value.elevation, _uiState.value.showDeepSpace, action.modes)
|
||||||
PassesAction.RefreshPasses -> refreshPasses()
|
PassesAction.RefreshPasses -> refreshPasses()
|
||||||
PassesAction.TogglePassesDialog -> _uiState.update { it.copy(isPassesDialogShown = !it.isPassesDialogShown) }
|
PassesAction.TogglePassesDialog ->
|
||||||
PassesAction.ToggleRadiosDialog -> _uiState.update { it.copy(isRadiosDialogShown = !it.isRadiosDialogShown) }
|
_uiState.update { it.copy(isPassesDialogShown = !it.isPassesDialogShown) }
|
||||||
|
|
||||||
|
PassesAction.ToggleRadiosDialog ->
|
||||||
|
_uiState.update { it.copy(isRadiosDialogShown = !it.isRadiosDialogShown) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,22 +150,24 @@ class PassesViewModel(
|
|||||||
return Triple(defaultPass, "00:00:00", true)
|
return Triple(defaultPass, "00:00:00", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyFilter(hoursAhead: Int, minElevation: Double, modes: List<String>) = viewModelScope.launch {
|
private fun applyFilter(
|
||||||
_uiState.update { it.copy(isRefreshing = true) }
|
hoursAhead: Int,
|
||||||
settingsRepo.setPassesSettings(PassesSettings(hoursAhead, minElevation, modes))
|
minElevation: Double,
|
||||||
_uiState.update { it.copy(hours = hoursAhead, elevation = minElevation, modes = modes) }
|
showDeepSpace: Boolean,
|
||||||
|
modes: List<String>
|
||||||
|
) = viewModelScope.launch {
|
||||||
|
settingsRepo.setPassesSettings(PassesSettings(showDeepSpace, hoursAhead, minElevation, modes))
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(hours = hoursAhead, elevation = minElevation, showDeepSpace = showDeepSpace, modes = modes)
|
||||||
|
}
|
||||||
satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
||||||
_uiState.update { it.copy(isRefreshing = false) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshPasses() = viewModelScope.launch {
|
private fun refreshPasses() = viewModelScope.launch {
|
||||||
_uiState.update { it.copy(isRefreshing = true) }
|
val (_, hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value
|
||||||
val (hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value
|
|
||||||
satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
||||||
_uiState.update { it.copy(isRefreshing = false) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||||
val applicationKey = ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY
|
val applicationKey = ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.feature.radar
|
package com.rtbishop.look4sat.feature.radar
|
||||||
|
|
||||||
import androidx.compose.animation.core.LinearEasing
|
|
||||||
import androidx.compose.animation.core.RepeatMode
|
|
||||||
import androidx.compose.animation.core.animateFloat
|
import androidx.compose.animation.core.animateFloat
|
||||||
import androidx.compose.animation.core.infiniteRepeatable
|
import androidx.compose.animation.core.infiniteRepeatable
|
||||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||||
@@ -80,21 +78,11 @@ fun RadarViewCompose(
|
|||||||
animationSpec = infiniteRepeatable(tween(1000)),
|
animationSpec = infiniteRepeatable(tween(1000)),
|
||||||
label = "animScale"
|
label = "animScale"
|
||||||
)
|
)
|
||||||
val eclipsedGlowAlpha by animTransition.animateFloat(
|
|
||||||
initialValue = 1.0f,
|
|
||||||
targetValue = 0.0f,
|
|
||||||
animationSpec = infiniteRepeatable(
|
|
||||||
animation = tween(durationMillis = 1000, delayMillis = 25, easing = LinearEasing),
|
|
||||||
repeatMode = RepeatMode.Reverse
|
|
||||||
),
|
|
||||||
label = "eclipsedGlowAlpha"
|
|
||||||
)
|
|
||||||
val measurer = rememberTextMeasurer()
|
val measurer = rememberTextMeasurer()
|
||||||
var sweepDegrees by remember { mutableFloatStateOf(0f) }
|
var sweepDegrees by remember { mutableFloatStateOf(0f) }
|
||||||
var cachedRadius by remember { mutableFloatStateOf(0f) }
|
var cachedRadius by remember { mutableFloatStateOf(0f) }
|
||||||
var trackPath by remember { mutableStateOf(Path()) }
|
var trackPath by remember { mutableStateOf(Path()) }
|
||||||
var trackEffect by remember { mutableStateOf(PathEffect.cornerPathEffect(0f)) }
|
var trackEffect by remember { mutableStateOf(PathEffect.cornerPathEffect(0f)) }
|
||||||
val isEclipsed = item.eclipsed
|
|
||||||
|
|
||||||
Canvas(modifier = modifier.aspectRatio(1f)) {
|
Canvas(modifier = modifier.aspectRatio(1f)) {
|
||||||
val radius = size.minDimension / 2f * 0.95f
|
val radius = size.minDimension / 2f * 0.95f
|
||||||
@@ -110,12 +98,8 @@ fun RadarViewCompose(
|
|||||||
translate(center.x, center.y) {
|
translate(center.x, center.y) {
|
||||||
drawTrack(trackPath, trackEffect, aimColor, trackColor)
|
drawTrack(trackPath, trackEffect, aimColor, trackColor)
|
||||||
if (item.elevation > 0) {
|
if (item.elevation > 0) {
|
||||||
if (isEclipsed) {
|
|
||||||
drawEclipsedPosition(item, radius, eclipsedGlowAlpha, trackColor)
|
|
||||||
} else {
|
|
||||||
drawPosition(item, radius, animScale, trackColor)
|
drawPosition(item, radius, animScale, trackColor)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (shouldUseCompass) drawAim(azimElev.first, azimElev.second, radius, aimColor)
|
if (shouldUseCompass) drawAim(azimElev.first, azimElev.second, radius, aimColor)
|
||||||
}
|
}
|
||||||
sweepDegrees = (sweepDegrees + SWEEP_INCREMENT) % 360f
|
sweepDegrees = (sweepDegrees + SWEEP_INCREMENT) % 360f
|
||||||
@@ -150,12 +134,7 @@ private fun DrawScope.drawTrack(path: Path, effect: PathEffect, color: Color, ef
|
|||||||
private fun DrawScope.drawPosition(item: OrbitalPos, radius: Float, posRadius: Float, color: Color) {
|
private fun DrawScope.drawPosition(item: OrbitalPos, radius: Float, posRadius: Float, color: Color) {
|
||||||
val pos = sph2Cart(item.azimuth, item.elevation, radius.toDouble())
|
val pos = sph2Cart(item.azimuth, item.elevation, radius.toDouble())
|
||||||
drawCircle(color, 16f, pos)
|
drawCircle(color, 16f, pos)
|
||||||
drawCircle(color.copy(alpha = 1 - (posRadius / 64f)), posRadius, pos)
|
if (!item.eclipsed) drawCircle(color.copy(alpha = 1 - (posRadius / 64f)), posRadius, pos)
|
||||||
}
|
|
||||||
|
|
||||||
private fun DrawScope.drawEclipsedPosition(item: OrbitalPos, radius: Float, glowAlpha: Float, color: Color) {
|
|
||||||
val pos = sph2Cart(item.azimuth, item.elevation, radius.toDouble())
|
|
||||||
drawCircle(color.copy(alpha = glowAlpha), 16f, pos)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DrawScope.drawAim(azim: Float, elev: Float, radius: Float, color: Color) {
|
private fun DrawScope.drawAim(azim: Float, elev: Float, radius: Float, color: Color) {
|
||||||
|
|||||||
+2
-2
@@ -44,12 +44,12 @@ class RadioControlViewModel(
|
|||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
private val trackingService: IRadioTrackingService,
|
private val trackingService: IRadioTrackingService,
|
||||||
private val satelliteRepo: ISatelliteRepo,
|
private val satelliteRepo: ISatelliteRepo,
|
||||||
private val settingsRepo: ISettingsRepo
|
settingsRepo: ISettingsRepo
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
|
private val stationPos = settingsRepo.stationPosition.value
|
||||||
private var currentPass: OrbitalPass? = null
|
private var currentPass: OrbitalPass? = null
|
||||||
private var transponders: List<SatRadio> = emptyList()
|
private var transponders: List<SatRadio> = emptyList()
|
||||||
private val stationPos = settingsRepo.stationPosition.value
|
|
||||||
|
|
||||||
private val _uiState = MutableStateFlow(
|
private val _uiState = MutableStateFlow(
|
||||||
RadioControlState(
|
RadioControlState(
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
[versions]
|
[versions]
|
||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection UnusedVersionCatalogEntry
|
||||||
appVersionCode = "420"
|
appVersionCode = "421"
|
||||||
#noinspection UnusedVersionCatalogEntry
|
|
||||||
appVersionName = "4.2.0"
|
|
||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection UnusedVersionCatalogEntry
|
||||||
|
appVersionName = "4.2.1"
|
||||||
|
#noinspection GradleDependency,UnusedVersionCatalogEntry
|
||||||
compileSdk = "36"
|
compileSdk = "36"
|
||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection UnusedVersionCatalogEntry
|
||||||
minSdk = "24"
|
minSdk = "24"
|
||||||
@@ -12,7 +12,7 @@ jdkVersion = "17"
|
|||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection UnusedVersionCatalogEntry
|
||||||
packageName = "com.rtbishop.look4sat"
|
packageName = "com.rtbishop.look4sat"
|
||||||
|
|
||||||
android-gradle-plugin = "9.1.0"
|
android-gradle-plugin = "9.1.1"
|
||||||
google-ksp = "2.3.6"
|
google-ksp = "2.3.6"
|
||||||
kotlin = "2.3.20"
|
kotlin = "2.3.20"
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user