mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Major classes refactoring and code cleanup
This commit is contained in:
1 parent
6572dd4eab
commit
f7f317cf8b
67 files changed
+610
-754
No files matched your search
File renamed without changes.
+4
-4
@@ -118,10 +118,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"catnum"
|
"catnum"
|
||||||
],
|
]
|
||||||
"autoGenerate": false
|
|
||||||
},
|
},
|
||||||
"indices": [],
|
"indices": [],
|
||||||
"foreignKeys": []
|
"foreignKeys": []
|
||||||
@@ -186,10 +186,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"uuid"
|
"uuid"
|
||||||
],
|
]
|
||||||
"autoGenerate": false
|
|
||||||
},
|
},
|
||||||
"indices": [],
|
"indices": [],
|
||||||
"foreignKeys": []
|
"foreignKeys": []
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".presentation.MainApplication"
|
android:name=".MainApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
android:theme="@style/Theme.Look4Sat.Main"
|
android:theme="@style/Theme.Look4Sat.Main"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".presentation.MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/Theme.Look4Sat.SplashScreen">
|
android:theme="@style/Theme.Look4Sat.SplashScreen">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||||
|
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.rtbishop.look4sat
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
|
import com.rtbishop.look4sat.presentation.MainScreen
|
||||||
|
import com.rtbishop.look4sat.presentation.MainTheme
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
|
installSplashScreen()
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContent { MainTheme { MainScreen() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun attachBaseContext(newBase: Context?) {
|
||||||
|
val newConfig = Configuration(newBase?.resources?.configuration)
|
||||||
|
newConfig.fontScale = 1.0f
|
||||||
|
applyOverrideConfiguration(newConfig)
|
||||||
|
super.attachBaseContext(newBase)
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-8
@@ -15,12 +15,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation
|
package com.rtbishop.look4sat
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import com.rtbishop.look4sat.BuildConfig
|
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.IDataRepository
|
||||||
import com.rtbishop.look4sat.framework.SettingsManager
|
import com.rtbishop.look4sat.domain.ISettingsSource
|
||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@@ -31,10 +30,10 @@ import javax.inject.Inject
|
|||||||
class MainApplication : Application() {
|
class MainApplication : Application() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var repository: IDataRepository
|
lateinit var dataRepository: IDataRepository
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var settingsManager: SettingsManager
|
lateinit var settingsSource: ISettingsSource
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
@@ -45,12 +44,12 @@ class MainApplication : Application() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAutoUpdate() {
|
private fun checkAutoUpdate() {
|
||||||
if (settingsManager.isUpdateEnabled()) {
|
if (settingsSource.isUpdateEnabled()) {
|
||||||
val timeDelta = System.currentTimeMillis() - settingsManager.getLastUpdateTime()
|
val timeDelta = System.currentTimeMillis() - settingsSource.getLastUpdateTime()
|
||||||
if (timeDelta > 172800000) { // 48 hours in ms
|
if (timeDelta > 172800000) { // 48 hours in ms
|
||||||
val sdf = SimpleDateFormat("d MMM yyyy - HH:mm:ss", Locale.getDefault())
|
val sdf = SimpleDateFormat("d MMM yyyy - HH:mm:ss", Locale.getDefault())
|
||||||
Timber.d("Started periodic data update on ${sdf.format(Date())}")
|
Timber.d("Started periodic data update on ${sdf.format(Date())}")
|
||||||
repository.updateFromWeb()
|
dataRepository.updateFromWeb()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||||
|
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.rtbishop.look4sat
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.hardware.Sensor
|
||||||
|
import android.hardware.SensorManager
|
||||||
|
import android.location.LocationManager
|
||||||
|
import androidx.room.Room
|
||||||
|
import com.rtbishop.look4sat.data.DataParser
|
||||||
|
import com.rtbishop.look4sat.data.DataRepository
|
||||||
|
import com.rtbishop.look4sat.domain.*
|
||||||
|
import com.rtbishop.look4sat.framework.*
|
||||||
|
import com.rtbishop.look4sat.framework.data.*
|
||||||
|
import com.rtbishop.look4sat.framework.data.local.EntriesStorage
|
||||||
|
import com.rtbishop.look4sat.framework.data.local.RadiosStorage
|
||||||
|
import com.rtbishop.look4sat.framework.data.remote.FileSource
|
||||||
|
import com.rtbishop.look4sat.framework.data.remote.NetworkSource
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
object MainModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideBluetoothReporter(@ApplicationContext context: Context): BluetoothReporter {
|
||||||
|
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
||||||
|
return BluetoothReporter(manager, CoroutineScope(Dispatchers.IO))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideNetworkReporter(): NetworkReporter = NetworkReporter(CoroutineScope(Dispatchers.IO))
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideDataRepository(
|
||||||
|
@ApplicationContext context: Context, settings: ISettingsSource
|
||||||
|
): IDataRepository {
|
||||||
|
val db = Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb")
|
||||||
|
.addMigrations(MIGRATION_1_2).fallbackToDestructiveMigration().build()
|
||||||
|
val parser = DataParser(Dispatchers.Default)
|
||||||
|
val fileSource = FileSource(context.contentResolver, Dispatchers.IO)
|
||||||
|
val entries = EntriesStorage(db.entriesDao())
|
||||||
|
val radios = RadiosStorage(db.radiosDao())
|
||||||
|
val remoteSource = NetworkSource(Dispatchers.IO)
|
||||||
|
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||||
|
return DataRepository(parser, fileSource, entries, radios, remoteSource, scope, settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideLocationSource(
|
||||||
|
@ApplicationContext context: Context, settings: ISettingsSource
|
||||||
|
): ILocationSource {
|
||||||
|
val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||||
|
return LocationSource(manager, settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideOrientationSource(@ApplicationContext context: Context): OrientationSource {
|
||||||
|
val manager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||||
|
val sensor = manager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
|
||||||
|
return OrientationSource(manager, sensor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideSatelliteManager(): ISatelliteManager = SatelliteManager(Dispatchers.Default)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideSettingsSource(@ApplicationContext context: Context): ISettingsSource {
|
||||||
|
return SettingsSource(context.getSharedPreferences("default", Context.MODE_PRIVATE))
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-2
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.radarScreen
|
package com.rtbishop.look4sat.framework
|
||||||
|
|
||||||
import android.bluetooth.BluetoothManager
|
import android.bluetooth.BluetoothManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@@ -9,7 +9,10 @@ import java.io.OutputStream
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class BTReporter(private val manager: BluetoothManager, private val reporterScope: CoroutineScope) {
|
class BluetoothReporter(
|
||||||
|
private val manager: BluetoothManager,
|
||||||
|
private val reporterScope: CoroutineScope
|
||||||
|
) {
|
||||||
|
|
||||||
private val tag = "BTReporter"
|
private val tag = "BTReporter"
|
||||||
private val sppid: UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
|
private val sppid: UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
|
||||||
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.framework
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.location.Location
|
|
||||||
import android.location.LocationListener
|
|
||||||
import android.location.LocationManager
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import com.rtbishop.look4sat.R
|
|
||||||
import com.rtbishop.look4sat.domain.ILocationManager
|
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
|
||||||
import com.rtbishop.look4sat.utility.QthConverter
|
|
||||||
import com.rtbishop.look4sat.utility.round
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class LocationManager @Inject constructor(
|
|
||||||
@ApplicationContext private val context: Context,
|
|
||||||
private val manager: LocationManager,
|
|
||||||
private val settings: ISettingsManager,
|
|
||||||
) : LocationListener, ILocationManager {
|
|
||||||
|
|
||||||
private val providerDef = LocationManager.PASSIVE_PROVIDER
|
|
||||||
private val providerNet = LocationManager.NETWORK_PROVIDER
|
|
||||||
private val providerGps = LocationManager.GPS_PROVIDER
|
|
||||||
private val locationCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
|
|
||||||
private val locationFine = Manifest.permission.ACCESS_FINE_LOCATION
|
|
||||||
private val _stationPosition = MutableStateFlow<DataState<GeoPos>>(DataState.Handled)
|
|
||||||
private var currentLocator = settings.loadStationLocator()
|
|
||||||
private var currentPosition = settings.loadStationPosition()
|
|
||||||
|
|
||||||
override val stationPosition: StateFlow<DataState<GeoPos>> = _stationPosition
|
|
||||||
|
|
||||||
override fun getStationLocator(): String = currentLocator
|
|
||||||
|
|
||||||
override fun getStationPosition(): GeoPos = currentPosition
|
|
||||||
|
|
||||||
override fun setStationPosition(latitude: Double, longitude: Double) {
|
|
||||||
if (QthConverter.isValidPosition(latitude, longitude)) {
|
|
||||||
val tempLon = if (longitude > 180.0) longitude - 180 else longitude
|
|
||||||
val newLat = latitude.round(4)
|
|
||||||
val newLon = tempLon.round(4)
|
|
||||||
QthConverter.positionToQth(newLat, newLon)?.let { locator ->
|
|
||||||
currentLocator = locator
|
|
||||||
currentPosition = GeoPos(newLat, newLon)
|
|
||||||
settings.saveStationLocator(locator)
|
|
||||||
settings.saveStationPosition(currentPosition)
|
|
||||||
_stationPosition.value = DataState.Success(currentPosition)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_stationPosition.value =
|
|
||||||
DataState.Error(context.getString(R.string.location_manual_error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setPositionFromGps() {
|
|
||||||
val result = ContextCompat.checkSelfPermission(context, locationFine)
|
|
||||||
if (manager.isProviderEnabled(providerGps) && result == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
val location = manager.getLastKnownLocation(providerDef)
|
|
||||||
if (location != null) {
|
|
||||||
setStationPosition(location.latitude, location.longitude)
|
|
||||||
} else {
|
|
||||||
_stationPosition.value = DataState.Loading
|
|
||||||
manager.requestLocationUpdates(providerGps, 0L, 0f, this)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_stationPosition.value = DataState.Error(context.getString(R.string.location_null))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setPositionFromNet() {
|
|
||||||
val result = ContextCompat.checkSelfPermission(context, locationCoarse)
|
|
||||||
if (manager.isProviderEnabled(providerNet) && result == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
val location = manager.getLastKnownLocation(providerDef)
|
|
||||||
if (location != null) {
|
|
||||||
setStationPosition(location.latitude, location.longitude)
|
|
||||||
} else {
|
|
||||||
_stationPosition.value = DataState.Loading
|
|
||||||
manager.requestLocationUpdates(providerNet, 0L, 0f, this)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_stationPosition.value = DataState.Error(context.getString(R.string.location_null))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setPositionFromQth(locator: String) {
|
|
||||||
val position = QthConverter.qthToPosition(locator)
|
|
||||||
if (position != null) {
|
|
||||||
currentLocator = locator
|
|
||||||
currentPosition = position
|
|
||||||
settings.saveStationLocator(locator)
|
|
||||||
settings.saveStationPosition(currentPosition)
|
|
||||||
_stationPosition.value = DataState.Success(currentPosition)
|
|
||||||
} else {
|
|
||||||
_stationPosition.value = DataState.Error(context.getString(R.string.location_qth_error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setPositionHandled() {
|
|
||||||
_stationPosition.value = DataState.Handled
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLocationChanged(location: Location) {
|
|
||||||
manager.removeUpdates(this)
|
|
||||||
setStationPosition(location.latitude, location.longitude)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onProviderEnabled(provider: String) {}
|
|
||||||
|
|
||||||
override fun onProviderDisabled(provider: String) {}
|
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
|
||||||
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||||
|
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.rtbishop.look4sat.framework
|
||||||
|
|
||||||
|
import android.location.Location
|
||||||
|
import android.location.LocationManager
|
||||||
|
import androidx.core.location.LocationListenerCompat
|
||||||
|
import androidx.core.location.LocationManagerCompat
|
||||||
|
import com.rtbishop.look4sat.domain.ILocationSource
|
||||||
|
import com.rtbishop.look4sat.domain.ISettingsSource
|
||||||
|
import com.rtbishop.look4sat.model.StationPos
|
||||||
|
import com.rtbishop.look4sat.utility.QthConverter
|
||||||
|
import com.rtbishop.look4sat.utility.round
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class LocationSource(
|
||||||
|
private val manager: LocationManager,
|
||||||
|
private val settings: ISettingsSource,
|
||||||
|
) : ILocationSource, LocationListenerCompat {
|
||||||
|
|
||||||
|
private val _stationPosition = MutableStateFlow(settings.loadStationPosition())
|
||||||
|
override val stationPosition: StateFlow<StationPos> = _stationPosition
|
||||||
|
|
||||||
|
override fun setGpsPosition(): Boolean {
|
||||||
|
if (!LocationManagerCompat.isLocationEnabled(manager)) return false
|
||||||
|
forceLocationUpdate(LocationManager.GPS_PROVIDER)
|
||||||
|
forceLocationUpdate(LocationManager.NETWORK_PROVIDER)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setGeoPosition(latitude: Double, longitude: Double): Boolean {
|
||||||
|
manager.removeUpdates(this)
|
||||||
|
val newLongitude = if (longitude > 180.0) longitude - 180 else longitude
|
||||||
|
val locator = QthConverter.positionToQth(latitude, newLongitude) ?: return false
|
||||||
|
saveStationPosition(latitude, newLongitude, locator)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setQthPosition(locator: String): Boolean {
|
||||||
|
val position = QthConverter.qthToPosition(locator) ?: return false
|
||||||
|
saveStationPosition(position.lat, position.lon, locator)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLocationChanged(location: Location) {
|
||||||
|
setGeoPosition(location.latitude, location.longitude)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun forceLocationUpdate(provider: String) {
|
||||||
|
try {
|
||||||
|
val location = manager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)
|
||||||
|
if (location == null || System.currentTimeMillis() - location.time > 600000) {
|
||||||
|
Timber.d("Requesting $provider location update")
|
||||||
|
manager.requestLocationUpdates(provider, 0L, 0f, this)
|
||||||
|
} else {
|
||||||
|
setGeoPosition(location.latitude, location.longitude)
|
||||||
|
}
|
||||||
|
} catch (exception: SecurityException) {
|
||||||
|
Timber.d("No permissions were given")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveStationPosition(latitude: Double, longitude: Double, locator: String) {
|
||||||
|
val newLat = latitude.round(4)
|
||||||
|
val newLon = longitude.round(4)
|
||||||
|
Timber.d("Received new Position($newLat, $newLon) & Locator $locator")
|
||||||
|
_stationPosition.value = StationPos(newLat, newLon, locator, System.currentTimeMillis())
|
||||||
|
settings.saveStationPosition(stationPosition.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -15,7 +15,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.utility
|
package com.rtbishop.look4sat.framework
|
||||||
|
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
@@ -25,7 +25,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.cancelAndJoin
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class DataReporter(private val reporterScope: CoroutineScope) {
|
class NetworkReporter(private val reporterScope: CoroutineScope) {
|
||||||
|
|
||||||
private var rotationSocketChannel: SocketChannel? = null
|
private var rotationSocketChannel: SocketChannel? = null
|
||||||
private var rotationReporting: Job? = null
|
private var rotationReporting: Job? = null
|
||||||
+19
-30
@@ -21,47 +21,36 @@ import android.hardware.Sensor
|
|||||||
import android.hardware.SensorEvent
|
import android.hardware.SensorEvent
|
||||||
import android.hardware.SensorEventListener
|
import android.hardware.SensorEventListener
|
||||||
import android.hardware.SensorManager
|
import android.hardware.SensorManager
|
||||||
import com.rtbishop.look4sat.domain.predict.RAD2DEG
|
import com.rtbishop.look4sat.domain.RAD2DEG
|
||||||
import javax.inject.Inject
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import javax.inject.Singleton
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
@Singleton
|
class OrientationSource(
|
||||||
class OrientationManager @Inject constructor(private val sensorManager: SensorManager) :
|
private val manager: SensorManager, private val sensor: Sensor?
|
||||||
SensorEventListener {
|
) : SensorEventListener {
|
||||||
|
|
||||||
interface OrientationListener {
|
|
||||||
fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
|
|
||||||
private val rotationMatrix = FloatArray(9)
|
private val rotationMatrix = FloatArray(9)
|
||||||
private val orientationValues = FloatArray(3)
|
private val orientationValues = FloatArray(3)
|
||||||
private var sensorAccuracy: Int = SensorManager.SENSOR_STATUS_UNRELIABLE
|
private var sensorAccuracy: Int = SensorManager.SENSOR_STATUS_UNRELIABLE
|
||||||
private var orientationListener: OrientationListener? = null
|
|
||||||
|
|
||||||
fun startListening(listener: OrientationListener) {
|
private val _orientation = MutableStateFlow(Pair(0f, 0f))
|
||||||
if (sensor != null && orientationListener !== listener) {
|
val orientation: StateFlow<Pair<Float, Float>> = _orientation
|
||||||
orientationListener = listener
|
|
||||||
sensorManager.registerListener(this, sensor, 16000)
|
fun startListening() = sensor?.let {
|
||||||
} else return
|
manager.registerListener(this, it, 16000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopListening() {
|
fun stopListening() = manager.unregisterListener(this)
|
||||||
sensorManager.unregisterListener(this)
|
|
||||||
orientationListener = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
|
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
|
||||||
sensorAccuracy = accuracy
|
sensorAccuracy = accuracy
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSensorChanged(event: SensorEvent) {
|
override fun onSensorChanged(event: SensorEvent) = when {
|
||||||
when {
|
sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE -> {}
|
||||||
orientationListener == null -> return
|
event.sensor == sensor -> updateOrientation(event.values)
|
||||||
sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE -> return
|
else -> {}
|
||||||
event.sensor == sensor -> updateOrientation(event.values)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateOrientation(rotationVector: FloatArray) {
|
private fun updateOrientation(rotationVector: FloatArray) {
|
||||||
@@ -69,11 +58,11 @@ class OrientationManager @Inject constructor(private val sensorManager: SensorMa
|
|||||||
SensorManager.getOrientation(rotationMatrix, orientationValues)
|
SensorManager.getOrientation(rotationMatrix, orientationValues)
|
||||||
val azimuth = (orientationValues[0] * RAD2DEG).toFloat()
|
val azimuth = (orientationValues[0] * RAD2DEG).toFloat()
|
||||||
val pitch = (orientationValues[1] * RAD2DEG).toFloat()
|
val pitch = (orientationValues[1] * RAD2DEG).toFloat()
|
||||||
val roll = (orientationValues[2] * RAD2DEG).toFloat()
|
// val roll = (orientationValues[2] * RAD2DEG).toFloat()
|
||||||
val magneticAzimuth = (azimuth + 360f) % 360f
|
val magneticAzimuth = (azimuth + 360f) % 360f
|
||||||
val roundedAzimuth = round(magneticAzimuth * 10) / 10
|
val roundedAzimuth = round(magneticAzimuth * 10) / 10
|
||||||
val roundedPitch = round(pitch * 10) / 10
|
val roundedPitch = round(pitch * 10) / 10
|
||||||
val roundedRoll = round(roll * 10) / 10
|
// val roundedRoll = round(roll * 10) / 10
|
||||||
orientationListener?.onOrientationChanged(roundedAzimuth, roundedPitch, roundedRoll)
|
_orientation.value = Pair(roundedAzimuth, roundedPitch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+15
-24
@@ -19,13 +19,10 @@ package com.rtbishop.look4sat.framework
|
|||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
import com.rtbishop.look4sat.domain.ISettingsSource
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.model.StationPos
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
class SettingsSource(private val prefs: SharedPreferences) : ISettingsSource {
|
||||||
class SettingsManager @Inject constructor(private val prefs: SharedPreferences) : ISettingsManager {
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val keyModes = "satModes"
|
const val keyModes = "satModes"
|
||||||
@@ -46,29 +43,23 @@ class SettingsManager @Inject constructor(private val prefs: SharedPreferences)
|
|||||||
const val keyLatitude = "stationLat"
|
const val keyLatitude = "stationLat"
|
||||||
const val keyLongitude = "stationLon"
|
const val keyLongitude = "stationLon"
|
||||||
const val keyLocator = "stationQTH"
|
const val keyLocator = "stationQTH"
|
||||||
|
const val keyLocTimestamp = "locTimestamp"
|
||||||
const val keySelection = "selection"
|
const val keySelection = "selection"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadStationLocator(): String {
|
override fun loadStationPosition(): StationPos {
|
||||||
return prefs.getString(keyLocator, null) ?: ""
|
val latitude = prefs.getString(keyLatitude, null) ?: "0.0"
|
||||||
|
val longitude = prefs.getString(keyLongitude, null) ?: "0.0"
|
||||||
|
val qthLocator = prefs.getString(keyLocator, null) ?: ""
|
||||||
|
val timestamp = prefs.getLong(keyLocTimestamp, 0L)
|
||||||
|
return StationPos(latitude.toDouble(), longitude.toDouble(), qthLocator, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveStationLocator(locator: String) {
|
override fun saveStationPosition(stationPos: StationPos) = prefs.edit {
|
||||||
prefs.edit { putString(keyLocator, locator) }
|
putString(keyLatitude, stationPos.latitude.toString())
|
||||||
}
|
putString(keyLongitude, stationPos.longitude.toString())
|
||||||
|
putString(keyLocator, stationPos.qthLocator)
|
||||||
override fun loadStationPosition(): GeoPos {
|
putLong(keyLocTimestamp, stationPos.timestamp)
|
||||||
val defaultSP = "0.0"
|
|
||||||
val latitude = prefs.getString(keyLatitude, null) ?: defaultSP
|
|
||||||
val longitude = prefs.getString(keyLongitude, null) ?: defaultSP
|
|
||||||
return GeoPos(latitude.toDouble(), longitude.toDouble())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveStationPosition(position: GeoPos) {
|
|
||||||
prefs.edit {
|
|
||||||
putString(keyLatitude, position.lat.toString())
|
|
||||||
putString(keyLongitude, position.lon.toString())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveEntriesSelection(catnums: List<Int>) {
|
override fun saveEntriesSelection(catnums: List<Int>) {
|
||||||
+1
-1
@@ -27,7 +27,7 @@ import com.rtbishop.look4sat.framework.model.SatEntry
|
|||||||
import com.rtbishop.look4sat.framework.model.SatRadio
|
import com.rtbishop.look4sat.framework.model.SatRadio
|
||||||
|
|
||||||
@Database(entities = [SatEntry::class, SatRadio::class], version = 2, exportSchema = true)
|
@Database(entities = [SatEntry::class, SatRadio::class], version = 2, exportSchema = true)
|
||||||
abstract class LocalDatabase : RoomDatabase() {
|
abstract class MainDatabase : RoomDatabase() {
|
||||||
|
|
||||||
abstract fun entriesDao(): EntriesDao
|
abstract fun entriesDao(): EntriesDao
|
||||||
|
|
||||||
+6
-6
@@ -15,17 +15,17 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.framework.data
|
package com.rtbishop.look4sat.framework.data.local
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.data.ILocalEntrySource
|
import com.rtbishop.look4sat.data.IEntriesStorage
|
||||||
import com.rtbishop.look4sat.domain.predict.Satellite
|
import com.rtbishop.look4sat.domain.Satellite
|
||||||
import com.rtbishop.look4sat.framework.data.dao.EntriesDao
|
import com.rtbishop.look4sat.framework.data.dao.EntriesDao
|
||||||
import com.rtbishop.look4sat.domain.model.SatEntry as DomainEntry
|
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem as DomainItem
|
|
||||||
import com.rtbishop.look4sat.framework.model.SatEntry as FrameworkEntry
|
import com.rtbishop.look4sat.framework.model.SatEntry as FrameworkEntry
|
||||||
import com.rtbishop.look4sat.framework.model.SatItem as FrameworkItem
|
import com.rtbishop.look4sat.framework.model.SatItem as FrameworkItem
|
||||||
|
import com.rtbishop.look4sat.model.SatEntry as DomainEntry
|
||||||
|
import com.rtbishop.look4sat.model.SatItem as DomainItem
|
||||||
|
|
||||||
class LocalEntrySource(private val entriesDao: EntriesDao) : ILocalEntrySource {
|
class EntriesStorage(private val entriesDao: EntriesDao) : IEntriesStorage {
|
||||||
|
|
||||||
override fun getEntriesTotal() = entriesDao.getEntriesTotal()
|
override fun getEntriesTotal() = entriesDao.getEntriesTotal()
|
||||||
|
|
||||||
+5
-6
@@ -15,14 +15,14 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.framework.data
|
package com.rtbishop.look4sat.framework.data.local
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio as DomainRadio
|
import com.rtbishop.look4sat.data.IRadiosStorage
|
||||||
import com.rtbishop.look4sat.framework.model.SatRadio as FrameworkRadio
|
|
||||||
import com.rtbishop.look4sat.domain.data.ILocalRadioSource
|
|
||||||
import com.rtbishop.look4sat.framework.data.dao.RadiosDao
|
import com.rtbishop.look4sat.framework.data.dao.RadiosDao
|
||||||
|
import com.rtbishop.look4sat.framework.model.SatRadio as FrameworkRadio
|
||||||
|
import com.rtbishop.look4sat.model.SatRadio as DomainRadio
|
||||||
|
|
||||||
class LocalRadioSource(private val radiosDao: RadiosDao) : ILocalRadioSource {
|
class RadiosStorage(private val radiosDao: RadiosDao) : IRadiosStorage {
|
||||||
|
|
||||||
override fun getRadiosTotal() = radiosDao.getRadiosTotal()
|
override fun getRadiosTotal() = radiosDao.getRadiosTotal()
|
||||||
|
|
||||||
@@ -31,7 +31,6 @@ class LocalRadioSource(private val radiosDao: RadiosDao) : ILocalRadioSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun insertRadios(radios: List<DomainRadio>) {
|
override suspend fun insertRadios(radios: List<DomainRadio>) {
|
||||||
radiosDao.deleteRadios()
|
|
||||||
radiosDao.insertRadios(radios.toFrameworkRadios())
|
radiosDao.insertRadios(radios.toFrameworkRadios())
|
||||||
}
|
}
|
||||||
|
|
||||||
+6
-7
@@ -15,22 +15,21 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.framework.data
|
package com.rtbishop.look4sat.framework.data.remote
|
||||||
|
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.rtbishop.look4sat.domain.data.IFileDataSource
|
import com.rtbishop.look4sat.data.IFileSource
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
class FileDataSource(
|
class FileSource(
|
||||||
private val contentResolver: ContentResolver,
|
private val contentResolver: ContentResolver,
|
||||||
private val ioDispatcher: CoroutineDispatcher
|
private val coroutineDispatcher: CoroutineDispatcher
|
||||||
) : IFileDataSource {
|
) : IFileSource {
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
|
||||||
override suspend fun getDataStream(uri: String): InputStream? {
|
override suspend fun getDataStream(uri: String): InputStream? {
|
||||||
return withContext(ioDispatcher) { contentResolver.openInputStream(Uri.parse(uri)) }
|
return withContext(coroutineDispatcher) { contentResolver.openInputStream(Uri.parse(uri)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
-14
@@ -15,25 +15,17 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.framework.data
|
package com.rtbishop.look4sat.framework.data.remote
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.data.IRemoteDataSource
|
import com.rtbishop.look4sat.data.INetworkSource
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
class RemoteDataSource(
|
class NetworkSource(private val coroutineDispatcher: CoroutineDispatcher) : INetworkSource {
|
||||||
private val httpClient: OkHttpClient, private val ioDispatcher: CoroutineDispatcher
|
|
||||||
) : IRemoteDataSource {
|
|
||||||
|
|
||||||
override suspend fun getDataStream(url: String): InputStream? = withContext(ioDispatcher) {
|
override suspend fun getDataStream(url: String): InputStream? {
|
||||||
try {
|
return withContext(coroutineDispatcher) { URL(url).openStream() }
|
||||||
val request = Request.Builder().url(url).build()
|
|
||||||
httpClient.newCall(request).execute().body?.byteStream()
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ package com.rtbishop.look4sat.framework.model
|
|||||||
|
|
||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import com.rtbishop.look4sat.domain.predict.OrbitalData
|
import com.rtbishop.look4sat.model.OrbitalData
|
||||||
|
|
||||||
@Entity(tableName = "entries", primaryKeys = ["catnum"])
|
@Entity(tableName = "entries", primaryKeys = ["catnum"])
|
||||||
data class SatEntry(@Embedded val data: OrbitalData, var comment: String? = null)
|
data class SatEntry(@Embedded val data: OrbitalData, var comment: String? = null)
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
|
||||||
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.injection
|
|
||||||
|
|
||||||
import android.bluetooth.BluetoothManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.hardware.SensorManager
|
|
||||||
import android.location.LocationManager
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.Provides
|
|
||||||
import dagger.hilt.InstallIn
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import dagger.hilt.components.SingletonComponent
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Module
|
|
||||||
@InstallIn(SingletonComponent::class)
|
|
||||||
object AppModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideBluetoothManager(@ApplicationContext context: Context): BluetoothManager {
|
|
||||||
return context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideLocationManager(@ApplicationContext context: Context): LocationManager {
|
|
||||||
return context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideSensorManager(@ApplicationContext context: Context): SensorManager {
|
|
||||||
return context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
|
|
||||||
return context.getSharedPreferences("default", Context.MODE_PRIVATE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
|
||||||
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.injection
|
|
||||||
|
|
||||||
import android.bluetooth.BluetoothManager
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.room.Room
|
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
|
||||||
import com.rtbishop.look4sat.domain.ILocationManager
|
|
||||||
import com.rtbishop.look4sat.domain.ISatelliteManager
|
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
|
||||||
import com.rtbishop.look4sat.domain.data.DataRepository
|
|
||||||
import com.rtbishop.look4sat.domain.predict.SatelliteManager
|
|
||||||
import com.rtbishop.look4sat.framework.LocationManager
|
|
||||||
import com.rtbishop.look4sat.framework.SettingsManager
|
|
||||||
import com.rtbishop.look4sat.framework.data.FileDataSource
|
|
||||||
import com.rtbishop.look4sat.framework.data.LocalDatabase
|
|
||||||
import com.rtbishop.look4sat.framework.data.LocalEntrySource
|
|
||||||
import com.rtbishop.look4sat.framework.data.LocalRadioSource
|
|
||||||
import com.rtbishop.look4sat.framework.data.MIGRATION_1_2
|
|
||||||
import com.rtbishop.look4sat.framework.data.RemoteDataSource
|
|
||||||
import com.rtbishop.look4sat.presentation.radarScreen.BTReporter
|
|
||||||
import com.rtbishop.look4sat.utility.DataParser
|
|
||||||
import com.rtbishop.look4sat.utility.DataReporter
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.Provides
|
|
||||||
import dagger.hilt.InstallIn
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import dagger.hilt.components.SingletonComponent
|
|
||||||
import javax.inject.Singleton
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
|
|
||||||
@Module
|
|
||||||
@InstallIn(SingletonComponent::class)
|
|
||||||
object BaseModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideDataRepository(
|
|
||||||
@ApplicationContext context: Context,
|
|
||||||
settings: ISettingsManager
|
|
||||||
): IDataRepository {
|
|
||||||
val db = Room.databaseBuilder(context, LocalDatabase::class.java, "Look4SatDb")
|
|
||||||
.addMigrations(MIGRATION_1_2).fallbackToDestructiveMigration().build()
|
|
||||||
val parser = DataParser(Dispatchers.Default)
|
|
||||||
val fileSource = FileDataSource(context.contentResolver, Dispatchers.IO)
|
|
||||||
val entries = LocalEntrySource(db.entriesDao())
|
|
||||||
val radios = LocalRadioSource(db.radiosDao())
|
|
||||||
val remoteSource = RemoteDataSource(OkHttpClient.Builder().build(), Dispatchers.IO)
|
|
||||||
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
|
||||||
return DataRepository(parser, fileSource, entries, radios, remoteSource, scope, settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideDataReporter(): DataReporter = DataReporter(CoroutineScope(Dispatchers.IO))
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideBTReporter(manager: BluetoothManager): BTReporter {
|
|
||||||
return BTReporter(manager, CoroutineScope(Dispatchers.IO))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideLocationManager(manager: LocationManager): ILocationManager = manager
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideSatelliteManager(): ISatelliteManager = SatelliteManager(Dispatchers.Default)
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideSettingsManager(manager: SettingsManager): ISettingsManager = manager
|
|
||||||
}
|
|
||||||
+6
-51
@@ -1,29 +1,5 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
|
||||||
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.presentation
|
package com.rtbishop.look4sat.presentation
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.pm.ActivityInfo
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.compose.setContent
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@@ -32,7 +8,6 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
@@ -41,31 +16,11 @@ import androidx.navigation.compose.currentBackStackEntryAsState
|
|||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.presentation.entriesScreen.EntriesScreen
|
import com.rtbishop.look4sat.presentation.entries.EntriesScreen
|
||||||
import com.rtbishop.look4sat.presentation.mapScreen.MapScreen
|
import com.rtbishop.look4sat.presentation.map.MapScreen
|
||||||
import com.rtbishop.look4sat.presentation.passesScreen.PassesScreen
|
import com.rtbishop.look4sat.presentation.passes.PassesScreen
|
||||||
import com.rtbishop.look4sat.presentation.radarScreen.RadarScreen
|
import com.rtbishop.look4sat.presentation.radar.RadarScreen
|
||||||
import com.rtbishop.look4sat.presentation.settingsScreen.SettingsScreen
|
import com.rtbishop.look4sat.presentation.settings.SettingsScreen
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class MainActivity : ComponentActivity() {
|
|
||||||
|
|
||||||
@SuppressLint("SourceLockedOrientationActivity")
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
|
||||||
installSplashScreen()
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setContent { MainTheme { MainScreen() } }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun attachBaseContext(newBase: Context?) {
|
|
||||||
val newConfig = Configuration(newBase?.resources?.configuration)
|
|
||||||
newConfig.fontScale = 1.0f
|
|
||||||
applyOverrideConfiguration(newConfig)
|
|
||||||
super.attachBaseContext(newBase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Screen(var title: String, var icon: Int, var route: String) {
|
sealed class Screen(var title: String, var icon: Int, var route: String) {
|
||||||
object Entries : Screen("Entries", R.drawable.ic_entries, "entries")
|
object Entries : Screen("Entries", R.drawable.ic_entries, "entries")
|
||||||
@@ -77,7 +32,7 @@ sealed class Screen(var title: String, var icon: Int, var route: String) {
|
|||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun MainScreen(navController: NavHostController = rememberNavController()) {
|
fun MainScreen(navController: NavHostController = rememberNavController()) {
|
||||||
Scaffold(bottomBar = { MainNavBar(navController = navController) }) { innerPadding ->
|
Scaffold(bottomBar = { MainNavBar(navController = navController) }) { innerPadding ->
|
||||||
Box(modifier = Modifier.padding(innerPadding)) { MainNavGraph(navController) }
|
Box(modifier = Modifier.padding(innerPadding)) { MainNavGraph(navController) }
|
||||||
}
|
}
|
||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.passesScreen
|
package com.rtbishop.look4sat.presentation.dialogs
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.settingsScreen
|
package com.rtbishop.look4sat.presentation.dialogs
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.passesScreen
|
package com.rtbishop.look4sat.presentation.dialogs
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.settingsScreen
|
package com.rtbishop.look4sat.presentation.dialogs
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.entriesScreen
|
package com.rtbishop.look4sat.presentation.dialogs
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
+5
-4
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.entriesScreen
|
package com.rtbishop.look4sat.presentation.entries
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -28,11 +28,12 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
import com.rtbishop.look4sat.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.model.SatItem
|
||||||
import com.rtbishop.look4sat.presentation.Screen
|
|
||||||
import com.rtbishop.look4sat.presentation.CardLoadingIndicator
|
import com.rtbishop.look4sat.presentation.CardLoadingIndicator
|
||||||
import com.rtbishop.look4sat.presentation.MainTheme
|
import com.rtbishop.look4sat.presentation.MainTheme
|
||||||
|
import com.rtbishop.look4sat.presentation.Screen
|
||||||
|
import com.rtbishop.look4sat.presentation.dialogs.TypesDialog
|
||||||
import com.rtbishop.look4sat.presentation.onClick
|
import com.rtbishop.look4sat.presentation.onClick
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
+11
-7
@@ -15,15 +15,17 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.entriesScreen
|
package com.rtbishop.look4sat.presentation.entries
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.IDataRepository
|
||||||
|
import com.rtbishop.look4sat.domain.ILocationSource
|
||||||
import com.rtbishop.look4sat.domain.ISatelliteManager
|
import com.rtbishop.look4sat.domain.ISatelliteManager
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
import com.rtbishop.look4sat.domain.ISettingsSource
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
import com.rtbishop.look4sat.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
|
import com.rtbishop.look4sat.model.SatItem
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@@ -37,7 +39,8 @@ import javax.inject.Inject
|
|||||||
class EntriesViewModel @Inject constructor(
|
class EntriesViewModel @Inject constructor(
|
||||||
private val satelliteManager: ISatelliteManager,
|
private val satelliteManager: ISatelliteManager,
|
||||||
private val repository: IDataRepository,
|
private val repository: IDataRepository,
|
||||||
private val settings: ISettingsManager
|
private val settings: ISettingsSource,
|
||||||
|
private val locationSource: ILocationSource
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val satType = MutableStateFlow("All")
|
private val satType = MutableStateFlow("All")
|
||||||
@@ -78,11 +81,12 @@ class EntriesViewModel @Inject constructor(
|
|||||||
settings.saveEntriesSelection(newSelection)
|
settings.saveEntriesSelection(newSelection)
|
||||||
val selectedIds = settings.loadEntriesSelection()
|
val selectedIds = settings.loadEntriesSelection()
|
||||||
val satellites = repository.getEntriesWithIds(selectedIds)
|
val satellites = repository.getEntriesWithIds(selectedIds)
|
||||||
val stationPos = settings.loadStationPosition()
|
val stationPos = locationSource.stationPosition.value
|
||||||
|
val geoPos = GeoPos(stationPos.latitude, stationPos.longitude)
|
||||||
val timeRef = System.currentTimeMillis()
|
val timeRef = System.currentTimeMillis()
|
||||||
val hoursAhead = settings.getHoursAhead()
|
val hoursAhead = settings.getHoursAhead()
|
||||||
val minElev = settings.getMinElevation()
|
val minElev = settings.getMinElevation()
|
||||||
satelliteManager.calculatePasses(satellites, stationPos, timeRef, hoursAhead, minElev)
|
satelliteManager.calculatePasses(satellites, geoPos, timeRef, hoursAhead, minElev)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSelection(catNums: List<Int>, isSelected: Boolean) {
|
fun updateSelection(catNums: List<Int>, isSelected: Boolean) {
|
||||||
+2
-2
@@ -15,9 +15,9 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.mapScreen
|
package com.rtbishop.look4sat.presentation.map
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
|
|
||||||
data class MapData(
|
data class MapData(
|
||||||
val catNum: Int,
|
val catNum: Int,
|
||||||
+7
-5
@@ -1,5 +1,6 @@
|
|||||||
package com.rtbishop.look4sat.presentation.mapScreen
|
package com.rtbishop.look4sat.presentation.map
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.graphics.*
|
import android.graphics.*
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
@@ -22,9 +23,9 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
|||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.domain.Satellite
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPos
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
import com.rtbishop.look4sat.domain.predict.Satellite
|
import com.rtbishop.look4sat.model.SatPos
|
||||||
import org.osmdroid.config.Configuration
|
import org.osmdroid.config.Configuration
|
||||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
||||||
import org.osmdroid.util.GeoPoint
|
import org.osmdroid.util.GeoPoint
|
||||||
@@ -60,7 +61,8 @@ private val labelRect = Rect()
|
|||||||
@Composable
|
@Composable
|
||||||
fun MapScreen(viewModel: MapViewModel = hiltViewModel()) {
|
fun MapScreen(viewModel: MapViewModel = hiltViewModel()) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Configuration.getInstance().load(context, viewModel.getPreferences())
|
val preferences = context.getSharedPreferences("default", Context.MODE_PRIVATE)
|
||||||
|
Configuration.getInstance().load(context, preferences)
|
||||||
viewModel.selectDefaultSatellite(-1)
|
viewModel.selectDefaultSatellite(-1)
|
||||||
val stationPos = viewModel.stationPos.collectAsState(initial = null)
|
val stationPos = viewModel.stationPos.collectAsState(initial = null)
|
||||||
val positions = viewModel.positions.collectAsState(initial = null)
|
val positions = viewModel.positions.collectAsState(initial = null)
|
||||||
+8
-13
@@ -15,17 +15,13 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.mapScreen
|
package com.rtbishop.look4sat.presentation.map
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.*
|
||||||
import com.rtbishop.look4sat.domain.ISatelliteManager
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
import com.rtbishop.look4sat.model.SatPos
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPos
|
|
||||||
import com.rtbishop.look4sat.domain.predict.Satellite
|
|
||||||
import com.rtbishop.look4sat.utility.QthConverter
|
import com.rtbishop.look4sat.utility.QthConverter
|
||||||
import com.rtbishop.look4sat.utility.toDegrees
|
import com.rtbishop.look4sat.utility.toDegrees
|
||||||
import com.rtbishop.look4sat.utility.toTimerString
|
import com.rtbishop.look4sat.utility.toTimerString
|
||||||
@@ -42,13 +38,14 @@ import kotlin.math.min
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class MapViewModel @Inject constructor(
|
class MapViewModel @Inject constructor(
|
||||||
private val preferences: SharedPreferences,
|
|
||||||
private val repository: IDataRepository,
|
private val repository: IDataRepository,
|
||||||
private val satelliteManager: ISatelliteManager,
|
private val satelliteManager: ISatelliteManager,
|
||||||
private val settings: ISettingsManager
|
private val settings: ISettingsSource,
|
||||||
|
private val locationSource: ILocationSource
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val stationPosition = settings.loadStationPosition()
|
private val stationPosNew = locationSource.stationPosition.value
|
||||||
|
private val stationPosition = GeoPos(stationPosNew.latitude, stationPosNew.longitude)
|
||||||
private var allPasses = satelliteManager.getPasses()
|
private var allPasses = satelliteManager.getPasses()
|
||||||
private var allSatellites = listOf<Satellite>()
|
private var allSatellites = listOf<Satellite>()
|
||||||
private var dataUpdateJob: Job? = null
|
private var dataUpdateJob: Job? = null
|
||||||
@@ -73,8 +70,6 @@ class MapViewModel @Inject constructor(
|
|||||||
private val _positions = MutableSharedFlow<Map<Satellite, GeoPos>>()
|
private val _positions = MutableSharedFlow<Map<Satellite, GeoPos>>()
|
||||||
val positions: SharedFlow<Map<Satellite, GeoPos>> = _positions
|
val positions: SharedFlow<Map<Satellite, GeoPos>> = _positions
|
||||||
|
|
||||||
fun getPreferences() = preferences
|
|
||||||
|
|
||||||
fun scrollSelection(decrement: Boolean) {
|
fun scrollSelection(decrement: Boolean) {
|
||||||
if (allSatellites.isNotEmpty()) {
|
if (allSatellites.isNotEmpty()) {
|
||||||
val index = allSatellites.indexOf(selectedSatellite)
|
val index = allSatellites.indexOf(selectedSatellite)
|
||||||
+7
-7
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.passesScreen
|
package com.rtbishop.look4sat.presentation.passes
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -23,12 +23,12 @@ import androidx.compose.ui.unit.*
|
|||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
import com.rtbishop.look4sat.domain.NearEarthSat
|
||||||
import com.rtbishop.look4sat.domain.predict.NearEarthSat
|
import com.rtbishop.look4sat.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.predict.OrbitalData
|
import com.rtbishop.look4sat.model.OrbitalData
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPass
|
import com.rtbishop.look4sat.model.SatPass
|
||||||
import com.rtbishop.look4sat.presentation.Screen
|
import com.rtbishop.look4sat.presentation.*
|
||||||
import com.rtbishop.look4sat.presentation.MainTheme
|
import com.rtbishop.look4sat.presentation.dialogs.FilterDialog
|
||||||
import com.rtbishop.look4sat.presentation.pullRefresh.PullRefreshIndicator
|
import com.rtbishop.look4sat.presentation.pullRefresh.PullRefreshIndicator
|
||||||
import com.rtbishop.look4sat.presentation.pullRefresh.PullRefreshState
|
import com.rtbishop.look4sat.presentation.pullRefresh.PullRefreshState
|
||||||
import com.rtbishop.look4sat.presentation.pullRefresh.pullRefresh
|
import com.rtbishop.look4sat.presentation.pullRefresh.pullRefresh
|
||||||
+11
-7
@@ -15,15 +15,17 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.passesScreen
|
package com.rtbishop.look4sat.presentation.passes
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.IDataRepository
|
||||||
|
import com.rtbishop.look4sat.domain.ILocationSource
|
||||||
import com.rtbishop.look4sat.domain.ISatelliteManager
|
import com.rtbishop.look4sat.domain.ISatelliteManager
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
import com.rtbishop.look4sat.domain.ISettingsSource
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
import com.rtbishop.look4sat.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPass
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
|
import com.rtbishop.look4sat.model.SatPass
|
||||||
import com.rtbishop.look4sat.utility.toTimerString
|
import com.rtbishop.look4sat.utility.toTimerString
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@@ -35,7 +37,8 @@ import javax.inject.Inject
|
|||||||
class PassesViewModel @Inject constructor(
|
class PassesViewModel @Inject constructor(
|
||||||
private val satelliteManager: ISatelliteManager,
|
private val satelliteManager: ISatelliteManager,
|
||||||
private val repository: IDataRepository,
|
private val repository: IDataRepository,
|
||||||
private val settings: ISettingsManager
|
private val settings: ISettingsSource,
|
||||||
|
private val locationSource: ILocationSource
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _passes = MutableStateFlow<DataState<List<SatPass>>>(DataState.Loading)
|
private val _passes = MutableStateFlow<DataState<List<SatPass>>>(DataState.Loading)
|
||||||
@@ -105,11 +108,12 @@ class PassesViewModel @Inject constructor(
|
|||||||
selection?.let { items -> settings.saveEntriesSelection(items) }
|
selection?.let { items -> settings.saveEntriesSelection(items) }
|
||||||
settings.setHoursAhead(hoursAhead)
|
settings.setHoursAhead(hoursAhead)
|
||||||
settings.setMinElevation(minElevation)
|
settings.setMinElevation(minElevation)
|
||||||
val stationPos = settings.loadStationPosition()
|
val stationPos = locationSource.stationPosition.value
|
||||||
|
val geoPos = GeoPos(stationPos.latitude, stationPos.longitude)
|
||||||
val selectedIds = settings.loadEntriesSelection()
|
val selectedIds = settings.loadEntriesSelection()
|
||||||
val satellites = repository.getEntriesWithIds(selectedIds)
|
val satellites = repository.getEntriesWithIds(selectedIds)
|
||||||
satelliteManager.calculatePasses(
|
satelliteManager.calculatePasses(
|
||||||
satellites, stationPos, timeRef, hoursAhead, minElevation
|
satellites, geoPos, timeRef, hoursAhead, minElevation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -15,8 +15,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.radarScreen
|
package com.rtbishop.look4sat.presentation.radar
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPos
|
import com.rtbishop.look4sat.model.SatPos
|
||||||
|
|
||||||
data class RadarData(val satPos: SatPos, val satTrack: List<SatPos> = emptyList())
|
data class RadarData(val satPos: SatPos, val satTrack: List<SatPos> = emptyList())
|
||||||
+9
-20
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.radarScreen
|
package com.rtbishop.look4sat.presentation.radar
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
@@ -18,15 +18,12 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.model.SatRadio
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RadarScreen(navController: NavController) {
|
fun RadarScreen(navController: NavController) {
|
||||||
val viewModel: RadarViewModel = hiltViewModel()
|
val viewModel: RadarViewModel = hiltViewModel()
|
||||||
val currentPass = viewModel.getPass().collectAsState(null)
|
val currentPass = viewModel.getPass().collectAsState(null)
|
||||||
val radarData = viewModel.radarData.collectAsState()
|
|
||||||
val transmitters = viewModel.transmitters.collectAsState()
|
|
||||||
val orientation = viewModel.orientation.collectAsState()
|
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
ElevatedCard(modifier = Modifier.height(52.dp)) {
|
ElevatedCard(modifier = Modifier.height(52.dp)) {
|
||||||
@@ -62,20 +59,18 @@ fun RadarScreen(navController: NavController) {
|
|||||||
ElevatedCard(modifier = Modifier
|
ElevatedCard(modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.weight(1f)) {
|
.weight(1f)) {
|
||||||
radarData.value?.let { data ->
|
viewModel.radarData.value?.let { data ->
|
||||||
orientation.value?.let { triple ->
|
RadarViewCompose(
|
||||||
RadarViewCompose(
|
item = data.satPos,
|
||||||
item = data.satPos,
|
items = data.satTrack,
|
||||||
items = data.satTrack,
|
azimElev = viewModel.orientation.value
|
||||||
orientation = triple
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ElevatedCard(modifier = Modifier
|
ElevatedCard(modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.weight(1f)) {
|
.weight(1f)) {
|
||||||
TransmittersList(transmitters = transmitters.value)
|
TransmittersList(transmitters = viewModel.transmitters.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,15 +156,9 @@ private fun TransmitterItem(radio: SatRadio) {
|
|||||||
// setShowAim(viewModel.getUseCompass())
|
// setShowAim(viewModel.getUseCompass())
|
||||||
// setScanning(viewModel.getShowSweep())
|
// setScanning(viewModel.getShowSweep())
|
||||||
// }
|
// }
|
||||||
// radarCard.addView(radarView)
|
|
||||||
// viewModel.radarData.observe(viewLifecycleOwner) { passData ->
|
// viewModel.radarData.observe(viewLifecycleOwner) { passData ->
|
||||||
// radarView?.setPosition(passData.satPos)
|
|
||||||
// radarView?.setPositions(passData.satTrack)
|
|
||||||
// setPassText(pass, passData.satPos)
|
// setPassText(pass, passData.satPos)
|
||||||
// }
|
// }
|
||||||
// viewModel.orientation.observe(viewLifecycleOwner) { value ->
|
|
||||||
// radarView?.setOrientation(value.first, value.second, value.third)
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
+6
-6
@@ -1,6 +1,6 @@
|
|||||||
@file:OptIn(ExperimentalTextApi::class)
|
@file:OptIn(ExperimentalTextApi::class)
|
||||||
|
|
||||||
package com.rtbishop.look4sat.presentation.radarScreen
|
package com.rtbishop.look4sat.presentation.radar
|
||||||
|
|
||||||
import androidx.compose.animation.core.*
|
import androidx.compose.animation.core.*
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
@@ -14,14 +14,14 @@ import androidx.compose.ui.graphics.*
|
|||||||
import androidx.compose.ui.graphics.drawscope.*
|
import androidx.compose.ui.graphics.drawscope.*
|
||||||
import androidx.compose.ui.text.*
|
import androidx.compose.ui.text.*
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.rtbishop.look4sat.domain.predict.PI_2
|
import com.rtbishop.look4sat.domain.PI_2
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPos
|
import com.rtbishop.look4sat.model.SatPos
|
||||||
import com.rtbishop.look4sat.utility.toRadians
|
import com.rtbishop.look4sat.utility.toRadians
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RadarViewCompose(item: SatPos, items: List<SatPos>, orientation: Triple<Float, Float, Float>) {
|
fun RadarViewCompose(item: SatPos, items: List<SatPos>, azimElev: Pair<Float, Float>) {
|
||||||
val radarColor = Color(0xFFDCDCDC)
|
val radarColor = Color(0xFFDCDCDC)
|
||||||
val primaryColor = Color(0xFFFFE082)
|
val primaryColor = Color(0xFFFFE082)
|
||||||
val secondaryColor = Color(0xFFDC0000)
|
val secondaryColor = Color(0xFFDC0000)
|
||||||
@@ -41,14 +41,14 @@ fun RadarViewCompose(item: SatPos, items: List<SatPos>, orientation: Triple<Floa
|
|||||||
trackEffect.value = createTrackEffect(trackPath.value)
|
trackEffect.value = createTrackEffect(trackPath.value)
|
||||||
trackCreated.value = true
|
trackCreated.value = true
|
||||||
}
|
}
|
||||||
rotate(-orientation.first) {
|
rotate(-azimElev.first) {
|
||||||
drawSweep(center, sweepDegrees.value, radius, primaryColor)
|
drawSweep(center, sweepDegrees.value, radius, primaryColor)
|
||||||
drawRadar(radius, radarColor, strokeWidth, 3)
|
drawRadar(radius, radarColor, strokeWidth, 3)
|
||||||
drawInfo(radius, primaryColor, measurer, 3)
|
drawInfo(radius, primaryColor, measurer, 3)
|
||||||
translate(center.x, center.y) {
|
translate(center.x, center.y) {
|
||||||
drawTrack(trackPath.value, trackEffect.value, secondaryColor, primaryColor)
|
drawTrack(trackPath.value, trackEffect.value, secondaryColor, primaryColor)
|
||||||
if (item.elevation > 0) drawPosition(item, radius, animScale.value, primaryColor)
|
if (item.elevation > 0) drawPosition(item, radius, animScale.value, primaryColor)
|
||||||
drawAim(orientation.first, orientation.second, radius, strokeWidth, secondaryColor)
|
drawAim(azimElev.first, azimElev.second, radius, strokeWidth, secondaryColor)
|
||||||
}
|
}
|
||||||
sweepDegrees.value = (sweepDegrees.value + 360 / 12.0f / 60) % 360
|
sweepDegrees.value = (sweepDegrees.value + 360 / 12.0f / 60) % 360
|
||||||
}
|
}
|
||||||
+36
-45
@@ -15,29 +15,26 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.radarScreen
|
package com.rtbishop.look4sat.presentation.radar
|
||||||
|
|
||||||
import android.hardware.GeomagneticField
|
import android.hardware.GeomagneticField
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.*
|
||||||
import com.rtbishop.look4sat.domain.ISatelliteManager
|
import com.rtbishop.look4sat.framework.BluetoothReporter
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
import com.rtbishop.look4sat.framework.NetworkReporter
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.framework.OrientationSource
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPass
|
import com.rtbishop.look4sat.model.SatPass
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPos
|
import com.rtbishop.look4sat.model.SatPos
|
||||||
import com.rtbishop.look4sat.domain.predict.Satellite
|
import com.rtbishop.look4sat.model.SatRadio
|
||||||
import com.rtbishop.look4sat.framework.OrientationManager
|
|
||||||
import com.rtbishop.look4sat.utility.DataReporter
|
|
||||||
import com.rtbishop.look4sat.utility.round
|
import com.rtbishop.look4sat.utility.round
|
||||||
import com.rtbishop.look4sat.utility.toDegrees
|
import com.rtbishop.look4sat.utility.toDegrees
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -46,28 +43,34 @@ import javax.inject.Inject
|
|||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class RadarViewModel @Inject constructor(
|
class RadarViewModel @Inject constructor(
|
||||||
private val savedStateHandle: SavedStateHandle,
|
private val savedStateHandle: SavedStateHandle,
|
||||||
private val orientationManager: OrientationManager,
|
private val orientationSource: OrientationSource,
|
||||||
private val reporter: DataReporter,
|
private val reporter: NetworkReporter,
|
||||||
private val btReporter: BTReporter,
|
private val bluetoothReporter: BluetoothReporter,
|
||||||
private val satManager: ISatelliteManager,
|
private val satManager: ISatelliteManager,
|
||||||
private val repository: IDataRepository,
|
private val repository: IDataRepository,
|
||||||
private val settings: ISettingsManager
|
private val settings: ISettingsSource,
|
||||||
) : ViewModel(), OrientationManager.OrientationListener {
|
private val locationSource: ILocationSource
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
private val stationPos = settings.loadStationPosition()
|
private val stationPos = locationSource.stationPosition.value.toGeoPos()
|
||||||
private val _passData = MutableStateFlow<RadarData?>(null)
|
private val magDeclination = getMagDeclination(stationPos)
|
||||||
private val _transmitters = MutableStateFlow<List<SatRadio>>(emptyList())
|
val transmitters = mutableStateOf<List<SatRadio>>(emptyList())
|
||||||
private val _orientation = MutableStateFlow<Triple<Float, Float, Float>?>(null)
|
val radarData = mutableStateOf<RadarData?>(null)
|
||||||
val radarData: StateFlow<RadarData?> = _passData
|
val orientation = mutableStateOf(orientationSource.orientation.value)
|
||||||
val transmitters: StateFlow<List<SatRadio>> = _transmitters
|
|
||||||
val orientation: StateFlow<Triple<Float, Float, Float>?> = _orientation
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
enableSensor()
|
if (settings.isSensorEnabled()) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
orientationSource.startListening()
|
||||||
|
orientationSource.orientation.collect { data ->
|
||||||
|
orientation.value = Pair(data.first + magDeclination, data.second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
disableSensor()
|
orientationSource.stopListening()
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,22 +97,10 @@ class RadarViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun enableSensor() {
|
|
||||||
if (settings.isSensorEnabled()) orientationManager.startListening(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun disableSensor() {
|
|
||||||
if (settings.isSensorEnabled()) orientationManager.stopListening()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getUseCompass(): Boolean = settings.isSensorEnabled()
|
fun getUseCompass(): Boolean = settings.isSensorEnabled()
|
||||||
|
|
||||||
fun getShowSweep(): Boolean = settings.isSweepEnabled()
|
fun getShowSweep(): Boolean = settings.isSweepEnabled()
|
||||||
|
|
||||||
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
|
|
||||||
_orientation.value = Triple(azimuth + getMagDeclination(stationPos), pitch, roll)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getMagDeclination(geoPos: GeoPos, time: Long = System.currentTimeMillis()): Float {
|
private fun getMagDeclination(geoPos: GeoPos, time: Long = System.currentTimeMillis()): Float {
|
||||||
val latitude = geoPos.lat.toFloat()
|
val latitude = geoPos.lat.toFloat()
|
||||||
val longitude = geoPos.lon.toFloat()
|
val longitude = geoPos.lon.toFloat()
|
||||||
@@ -129,7 +120,7 @@ class RadarViewModel @Inject constructor(
|
|||||||
val elevation = satPos.elevation.toDegrees().round(1)
|
val elevation = satPos.elevation.toDegrees().round(1)
|
||||||
reporter.reportRotation(server, port, azimuth, elevation)
|
reporter.reportRotation(server, port, azimuth, elevation)
|
||||||
}
|
}
|
||||||
_passData.value = RadarData(satPos, track)
|
radarData.value = RadarData(satPos, track)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,14 +128,14 @@ class RadarViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (settings.getBTEnabled()) {
|
if (settings.getBTEnabled()) {
|
||||||
val btDevice = settings.getBTDeviceAddr()
|
val btDevice = settings.getBTDeviceAddr()
|
||||||
if (btReporter.isConnected()) {
|
if (bluetoothReporter.isConnected()) {
|
||||||
val format = settings.getBTFormat()
|
val format = settings.getBTFormat()
|
||||||
val azimuth = satPos.azimuth.toDegrees().round(0).toInt()
|
val azimuth = satPos.azimuth.toDegrees().round(0).toInt()
|
||||||
val elevation = satPos.elevation.toDegrees().round(0).toInt()
|
val elevation = satPos.elevation.toDegrees().round(0).toInt()
|
||||||
btReporter.reportRotation(format, azimuth, elevation)
|
bluetoothReporter.reportRotation(format, azimuth, elevation)
|
||||||
} else if (!btReporter.isConnecting()) {
|
} else if (!bluetoothReporter.isConnecting()) {
|
||||||
Log.i("BTReporter", "BTReporter: Attempting to connect...")
|
Log.i("BTReporter", "BTReporter: Attempting to connect...")
|
||||||
btReporter.connectBTDevice(btDevice)
|
bluetoothReporter.connectBTDevice(btDevice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,7 +145,7 @@ class RadarViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
delay(125)
|
delay(125)
|
||||||
val list = satManager.processRadios(satellite, stationPos, radios, time)
|
val list = satManager.processRadios(satellite, stationPos, radios, time)
|
||||||
_transmitters.value = list
|
transmitters.value = list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-3
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.settingsScreen
|
package com.rtbishop.look4sat.presentation.settings
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@@ -26,6 +26,8 @@ import com.rtbishop.look4sat.BuildConfig
|
|||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.presentation.CardButton
|
import com.rtbishop.look4sat.presentation.CardButton
|
||||||
import com.rtbishop.look4sat.presentation.MainTheme
|
import com.rtbishop.look4sat.presentation.MainTheme
|
||||||
|
import com.rtbishop.look4sat.presentation.dialogs.LocatorDialog
|
||||||
|
import com.rtbishop.look4sat.presentation.dialogs.PositionDialog
|
||||||
import com.rtbishop.look4sat.presentation.gotoUrl
|
import com.rtbishop.look4sat.presentation.gotoUrl
|
||||||
import com.rtbishop.look4sat.presentation.showToast
|
import com.rtbishop.look4sat.presentation.showToast
|
||||||
|
|
||||||
@@ -57,8 +59,8 @@ fun SettingsScreen(navController: NavController) {
|
|||||||
val locationPermFine = Manifest.permission.ACCESS_FINE_LOCATION
|
val locationPermFine = Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
val locationRequest = rememberLauncherForActivityResult(locationContract) { permissions ->
|
val locationRequest = rememberLauncherForActivityResult(locationContract) { permissions ->
|
||||||
when {
|
when {
|
||||||
permissions[locationPermFine] == true -> viewModel.locationSettings.value.setGpsLoc
|
permissions[locationPermFine] == true -> viewModel.locationSettings.value.setGpsLoc()
|
||||||
permissions[locationPermCoarse] == true -> viewModel.locationSettings.value.setGpsLoc
|
permissions[locationPermCoarse] == true -> viewModel.locationSettings.value.setGpsLoc()
|
||||||
else -> showToast(context, locationError)
|
else -> showToast(context, locationError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.rtbishop.look4sat.presentation.settingsScreen
|
package com.rtbishop.look4sat.presentation.settings
|
||||||
|
|
||||||
data class LocationSettings(
|
data class LocationSettings(
|
||||||
val getUpdating: Boolean,
|
val getUpdating: Boolean,
|
||||||
+17
-22
@@ -15,15 +15,15 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.settingsScreen
|
package com.rtbishop.look4sat.presentation.settings
|
||||||
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.IDataRepository
|
||||||
import com.rtbishop.look4sat.domain.ILocationManager
|
import com.rtbishop.look4sat.domain.ILocationSource
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
import com.rtbishop.look4sat.domain.ISettingsSource
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
import com.rtbishop.look4sat.model.DataState
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -31,21 +31,20 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SettingsViewModel @Inject constructor(
|
class SettingsViewModel @Inject constructor(
|
||||||
private val locationManager: ILocationManager,
|
private val locationSource: ILocationSource,
|
||||||
private val repository: IDataRepository,
|
private val repository: IDataRepository,
|
||||||
private val settings: ISettingsManager
|
private val settings: ISettingsSource
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val defaultLocationSettings = LocationSettings(false,
|
private val defaultLocationSettings = LocationSettings(false,
|
||||||
settings.getLastUpdateTime(),
|
locationSource.stationPosition.value.timestamp,
|
||||||
locationManager.getStationPosition().lat,
|
locationSource.stationPosition.value.latitude,
|
||||||
locationManager.getStationPosition().lon,
|
locationSource.stationPosition.value.longitude,
|
||||||
settings.loadStationLocator(),
|
locationSource.stationPosition.value.qthLocator,
|
||||||
{ locationManager.setPositionFromGps() },
|
{ locationSource.setGpsPosition() },
|
||||||
{ lat, lon -> locationManager.setStationPosition(lat, lon) },
|
{ lat, lon -> locationSource.setGeoPosition(lat, lon) },
|
||||||
{ locationManager.setPositionFromQth(it) })
|
{ locationSource.setQthPosition(it) })
|
||||||
var locationSettings = mutableStateOf(defaultLocationSettings)
|
val locationSettings = mutableStateOf(defaultLocationSettings)
|
||||||
private set
|
|
||||||
|
|
||||||
private val defaultDataSettings = DataSettings(false,
|
private val defaultDataSettings = DataSettings(false,
|
||||||
settings.getLastUpdateTime(),
|
settings.getLastUpdateTime(),
|
||||||
@@ -54,8 +53,7 @@ class SettingsViewModel @Inject constructor(
|
|||||||
{ repository.updateFromWeb() },
|
{ repository.updateFromWeb() },
|
||||||
{ repository.updateFromFile(it) },
|
{ repository.updateFromFile(it) },
|
||||||
{ repository.clearAllData() })
|
{ repository.clearAllData() })
|
||||||
var dataSettings = mutableStateOf(defaultDataSettings)
|
val dataSettings = mutableStateOf(defaultDataSettings)
|
||||||
private set
|
|
||||||
|
|
||||||
private val defaultOtherSettings = OtherSettings(settings.isUtcEnabled(),
|
private val defaultOtherSettings = OtherSettings(settings.isUtcEnabled(),
|
||||||
settings.isUpdateEnabled(),
|
settings.isUpdateEnabled(),
|
||||||
@@ -65,8 +63,7 @@ class SettingsViewModel @Inject constructor(
|
|||||||
{ setUpdate(it) },
|
{ setUpdate(it) },
|
||||||
{ setSweep(it) },
|
{ setSweep(it) },
|
||||||
{ setSensor(it) })
|
{ setSensor(it) })
|
||||||
var otherSettings = mutableStateOf(defaultOtherSettings)
|
val otherSettings = mutableStateOf(defaultOtherSettings)
|
||||||
private set
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@@ -81,9 +78,7 @@ class SettingsViewModel @Inject constructor(
|
|||||||
combine(repository.getEntriesTotal(), repository.getRadiosTotal()) { sats, radios ->
|
combine(repository.getEntriesTotal(), repository.getRadiosTotal()) { sats, radios ->
|
||||||
dataSettings.value =
|
dataSettings.value =
|
||||||
dataSettings.value.copy(getSatellites = sats, getRadios = radios)
|
dataSettings.value.copy(getSatellites = sats, getRadios = radios)
|
||||||
}.collect {
|
}.collect {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+36
-40
@@ -15,50 +15,52 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.utility
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.model.OrbitalData
|
||||||
import com.rtbishop.look4sat.domain.predict.OrbitalData
|
import com.rtbishop.look4sat.model.SatRadio
|
||||||
import java.io.InputStream
|
|
||||||
import kotlin.math.pow
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.io.InputStream
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
class DataParser(private val defaultDispatcher: CoroutineDispatcher) {
|
class DataParser(private val defaultDispatcher: CoroutineDispatcher) {
|
||||||
|
|
||||||
suspend fun parseCSVStream(csvStream: InputStream): List<OrbitalData> = withContext(defaultDispatcher) {
|
suspend fun parseCSVStream(csvStream: InputStream): List<OrbitalData> =
|
||||||
val parsedItems = mutableListOf<OrbitalData>()
|
withContext(defaultDispatcher) {
|
||||||
csvStream.bufferedReader().useLines { lines ->
|
val parsedItems = mutableListOf<OrbitalData>()
|
||||||
lines.forEachIndexed { index, line ->
|
csvStream.bufferedReader().useLines { lines ->
|
||||||
if (index != 0) {
|
lines.forEachIndexed { index, line ->
|
||||||
val values = line.split(",")
|
if (index != 0) {
|
||||||
parseCSV(values)?.let { tle -> parsedItems.add(tle) }
|
val values = line.split(",")
|
||||||
|
parseCSV(values)?.let { tle -> parsedItems.add(tle) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return@withContext parsedItems
|
||||||
}
|
}
|
||||||
return@withContext parsedItems
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun parseTLEStream(tleStream: InputStream): List<OrbitalData> = withContext(defaultDispatcher) {
|
suspend fun parseTLEStream(tleStream: InputStream): List<OrbitalData> =
|
||||||
val tleStrings = mutableListOf(String(), String(), String())
|
withContext(defaultDispatcher) {
|
||||||
val parsedItems = mutableListOf<OrbitalData>()
|
val tleStrings = mutableListOf(String(), String(), String())
|
||||||
var lineIndex = 0
|
val parsedItems = mutableListOf<OrbitalData>()
|
||||||
tleStream.bufferedReader().forEachLine { line ->
|
var lineIndex = 0
|
||||||
tleStrings[lineIndex] = line
|
tleStream.bufferedReader().forEachLine { line ->
|
||||||
if (lineIndex < 2) {
|
tleStrings[lineIndex] = line
|
||||||
lineIndex++
|
if (lineIndex < 2) {
|
||||||
} else {
|
lineIndex++
|
||||||
val isLineOneValid = tleStrings[1].substring(0, 1) == "1"
|
} else {
|
||||||
val isLineTwoValid = tleStrings[2].substring(0, 1) == "2"
|
val isLineOneValid = tleStrings[1].substring(0, 1) == "1"
|
||||||
if (!isLineOneValid && !isLineTwoValid) return@forEachLine
|
val isLineTwoValid = tleStrings[2].substring(0, 1) == "2"
|
||||||
parseTLE(tleStrings)?.let { tle -> parsedItems.add(tle) }
|
if (!isLineOneValid && !isLineTwoValid) return@forEachLine
|
||||||
lineIndex = 0
|
parseTLE(tleStrings)?.let { tle -> parsedItems.add(tle) }
|
||||||
|
lineIndex = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return@withContext parsedItems
|
||||||
}
|
}
|
||||||
return@withContext parsedItems
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun parseJSONStream(jsonStream: InputStream): List<SatRadio> {
|
suspend fun parseJSONStream(jsonStream: InputStream): List<SatRadio> {
|
||||||
return withContext(defaultDispatcher) {
|
return withContext(defaultDispatcher) {
|
||||||
@@ -76,10 +78,6 @@ class DataParser(private val defaultDispatcher: CoroutineDispatcher) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isLeapYear(year: Int): Boolean {
|
|
||||||
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseCSV(values: List<String>): OrbitalData? {
|
private fun parseCSV(values: List<String>): OrbitalData? {
|
||||||
try {
|
try {
|
||||||
val name = values[0]
|
val name = values[0]
|
||||||
@@ -122,8 +120,8 @@ class DataParser(private val defaultDispatcher: CoroutineDispatcher) {
|
|||||||
val argper: Double = tle[2].substring(34, 42).toDouble()
|
val argper: Double = tle[2].substring(34, 42).toDouble()
|
||||||
val meanan: Double = tle[2].substring(43, 51).toDouble()
|
val meanan: Double = tle[2].substring(43, 51).toDouble()
|
||||||
val catnum: Int = tle[1].substring(2, 7).trim().toInt()
|
val catnum: Int = tle[1].substring(2, 7).trim().toInt()
|
||||||
val bstar: Double =
|
val bstar: Double = 1.0e-5 * tle[1].substring(53, 59).toDouble() /
|
||||||
1.0e-5 * tle[1].substring(53, 59).toDouble() / 10.0.pow(tle[1].substring(60, 61).toDouble())
|
10.0.pow(tle[1].substring(60, 61).toDouble())
|
||||||
return OrbitalData(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar)
|
return OrbitalData(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
return null
|
return null
|
||||||
@@ -155,10 +153,8 @@ class DataParser(private val defaultDispatcher: CoroutineDispatcher) {
|
|||||||
val daysArray = arrayOf(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
|
val daysArray = arrayOf(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
|
||||||
var dayOfYear = dayOfMonth
|
var dayOfYear = dayOfMonth
|
||||||
// If leap year increment Feb days
|
// If leap year increment Feb days
|
||||||
if (isLeapYear(year)) daysArray[1]++
|
if (((year / 4 == 0) && (year / 100 != 0)) || (year / 400 == 0)) daysArray[1]++
|
||||||
for (i in 0 until month - 1) {
|
for (i in 0 until month - 1) { dayOfYear += daysArray[i] }
|
||||||
dayOfYear += daysArray[i]
|
|
||||||
}
|
|
||||||
return dayOfYear
|
return dayOfYear
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+10
-11
@@ -15,13 +15,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.data
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.IDataRepository
|
||||||
import com.rtbishop.look4sat.domain.ISettingsManager
|
import com.rtbishop.look4sat.domain.ISettingsSource
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
import com.rtbishop.look4sat.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.model.SatEntry
|
import com.rtbishop.look4sat.model.SatEntry
|
||||||
import com.rtbishop.look4sat.utility.DataParser
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@@ -30,16 +29,16 @@ import java.util.zip.ZipInputStream
|
|||||||
|
|
||||||
class DataRepository(
|
class DataRepository(
|
||||||
private val dataParser: DataParser,
|
private val dataParser: DataParser,
|
||||||
private val fileSource: IFileDataSource,
|
private val fileSource: IFileSource,
|
||||||
private val entrySource: ILocalEntrySource,
|
private val entrySource: IEntriesStorage,
|
||||||
private val radioSource: ILocalRadioSource,
|
private val radioSource: IRadiosStorage,
|
||||||
private val remoteSource: IRemoteDataSource,
|
private val remoteSource: INetworkSource,
|
||||||
private val repositoryScope: CoroutineScope,
|
private val repositoryScope: CoroutineScope,
|
||||||
private val settingsManager: ISettingsManager
|
private val settingsManager: ISettingsSource
|
||||||
) : IDataRepository {
|
) : IDataRepository {
|
||||||
|
|
||||||
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
|
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
|
||||||
_updateState.value = DataState.Error(exception.message)
|
_updateState.value = DataState.Exception(exception.message)
|
||||||
}
|
}
|
||||||
private val updateStateDelay = 875L
|
private val updateStateDelay = 875L
|
||||||
private val _updateState = MutableStateFlow<DataState<Long>>(DataState.Handled)
|
private val _updateState = MutableStateFlow<DataState<Long>>(DataState.Handled)
|
||||||
+5
-5
@@ -15,14 +15,14 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.data
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.model.SatEntry
|
import com.rtbishop.look4sat.domain.Satellite
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.model.SatEntry
|
||||||
import com.rtbishop.look4sat.domain.predict.Satellite
|
import com.rtbishop.look4sat.model.SatItem
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface ILocalEntrySource {
|
interface IEntriesStorage {
|
||||||
|
|
||||||
fun getEntriesTotal(): Flow<Int>
|
fun getEntriesTotal(): Flow<Int>
|
||||||
|
|
||||||
+2
-2
@@ -15,11 +15,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.data
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
interface IFileDataSource {
|
interface IFileSource {
|
||||||
|
|
||||||
suspend fun getDataStream(uri: String): InputStream?
|
suspend fun getDataStream(uri: String): InputStream?
|
||||||
}
|
}
|
||||||
+2
-2
@@ -15,11 +15,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.data
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
interface IRemoteDataSource {
|
interface INetworkSource {
|
||||||
|
|
||||||
val radioApi: String get() = "https://db.satnogs.org/api/transmitters/?format=json&status=active"
|
val radioApi: String get() = "https://db.satnogs.org/api/transmitters/?format=json&status=active"
|
||||||
|
|
||||||
+3
-3
@@ -15,12 +15,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.data
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.model.SatRadio
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface ILocalRadioSource {
|
interface IRadiosStorage {
|
||||||
|
|
||||||
fun getRadiosTotal(): Flow<Int>
|
fun getRadiosTotal(): Flow<Int>
|
||||||
|
|
||||||
+2
-1
@@ -15,8 +15,9 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.predict
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.model.OrbitalData
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
class DeepSpaceSat(data: OrbitalData) : Satellite(data) {
|
class DeepSpaceSat(data: OrbitalData) : Satellite(data) {
|
||||||
@@ -17,10 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
import com.rtbishop.look4sat.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.model.SatItem
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.model.SatRadio
|
||||||
import com.rtbishop.look4sat.domain.predict.Satellite
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
|
||||||
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.domain
|
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.model.DataState
|
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
|
||||||
|
|
||||||
interface ILocationManager {
|
|
||||||
|
|
||||||
val stationPosition: SharedFlow<DataState<GeoPos>>
|
|
||||||
|
|
||||||
fun getStationLocator(): String
|
|
||||||
|
|
||||||
fun getStationPosition(): GeoPos
|
|
||||||
|
|
||||||
fun setStationPosition(latitude: Double, longitude: Double)
|
|
||||||
|
|
||||||
fun setPositionFromGps()
|
|
||||||
|
|
||||||
fun setPositionFromNet()
|
|
||||||
|
|
||||||
fun setPositionFromQth(locator: String)
|
|
||||||
|
|
||||||
fun setPositionHandled()
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||||
|
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.model.StationPos
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
|
interface ILocationSource {
|
||||||
|
|
||||||
|
val stationPosition: StateFlow<StationPos>
|
||||||
|
|
||||||
|
fun setGpsPosition(): Boolean
|
||||||
|
|
||||||
|
fun setGeoPosition(latitude: Double, longitude: Double): Boolean
|
||||||
|
|
||||||
|
fun setQthPosition(locator: String): Boolean
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package com.rtbishop.look4sat.domain
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.model.SatPass
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPass
|
import com.rtbishop.look4sat.model.SatPos
|
||||||
import com.rtbishop.look4sat.domain.predict.SatPos
|
import com.rtbishop.look4sat.model.SatRadio
|
||||||
import com.rtbishop.look4sat.domain.predict.Satellite
|
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
|
||||||
interface ISatelliteManager {
|
interface ISatelliteManager {
|
||||||
|
|||||||
+4
-8
@@ -17,9 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.model.StationPos
|
||||||
|
|
||||||
interface ISettingsManager {
|
interface ISettingsSource {
|
||||||
|
|
||||||
val sourcesMap: Map<String, String>
|
val sourcesMap: Map<String, String>
|
||||||
get() = mapOf(
|
get() = mapOf(
|
||||||
@@ -51,13 +51,9 @@ interface ISettingsManager {
|
|||||||
"Amsat" to "https://amsat.org/tle/current/nasabare.txt"
|
"Amsat" to "https://amsat.org/tle/current/nasabare.txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
fun loadStationLocator(): String
|
fun loadStationPosition(): StationPos
|
||||||
|
|
||||||
fun saveStationLocator(locator: String)
|
fun saveStationPosition(stationPos: StationPos)
|
||||||
|
|
||||||
fun loadStationPosition(): GeoPos
|
|
||||||
|
|
||||||
fun saveStationPosition(position: GeoPos)
|
|
||||||
|
|
||||||
fun getHoursAhead(): Int
|
fun getHoursAhead(): Int
|
||||||
|
|
||||||
+2
-1
@@ -15,8 +15,9 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.predict
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.model.OrbitalData
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
class NearEarthSat(data: OrbitalData) : Satellite(data) {
|
class NearEarthSat(data: OrbitalData) : Satellite(data) {
|
||||||
+4
-1
@@ -15,8 +15,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.predict
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
|
import com.rtbishop.look4sat.model.OrbitalData
|
||||||
|
import com.rtbishop.look4sat.model.SatPos
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
const val ASTRONOMICAL_UNIT = 1.49597870691E8
|
const val ASTRONOMICAL_UNIT = 1.49597870691E8
|
||||||
+5
-3
@@ -15,10 +15,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.predict
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.ISatelliteManager
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.model.SatPass
|
||||||
|
import com.rtbishop.look4sat.model.SatPos
|
||||||
|
import com.rtbishop.look4sat.model.SatRadio
|
||||||
import com.rtbishop.look4sat.utility.round
|
import com.rtbishop.look4sat.utility.round
|
||||||
import com.rtbishop.look4sat.utility.toDegrees
|
import com.rtbishop.look4sat.utility.toDegrees
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
+3
-2
@@ -15,11 +15,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.model
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
sealed class DataState<out T> {
|
sealed class DataState<out T> {
|
||||||
data class Success<out T>(val data: T) : DataState<T>()
|
data class Success<out T>(val data: T) : DataState<T>()
|
||||||
data class Error(val message: String?) : DataState<Nothing>()
|
data class Error(val resId: Int?) : DataState<Nothing>()
|
||||||
|
data class Exception(val message: String?) : DataState<Nothing>()
|
||||||
object Handled : DataState<Nothing>()
|
object Handled : DataState<Nothing>()
|
||||||
object Loading : DataState<Nothing>()
|
object Loading : DataState<Nothing>()
|
||||||
}
|
}
|
||||||
+1
-1
@@ -15,6 +15,6 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.predict
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
data class GeoPos(val lat: Double, val lon: Double, val alt: Double = 0.0, val name: String? = null)
|
data class GeoPos(val lat: Double, val lon: Double, val alt: Double = 0.0, val name: String? = null)
|
||||||
+3
-1
@@ -15,7 +15,9 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.predict
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.domain.*
|
||||||
|
|
||||||
data class OrbitalData(
|
data class OrbitalData(
|
||||||
val name: String,
|
val name: String,
|
||||||
+1
-3
@@ -15,8 +15,6 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.model
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict.OrbitalData
|
|
||||||
|
|
||||||
data class SatEntry(val data: OrbitalData, var comment: String? = null)
|
data class SatEntry(val data: OrbitalData, var comment: String? = null)
|
||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.model
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
data class SatItem(
|
data class SatItem(
|
||||||
val catnum: Int,
|
val catnum: Int,
|
||||||
+3
-1
@@ -15,7 +15,9 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.predict
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.domain.Satellite
|
||||||
|
|
||||||
data class SatPass(
|
data class SatPass(
|
||||||
val aosTime: Long = 0L,
|
val aosTime: Long = 0L,
|
||||||
+5
-1
@@ -15,8 +15,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.predict
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.domain.DEG2RAD
|
||||||
|
import com.rtbishop.look4sat.domain.EARTH_RADIUS
|
||||||
|
import com.rtbishop.look4sat.domain.RAD2DEG
|
||||||
|
import com.rtbishop.look4sat.domain.SPEED_OF_LIGHT
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
data class SatPos(
|
data class SatPos(
|
||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.model
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
data class SatRadio(
|
data class SatRadio(
|
||||||
val uuid: String,
|
val uuid: String,
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.rtbishop.look4sat.model
|
||||||
|
|
||||||
|
data class StationPos(
|
||||||
|
val latitude: Double, val longitude: Double, val qthLocator: String, val timestamp: Long
|
||||||
|
) {
|
||||||
|
fun toGeoPos(): GeoPos = GeoPos(latitude, longitude)
|
||||||
|
}
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.utility
|
package com.rtbishop.look4sat.utility
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict.DEG2RAD
|
import com.rtbishop.look4sat.domain.DEG2RAD
|
||||||
import com.rtbishop.look4sat.domain.predict.RAD2DEG
|
import com.rtbishop.look4sat.domain.RAD2DEG
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
fun Long.toTimerString(): String {
|
fun Long.toTimerString(): String {
|
||||||
@@ -64,7 +64,7 @@ fun Double.toRadians(): Double = this * DEG2RAD
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
fun String.isValidIPv4(): Boolean {
|
fun String.isValidIPv4(): Boolean {
|
||||||
val ip4 = "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!\$)|\$)){4}\$"
|
val ip4 = "^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])(\\.(?!\$)|\$)){4}\$"
|
||||||
return this.matches(ip4.toRegex())
|
return this.matches(ip4.toRegex())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.utility
|
package com.rtbishop.look4sat.utility
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.model.GeoPos
|
||||||
|
|
||||||
object QthConverter {
|
object QthConverter {
|
||||||
|
|
||||||
@@ -35,27 +35,27 @@ object QthConverter {
|
|||||||
return GeoPos(latitude, longitude)
|
return GeoPos(latitude, longitude)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun positionToQth(lat: Double, lon: Double): String? {
|
fun positionToQth(latitude: Double, longitude: Double): String? {
|
||||||
if (!isValidPosition(lat, lon)) return null
|
if (!isValidPosition(latitude, longitude)) return null
|
||||||
val tempLon = if (lon > 180.0) lon - 180 else lon
|
val tempLon = if (longitude > 180.0) longitude - 180 else longitude
|
||||||
val upper = "ABCDEFGHIJKLMNOPQRSTUVWX"
|
val upper = "ABCDEFGHIJKLMNOPQRSTUVWX"
|
||||||
val lower = "abcdefghijklmnopqrstuvwx"
|
val lower = "abcdefghijklmnopqrstuvwx"
|
||||||
val longitude = tempLon + 180
|
val newLongitude = tempLon + 180
|
||||||
val latitude = lat + 90
|
val newLatitude = latitude + 90
|
||||||
val lonFirst = upper[(longitude / 20).toInt()]
|
val lonFirst = upper[(newLongitude / 20).toInt()]
|
||||||
val latFirst = upper[(latitude / 10).toInt()]
|
val latFirst = upper[(newLatitude / 10).toInt()]
|
||||||
val lonSecond = ((longitude / 2) % 10).toInt().toString()
|
val lonSecond = ((newLongitude / 2) % 10).toInt().toString()
|
||||||
val latSecond = (latitude % 10).toInt().toString()
|
val latSecond = (newLatitude % 10).toInt().toString()
|
||||||
val lonThird = lower[((longitude % 2) * 12).toInt()]
|
val lonThird = lower[((newLongitude % 2) * 12).toInt()]
|
||||||
val latThird = lower[((latitude % 1) * 24).toInt()]
|
val latThird = lower[((newLatitude % 1) * 24).toInt()]
|
||||||
return "$lonFirst$latFirst$lonSecond$latSecond$lonThird$latThird"
|
return "$lonFirst$latFirst$lonSecond$latSecond$lonThird$latThird"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isValidPosition(lat: Double, lon: Double): Boolean {
|
private fun isValidPosition(lat: Double, lon: Double): Boolean {
|
||||||
return (lat >= -90.0 && lat <= 90.0) && (lon >= -180.0 && lon <= 360.0)
|
return (lat >= -90.0 && lat <= 90.0) && (lon >= -180.0 && lon <= 360.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isValidLocator(locator: String): Boolean {
|
private fun isValidLocator(locator: String): Boolean {
|
||||||
return locator.matches("[a-xA-X][a-xA-X][0-9][0-9][a-xA-X][a-xA-X]".toRegex())
|
return locator.matches("[a-xA-X][a-xA-X]\\d\\d[a-xA-X][a-xA-X]".toRegex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat
|
package com.rtbishop.look4sat
|
||||||
|
|
||||||
import com.rtbishop.look4sat.utility.DataParser
|
import com.rtbishop.look4sat.data.DataParser
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|||||||
Reference in new issue
Block a user