kopia lustrzana https://github.com/rt-bishop/Look4Sat
Moved and renamed various classes to simplify structure
rodzic
c91c58ac69
commit
fdb5752408
|
@ -21,7 +21,7 @@ import android.content.SharedPreferences
|
||||||
import android.hardware.GeomagneticField
|
import android.hardware.GeomagneticField
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import com.rtbishop.look4sat.data.PreferenceSource
|
import com.rtbishop.look4sat.data.PreferencesSource
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||||
import com.rtbishop.look4sat.utility.round
|
import com.rtbishop.look4sat.utility.round
|
||||||
|
@ -31,7 +31,7 @@ class PreferencesProvider @Inject constructor(
|
||||||
private val qthConverter: QthConverter,
|
private val qthConverter: QthConverter,
|
||||||
private val locationManager: LocationManager,
|
private val locationManager: LocationManager,
|
||||||
private val preferences: SharedPreferences
|
private val preferences: SharedPreferences
|
||||||
) : PreferenceSource {
|
) : PreferencesSource {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val keyModes = "satModes"
|
const val keyModes = "satModes"
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package com.rtbishop.look4sat.framework.api
|
|
||||||
|
|
||||||
import com.rtbishop.look4sat.data.RemoteDataSource
|
|
||||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class NetworkDataSource(private val api: SatelliteService) : RemoteDataSource {
|
|
||||||
|
|
||||||
override suspend fun fetchDataStream(url: String): InputStream? {
|
|
||||||
return api.fetchFileByUrl(url).body()?.byteStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun fetchTransmitters(): List<SatTrans> {
|
|
||||||
return api.fetchTransmitters().map { trans ->
|
|
||||||
SatTrans(
|
|
||||||
trans.uuid, trans.info, trans.isAlive, trans.downlink,
|
|
||||||
trans.uplink, trans.mode, trans.isInverted, trans.catNum
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.rtbishop.look4sat.framework.api
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.data.SatDataRemoteSource
|
||||||
|
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||||
|
import com.rtbishop.look4sat.utility.DataMapper
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
class SatDataRemote(private val api: SatDataService) : SatDataRemoteSource {
|
||||||
|
|
||||||
|
override suspend fun fetchDataStream(url: String): InputStream? {
|
||||||
|
return api.fetchFileByUrl(url).body()?.byteStream()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun fetchTransmitters(): List<SatTrans> {
|
||||||
|
return DataMapper.satTransListToDomainTransList(api.fetchTransmitters())
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ import retrofit2.http.GET
|
||||||
import retrofit2.http.Streaming
|
import retrofit2.http.Streaming
|
||||||
import retrofit2.http.Url
|
import retrofit2.http.Url
|
||||||
|
|
||||||
interface SatelliteService {
|
interface SatDataService {
|
||||||
|
|
||||||
@Streaming
|
@Streaming
|
||||||
@GET
|
@GET
|
|
@ -25,7 +25,7 @@ import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface SatelliteDao {
|
interface SatDataDao {
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT catNum, name, isSelected FROM entries ORDER BY name ASC")
|
@Query("SELECT catNum, name, isSelected FROM entries ORDER BY name ASC")
|
|
@ -25,7 +25,7 @@ import com.rtbishop.look4sat.framework.model.SatTrans
|
||||||
|
|
||||||
@Database(entities = [SatEntry::class, SatTrans::class], version = 1, exportSchema = false)
|
@Database(entities = [SatEntry::class, SatTrans::class], version = 1, exportSchema = false)
|
||||||
@TypeConverters(RoomConverters::class)
|
@TypeConverters(RoomConverters::class)
|
||||||
abstract class SatelliteDb : RoomDatabase() {
|
abstract class SatDataDb : RoomDatabase() {
|
||||||
|
|
||||||
abstract fun satelliteDao(): SatelliteDao
|
abstract fun satelliteDao(): SatDataDao
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package com.rtbishop.look4sat.framework.db
|
package com.rtbishop.look4sat.framework.db
|
||||||
|
|
||||||
import com.rtbishop.look4sat.data.LocalDataSource
|
import com.rtbishop.look4sat.data.SatDataLocalSource
|
||||||
import com.rtbishop.look4sat.domain.model.SatEntry
|
import com.rtbishop.look4sat.domain.model.SatEntry
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.domain.model.SatItem
|
||||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||||
|
@ -9,33 +9,33 @@ import com.rtbishop.look4sat.utility.DataMapper
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
class RoomDataSource(private val satelliteDao: SatelliteDao) : LocalDataSource {
|
class SatDataLocal(private val satDataDao: SatDataDao) : SatDataLocalSource {
|
||||||
|
|
||||||
override fun getSatItems(): Flow<List<SatItem>> {
|
override fun getSatItems(): Flow<List<SatItem>> {
|
||||||
return satelliteDao.getSatItems()
|
return satDataDao.getSatItems()
|
||||||
.map { satItems -> DataMapper.satItemsToDomainItems(satItems) }
|
.map { satItems -> DataMapper.satItemsToDomainItems(satItems) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getSelectedSatellites(): List<Satellite> {
|
override suspend fun getSelectedSatellites(): List<Satellite> {
|
||||||
return satelliteDao.getSelectedSatellites()
|
return satDataDao.getSelectedSatellites()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateEntries(entries: List<SatEntry>) {
|
override suspend fun updateEntries(entries: List<SatEntry>) {
|
||||||
val satEntries = entries.map { entry -> DataMapper.domainEntryToSatEntry(entry) }
|
val satEntries = entries.map { entry -> DataMapper.domainEntryToSatEntry(entry) }
|
||||||
satelliteDao.updateEntries(satEntries)
|
satDataDao.updateEntries(satEntries)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
|
override suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
|
||||||
satelliteDao.updateEntriesSelection(catNums, isSelected)
|
satDataDao.updateEntriesSelection(catNums, isSelected)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
|
override fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
|
||||||
return satelliteDao.getSatTransmitters(catNum)
|
return satDataDao.getSatTransmitters(catNum)
|
||||||
.map { satTransList -> DataMapper.satTransListToDomainTransList(satTransList) }
|
.map { satTransList -> DataMapper.satTransListToDomainTransList(satTransList) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateTransmitters(satelliteTrans: List<SatTrans>) {
|
override suspend fun updateTransmitters(satelliteTrans: List<SatTrans>) {
|
||||||
val satTransList = DataMapper.domainTransListToSatTransList(satelliteTrans)
|
val satTransList = DataMapper.domainTransListToSatTransList(satelliteTrans)
|
||||||
satelliteDao.updateTransmitters(satTransList)
|
satDataDao.updateTransmitters(satTransList)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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.di
|
package com.rtbishop.look4sat.injection
|
||||||
|
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -23,7 +23,6 @@ import android.content.SharedPreferences
|
||||||
import android.hardware.SensorManager
|
import android.hardware.SensorManager
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
|
@ -34,11 +33,6 @@ import dagger.hilt.components.SingletonComponent
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
object ApplicationModule {
|
object ApplicationModule {
|
||||||
|
|
||||||
@Provides
|
|
||||||
fun provideQthConverter(): QthConverter {
|
|
||||||
return QthConverter()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideContentResolver(@ApplicationContext context: Context): ContentResolver {
|
fun provideContentResolver(@ApplicationContext context: Context): ContentResolver {
|
||||||
return context.contentResolver
|
return context.contentResolver
|
|
@ -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.di
|
package com.rtbishop.look4sat.injection
|
||||||
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
|
@ -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.di
|
package com.rtbishop.look4sat.injection
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
@ -24,12 +24,12 @@ import androidx.room.Room
|
||||||
import com.rtbishop.look4sat.data.*
|
import com.rtbishop.look4sat.data.*
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
||||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||||
import com.rtbishop.look4sat.framework.api.NetworkDataSource
|
import com.rtbishop.look4sat.framework.api.SatDataRemote
|
||||||
import com.rtbishop.look4sat.framework.api.SatelliteService
|
import com.rtbishop.look4sat.framework.api.SatDataService
|
||||||
import com.rtbishop.look4sat.framework.db.RoomConverters
|
import com.rtbishop.look4sat.framework.db.RoomConverters
|
||||||
import com.rtbishop.look4sat.framework.db.RoomDataSource
|
import com.rtbishop.look4sat.framework.db.SatDataLocal
|
||||||
import com.rtbishop.look4sat.framework.db.SatelliteDao
|
import com.rtbishop.look4sat.framework.db.SatDataDao
|
||||||
import com.rtbishop.look4sat.framework.db.SatelliteDb
|
import com.rtbishop.look4sat.framework.db.SatDataDb
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
@ -43,7 +43,12 @@ import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
object DataSourceModule {
|
object SatDataModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun provideQthConverter(): QthConverter {
|
||||||
|
return QthConverter()
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideMoshi(): Moshi {
|
fun provideMoshi(): Moshi {
|
||||||
|
@ -56,56 +61,57 @@ object DataSourceModule {
|
||||||
qthConverter: QthConverter,
|
qthConverter: QthConverter,
|
||||||
locationManager: LocationManager,
|
locationManager: LocationManager,
|
||||||
preferences: SharedPreferences
|
preferences: SharedPreferences
|
||||||
): PreferenceSource {
|
): PreferencesSource {
|
||||||
return PreferencesProvider(qthConverter, locationManager, preferences)
|
return PreferencesProvider(qthConverter, locationManager, preferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providePassesRepo(
|
fun providePassesRepo(
|
||||||
preferenceSource: PreferenceSource,
|
preferencesSource: PreferencesSource,
|
||||||
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
|
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
|
||||||
): PassesRepo {
|
): SatPassRepository {
|
||||||
return PassesRepo(preferenceSource, defaultDispatcher)
|
return SatPassRepository(preferencesSource, defaultDispatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideSatelliteRepo(
|
fun provideSatelliteRepo(
|
||||||
localSource: LocalDataSource,
|
preferencesSource: PreferencesSource,
|
||||||
remoteSource: RemoteDataSource,
|
satLocalSource: SatDataLocalSource,
|
||||||
|
satRemoteSource: SatDataRemoteSource,
|
||||||
@IoDispatcher ioDispatcher: CoroutineDispatcher
|
@IoDispatcher ioDispatcher: CoroutineDispatcher
|
||||||
): SatelliteRepo {
|
): SatDataRepository {
|
||||||
return SatelliteRepo(localSource, remoteSource, ioDispatcher)
|
return SatDataRepository(preferencesSource, satLocalSource, satRemoteSource, ioDispatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideLocalDataSource(satelliteDao: SatelliteDao): LocalDataSource {
|
fun provideLocalDataSource(satDataDao: SatDataDao): SatDataLocalSource {
|
||||||
return RoomDataSource(satelliteDao)
|
return SatDataLocal(satDataDao)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSatDataDao(db: SatelliteDb): SatelliteDao {
|
fun provideSatDataDao(db: SatDataDb): SatDataDao {
|
||||||
return db.satelliteDao()
|
return db.satelliteDao()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSatelliteDb(@ApplicationContext context: Context, moshi: Moshi): SatelliteDb {
|
fun provideSatelliteDb(@ApplicationContext context: Context, moshi: Moshi): SatDataDb {
|
||||||
RoomConverters.initialize(moshi)
|
RoomConverters.initialize(moshi)
|
||||||
return Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb").build()
|
return Room.databaseBuilder(context, SatDataDb::class.java, "SatelliteDb").build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideRemoteDataSource(satelliteService: SatelliteService): RemoteDataSource {
|
fun provideRemoteDataSource(satDataService: SatDataService): SatDataRemoteSource {
|
||||||
return NetworkDataSource(satelliteService)
|
return SatDataRemote(satDataService)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSatDataService(): SatelliteService {
|
fun provideSatDataService(): SatDataService {
|
||||||
return Retrofit.Builder()
|
return Retrofit.Builder()
|
||||||
.baseUrl("https://db.satnogs.org/api/")
|
.baseUrl("https://db.satnogs.org/api/")
|
||||||
.addConverterFactory(MoshiConverterFactory.create())
|
.addConverterFactory(MoshiConverterFactory.create())
|
||||||
.build()
|
.build()
|
||||||
.create(SatelliteService::class.java)
|
.create(SatDataService::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,8 +24,8 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.data.PreferencesSource
|
||||||
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
||||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
|
||||||
import com.rtbishop.look4sat.utility.navigateSafe
|
import com.rtbishop.look4sat.utility.navigateSafe
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -34,7 +34,7 @@ import javax.inject.Inject
|
||||||
class Look4SatActivity : AppCompatActivity() {
|
class Look4SatActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var preferenceSource: PreferencesProvider
|
lateinit var preferenceSource: PreferencesSource
|
||||||
|
|
||||||
@SuppressLint("SourceLockedOrientationActivity")
|
@SuppressLint("SourceLockedOrientationActivity")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
|
@ -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.infoScreen
|
package com.rtbishop.look4sat.presentation.appInfoScreen
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -27,7 +27,7 @@ import com.rtbishop.look4sat.BuildConfig
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.databinding.FragmentInfoBinding
|
import com.rtbishop.look4sat.databinding.FragmentInfoBinding
|
||||||
|
|
||||||
class InfoFragment : Fragment(R.layout.fragment_info) {
|
class AppInfoFragment : Fragment(R.layout.fragment_info) {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
|
@ -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.prefsScreen
|
package com.rtbishop.look4sat.presentation.appSettingsScreen
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
@ -30,16 +30,16 @@ import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.data.PreferenceSource
|
import com.rtbishop.look4sat.data.PreferencesSource
|
||||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PrefsFragment : PreferenceFragmentCompat() {
|
class AppSettingsFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var preferenceSource: PreferenceSource
|
lateinit var preferencesSource: PreferencesSource
|
||||||
|
|
||||||
private val requestPermissionLauncher =
|
private val requestPermissionLauncher =
|
||||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||||
|
@ -96,7 +96,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePositionFromQth(qthString: String): Boolean {
|
private fun updatePositionFromQth(qthString: String): Boolean {
|
||||||
return if (preferenceSource.updatePositionFromQTH(qthString)) {
|
return if (preferencesSource.updatePositionFromQTH(qthString)) {
|
||||||
showSnack(getString(R.string.pref_pos_success))
|
showSnack(getString(R.string.pref_pos_success))
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,7 +109,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
||||||
val locPermString = Manifest.permission.ACCESS_FINE_LOCATION
|
val locPermString = Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
val locPermResult = ContextCompat.checkSelfPermission(requireContext(), locPermString)
|
val locPermResult = ContextCompat.checkSelfPermission(requireContext(), locPermString)
|
||||||
if (locPermResult == PackageManager.PERMISSION_GRANTED) {
|
if (locPermResult == PackageManager.PERMISSION_GRANTED) {
|
||||||
if (preferenceSource.updatePositionFromGPS()) {
|
if (preferencesSource.updatePositionFromGPS()) {
|
||||||
showSnack(getString(R.string.pref_pos_success))
|
showSnack(getString(R.string.pref_pos_success))
|
||||||
} else showSnack(getString(R.string.pref_pos_gps_null))
|
} else showSnack(getString(R.string.pref_pos_gps_null))
|
||||||
} else requestPermissionLauncher.launch(locPermString)
|
} else requestPermissionLauncher.launch(locPermString)
|
|
@ -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.splashDialog
|
package com.rtbishop.look4sat.presentation.appSplashDialog
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -26,7 +26,7 @@ import androidx.appcompat.app.AppCompatDialogFragment
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.databinding.DialogSplashBinding
|
import com.rtbishop.look4sat.databinding.DialogSplashBinding
|
||||||
|
|
||||||
class SplashDialog : AppCompatDialogFragment() {
|
class AppSplashDialog : AppCompatDialogFragment() {
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.dialog_splash, group, false)
|
return inflater.inflate(R.layout.dialog_splash, group, false)
|
|
@ -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.entriesScreen
|
package com.rtbishop.look4sat.presentation.satItemScreen
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -25,7 +25,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.rtbishop.look4sat.databinding.SatItemBinding
|
import com.rtbishop.look4sat.databinding.SatItemBinding
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.domain.model.SatItem
|
||||||
|
|
||||||
class EntriesAdapter : RecyclerView.Adapter<EntriesAdapter.SatItemHolder>() {
|
class SatItemAdapter : RecyclerView.Adapter<SatItemAdapter.SatItemHolder>() {
|
||||||
|
|
||||||
private val diffCallback = object : DiffUtil.ItemCallback<SatItem>() {
|
private val diffCallback = object : DiffUtil.ItemCallback<SatItem>() {
|
||||||
override fun areItemsTheSame(oldItem: SatItem, newItem: SatItem): Boolean {
|
override fun areItemsTheSame(oldItem: SatItem, newItem: SatItem): Boolean {
|
|
@ -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.entriesScreen
|
package com.rtbishop.look4sat.presentation.satItemScreen
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -33,9 +33,9 @@ import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
class SatItemFragment : Fragment(R.layout.fragment_entries) {
|
||||||
|
|
||||||
private val viewModel: EntriesViewModel by viewModels()
|
private val viewModel: SatItemViewModel by viewModels()
|
||||||
private val contentContract = ActivityResultContracts.GetContent()
|
private val contentContract = ActivityResultContracts.GetContent()
|
||||||
private val filePicker = registerForActivityResult(contentContract) { uri ->
|
private val filePicker = registerForActivityResult(contentContract) { uri ->
|
||||||
uri?.let { viewModel.updateEntriesFromFile(uri) }
|
uri?.let { viewModel.updateEntriesFromFile(uri) }
|
||||||
|
@ -47,7 +47,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupComponents(view: View) {
|
private fun setupComponents(view: View) {
|
||||||
val entriesAdapter = EntriesAdapter().apply {
|
val entriesAdapter = SatItemAdapter().apply {
|
||||||
setEntriesClickListener(viewModel)
|
setEntriesClickListener(viewModel)
|
||||||
}
|
}
|
||||||
val binding = FragmentEntriesBinding.bind(view).apply {
|
val binding = FragmentEntriesBinding.bind(view).apply {
|
||||||
|
@ -72,11 +72,11 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||||
private fun handleSatData(
|
private fun handleSatData(
|
||||||
result: Result<List<SatItem>>,
|
result: Result<List<SatItem>>,
|
||||||
binding: FragmentEntriesBinding,
|
binding: FragmentEntriesBinding,
|
||||||
entriesAdapter: EntriesAdapter
|
satItemAdapter: SatItemAdapter
|
||||||
) {
|
) {
|
||||||
when (result) {
|
when (result) {
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
entriesAdapter.submitList(result.data)
|
satItemAdapter.submitList(result.data)
|
||||||
binding.entriesProgress.visibility = View.INVISIBLE
|
binding.entriesProgress.visibility = View.INVISIBLE
|
||||||
binding.entriesRecycler.visibility = View.VISIBLE
|
binding.entriesRecycler.visibility = View.VISIBLE
|
||||||
binding.entriesRecycler.scrollToPosition(0)
|
binding.entriesRecycler.scrollToPosition(0)
|
|
@ -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.entriesScreen
|
package com.rtbishop.look4sat.presentation.satItemScreen
|
||||||
|
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -25,9 +25,8 @@ import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
import com.rtbishop.look4sat.data.SatDataRepository
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.domain.model.SatItem
|
||||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
import com.rtbishop.look4sat.framework.model.Result
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
|
@ -36,16 +35,15 @@ import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class EntriesViewModel @Inject constructor(
|
class SatItemViewModel @Inject constructor(
|
||||||
private val preferenceSource: PreferencesProvider,
|
|
||||||
private val resolver: ContentResolver,
|
private val resolver: ContentResolver,
|
||||||
private val satelliteRepo: SatelliteRepo,
|
private val satDataRepository: SatDataRepository,
|
||||||
) : ViewModel(), EntriesAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
|
) : ViewModel(), SatItemAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
|
||||||
|
|
||||||
private val transModes = MutableLiveData(preferenceSource.loadModesSelection())
|
private val transModes = MutableLiveData(satDataRepository.loadModesSelection())
|
||||||
private val currentQuery = MutableLiveData(String())
|
private val currentQuery = MutableLiveData(String())
|
||||||
private val itemsWithModes = transModes.switchMap { modes ->
|
private val itemsWithModes = transModes.switchMap { modes ->
|
||||||
liveData { satelliteRepo.getSatItems().collect { emit(filterByModes(it, modes)) } }
|
liveData { satDataRepository.getSatItems().collect { emit(filterByModes(it, modes)) } }
|
||||||
}
|
}
|
||||||
private val itemsWithQuery = currentQuery.switchMap { query ->
|
private val itemsWithQuery = currentQuery.switchMap { query ->
|
||||||
itemsWithModes.map { items -> Result.Success(filterByQuery(items, query)) }
|
itemsWithModes.map { items -> Result.Success(filterByQuery(items, query)) }
|
||||||
|
@ -61,7 +59,7 @@ class EntriesViewModel @Inject constructor(
|
||||||
_satData.value = Result.InProgress
|
_satData.value = Result.InProgress
|
||||||
runCatching {
|
runCatching {
|
||||||
resolver.openInputStream(uri)?.use { stream ->
|
resolver.openInputStream(uri)?.use { stream ->
|
||||||
satelliteRepo.updateEntriesFromFile(stream)
|
satDataRepository.updateEntriesFromFile(stream)
|
||||||
}
|
}
|
||||||
}.onFailure { _satData.value = Result.Error(it) }
|
}.onFailure { _satData.value = Result.Error(it) }
|
||||||
}
|
}
|
||||||
|
@ -71,8 +69,8 @@ class EntriesViewModel @Inject constructor(
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_satData.value = Result.InProgress
|
_satData.value = Result.InProgress
|
||||||
runCatching {
|
runCatching {
|
||||||
if (sources == null) satelliteRepo.updateEntriesFromWeb()
|
if (sources == null) satDataRepository.updateEntriesFromWeb()
|
||||||
else satelliteRepo.updateEntriesFromWeb(sources)
|
else satDataRepository.updateEntriesFromWeb(sources)
|
||||||
}.onFailure { _satData.value = Result.Error(it) }
|
}.onFailure { _satData.value = Result.Error(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,15 +84,9 @@ class EntriesViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createModesDialog(context: Context): AlertDialog {
|
fun createModesDialog(context: Context): AlertDialog {
|
||||||
val modes = arrayOf(
|
val modes = satDataRepository.getAllModes()
|
||||||
"AFSK", "AFSK S-Net", "AFSK SALSAT", "AHRPT", "AM", "APT", "BPSK", "BPSK PMT-A3",
|
|
||||||
"CERTO", "CW", "DQPSK", "DSTAR", "DUV", "FFSK", "FM", "FMN", "FSK", "FSK AX.100 Mode 5",
|
|
||||||
"FSK AX.100 Mode 6", "FSK AX.25 G3RUH", "GFSK", "GFSK Rktr", "GMSK", "HRPT", "LoRa",
|
|
||||||
"LRPT", "LSB", "MFSK", "MSK", "MSK AX.100 Mode 5", "MSK AX.100 Mode 6", "OFDM", "OQPSK",
|
|
||||||
"PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT"
|
|
||||||
)
|
|
||||||
val savedModes = BooleanArray(modes.size)
|
val savedModes = BooleanArray(modes.size)
|
||||||
val selectedModes = preferenceSource.loadModesSelection().toMutableList()
|
val selectedModes = satDataRepository.loadModesSelection().toMutableList()
|
||||||
selectedModes.forEach { savedModes[modes.indexOf(it)] = true }
|
selectedModes.forEach { savedModes[modes.indexOf(it)] = true }
|
||||||
val dialogBuilder = MaterialAlertDialogBuilder(context).apply {
|
val dialogBuilder = MaterialAlertDialogBuilder(context).apply {
|
||||||
setTitle(context.getString(R.string.modes_title))
|
setTitle(context.getString(R.string.modes_title))
|
||||||
|
@ -106,7 +98,7 @@ class EntriesViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
setPositiveButton(context.getString(android.R.string.ok)) { _, _ ->
|
setPositiveButton(context.getString(android.R.string.ok)) { _, _ ->
|
||||||
transModes.value = selectedModes
|
transModes.value = selectedModes
|
||||||
preferenceSource.saveModesSelection(selectedModes)
|
satDataRepository.saveModesSelection(selectedModes)
|
||||||
}
|
}
|
||||||
setNeutralButton(context.getString(android.R.string.cancel)) { dialog, _ ->
|
setNeutralButton(context.getString(android.R.string.cancel)) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
@ -125,7 +117,7 @@ class EntriesViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateSelection(catNums: List<Int>, isSelected: Boolean) {
|
override fun updateSelection(catNums: List<Int>, isSelected: Boolean) {
|
||||||
viewModelScope.launch { satelliteRepo.updateEntriesSelection(catNums, isSelected) }
|
viewModelScope.launch { satDataRepository.updateEntriesSelection(catNums, isSelected) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterByModes(items: List<SatItem>, modes: List<String>): List<SatItem> {
|
private fun filterByModes(items: List<SatItem>, modes: List<String>): List<SatItem> {
|
|
@ -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.mapScreen
|
package com.rtbishop.look4sat.presentation.satMapScreen
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
@ -44,12 +44,12 @@ import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MapFragment : Fragment(R.layout.fragment_map) {
|
class SatMapFragment : Fragment(R.layout.fragment_map) {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var sharedPreferences: SharedPreferences
|
lateinit var sharedPreferences: SharedPreferences
|
||||||
|
|
||||||
private val viewModel: MapViewModel by viewModels()
|
private val viewModelSat: SatMapViewModel by viewModels()
|
||||||
private val minLat = MapView.getTileSystem().minLatitude
|
private val minLat = MapView.getTileSystem().minLatitude
|
||||||
private val maxLat = MapView.getTileSystem().maxLatitude
|
private val maxLat = MapView.getTileSystem().maxLatitude
|
||||||
private val trackPaint = Paint().apply {
|
private val trackPaint = Paint().apply {
|
||||||
|
@ -86,17 +86,17 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||||
overlays.addAll(Array(4) { FolderOverlay() })
|
overlays.addAll(Array(4) { FolderOverlay() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.fabPrev.setOnClickListener { viewModel.scrollSelection(true) }
|
binding.fabPrev.setOnClickListener { viewModelSat.scrollSelection(true) }
|
||||||
binding.fabNext.setOnClickListener { viewModel.scrollSelection(false) }
|
binding.fabNext.setOnClickListener { viewModelSat.scrollSelection(false) }
|
||||||
setupObservers(binding)
|
setupObservers(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupObservers(binding: FragmentMapBinding) {
|
private fun setupObservers(binding: FragmentMapBinding) {
|
||||||
viewModel.stationPos.observe(viewLifecycleOwner, { renderStationPos(it, binding) })
|
viewModelSat.stationPos.observe(viewLifecycleOwner, { renderStationPos(it, binding) })
|
||||||
viewModel.allSatPositions.observe(viewLifecycleOwner, { renderSatPositions(it, binding) })
|
viewModelSat.allSatPositions.observe(viewLifecycleOwner, { renderSatPositions(it, binding) })
|
||||||
viewModel.satTrack.observe(viewLifecycleOwner, { renderSatTrack(it, binding) })
|
viewModelSat.satTrack.observe(viewLifecycleOwner, { renderSatTrack(it, binding) })
|
||||||
viewModel.satFootprint.observe(viewLifecycleOwner, { renderSatFootprint(it, binding) })
|
viewModelSat.satFootprint.observe(viewLifecycleOwner, { renderSatFootprint(it, binding) })
|
||||||
viewModel.satData.observe(viewLifecycleOwner, { renderSatData(it, binding) })
|
viewModelSat.satData.observe(viewLifecycleOwner, { renderSatData(it, binding) })
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderStationPos(stationPos: Position, binding: FragmentMapBinding) {
|
private fun renderStationPos(stationPos: Position, binding: FragmentMapBinding) {
|
||||||
|
@ -116,7 +116,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
val markers = FolderOverlay()
|
val markers = FolderOverlay()
|
||||||
posMap.entries.forEach {
|
posMap.entries.forEach {
|
||||||
if (viewModel.shouldUseTextLabels()) {
|
if (viewModelSat.shouldUseTextLabels()) {
|
||||||
Marker(mapView).apply {
|
Marker(mapView).apply {
|
||||||
setInfoWindow(null)
|
setInfoWindow(null)
|
||||||
textLabelFontSize = 24
|
textLabelFontSize = 24
|
||||||
|
@ -131,7 +131,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||||
Timber.d(exception)
|
Timber.d(exception)
|
||||||
}
|
}
|
||||||
setOnMarkerClickListener { _, _ ->
|
setOnMarkerClickListener { _, _ ->
|
||||||
viewModel.selectSatellite(it.key)
|
viewModelSat.selectSatellite(it.key)
|
||||||
return@setOnMarkerClickListener true
|
return@setOnMarkerClickListener true
|
||||||
}
|
}
|
||||||
markers.add(this)
|
markers.add(this)
|
||||||
|
@ -147,7 +147,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||||
Timber.d(exception)
|
Timber.d(exception)
|
||||||
}
|
}
|
||||||
setOnMarkerClickListener { _, _ ->
|
setOnMarkerClickListener { _, _ ->
|
||||||
viewModel.selectSatellite(it.key)
|
viewModelSat.selectSatellite(it.key)
|
||||||
return@setOnMarkerClickListener true
|
return@setOnMarkerClickListener true
|
||||||
}
|
}
|
||||||
markers.add(this)
|
markers.add(this)
|
|
@ -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.presentation.mapScreen
|
package com.rtbishop.look4sat.presentation.satMapScreen
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import com.rtbishop.look4sat.data.PreferenceSource
|
import com.rtbishop.look4sat.data.PreferencesSource
|
||||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
import com.rtbishop.look4sat.data.SatDataRepository
|
||||||
import com.rtbishop.look4sat.di.DefaultDispatcher
|
import com.rtbishop.look4sat.injection.DefaultDispatcher
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.Position
|
import com.rtbishop.look4sat.domain.predict4kotlin.Position
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||||
|
@ -35,13 +35,13 @@ import kotlin.math.pow
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class MapViewModel @Inject constructor(
|
class SatMapViewModel @Inject constructor(
|
||||||
private val satelliteRepo: SatelliteRepo,
|
private val satDataRepository: SatDataRepository,
|
||||||
private val preferenceSource: PreferenceSource,
|
private val preferencesSource: PreferencesSource,
|
||||||
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val gsp = preferenceSource.loadStationPosition()
|
private val gsp = preferencesSource.loadStationPosition()
|
||||||
private var dataUpdateJob: Job? = null
|
private var dataUpdateJob: Job? = null
|
||||||
private var allSatList = listOf<Satellite>()
|
private var allSatList = listOf<Satellite>()
|
||||||
private lateinit var selectedSat: Satellite
|
private lateinit var selectedSat: Satellite
|
||||||
|
@ -66,7 +66,7 @@ class MapViewModel @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
satelliteRepo.getSelectedSatellites().also { selectedSatellites ->
|
satDataRepository.getSelectedSatellites().also { selectedSatellites ->
|
||||||
if (selectedSatellites.isNotEmpty()) {
|
if (selectedSatellites.isNotEmpty()) {
|
||||||
allSatList = selectedSatellites
|
allSatList = selectedSatellites
|
||||||
selectSatellite(selectedSatellites.first())
|
selectSatellite(selectedSatellites.first())
|
||||||
|
@ -76,7 +76,7 @@ class MapViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldUseTextLabels(): Boolean {
|
fun shouldUseTextLabels(): Boolean {
|
||||||
return preferenceSource.shouldUseTextLabels()
|
return preferencesSource.shouldUseTextLabels()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scrollSelection(decrement: Boolean) {
|
fun scrollSelection(decrement: Boolean) {
|
||||||
|
@ -171,13 +171,13 @@ class MapViewModel @Inject constructor(
|
||||||
val osmLon = getOsmLon(Math.toDegrees(satPos.longitude))
|
val osmLon = getOsmLon(Math.toDegrees(satPos.longitude))
|
||||||
val osmPos = Position(osmLat, osmLon)
|
val osmPos = Position(osmLat, osmLon)
|
||||||
val qthLoc =
|
val qthLoc =
|
||||||
preferenceSource.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
|
preferencesSource.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
|
||||||
val velocity = getOrbitalVelocity(satPos.altitude)
|
val velocity = getOrbitalVelocity(satPos.altitude)
|
||||||
val satData = SatData(
|
val satData = SatData(
|
||||||
sat, sat.tle.catnum, sat.tle.name, satPos.range,
|
sat, sat.tle.catnum, sat.tle.name, satPos.range,
|
||||||
satPos.altitude, velocity, qthLoc, osmPos
|
satPos.altitude, velocity, qthLoc, osmPos
|
||||||
)
|
)
|
||||||
this@MapViewModel._satData.postValue(satData)
|
this@SatMapViewModel._satData.postValue(satData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.polarScreen
|
package com.rtbishop.look4sat.presentation.satPassInfoScreen
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -34,15 +34,15 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PolarFragment : Fragment(R.layout.fragment_polar) {
|
class PassInfoFragment : Fragment(R.layout.fragment_polar) {
|
||||||
|
|
||||||
private val viewModel: PolarViewModel by viewModels()
|
private val viewModel: PassInfoViewModel by viewModels()
|
||||||
private var polarView: PolarView? = null
|
private var passInfoView: PassInfoView? = null
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
FragmentPolarBinding.bind(view).apply {
|
FragmentPolarBinding.bind(view).apply {
|
||||||
val transAdapter = TransAdapter()
|
val transAdapter = SatTransAdapter()
|
||||||
recycler.apply {
|
recycler.apply {
|
||||||
setHasFixedSize(true)
|
setHasFixedSize(true)
|
||||||
adapter = transAdapter
|
adapter = transAdapter
|
||||||
|
@ -65,27 +65,27 @@ class PolarFragment : Fragment(R.layout.fragment_polar) {
|
||||||
viewModel.disableSensor()
|
viewModel.disableSensor()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupObservers(transAdapter: TransAdapter, binding: FragmentPolarBinding) {
|
private fun setupObservers(satTransAdapter: SatTransAdapter, binding: FragmentPolarBinding) {
|
||||||
val catNum = requireArguments().getInt("catNum")
|
val catNum = requireArguments().getInt("catNum")
|
||||||
val aosTime = requireArguments().getLong("aosTime")
|
val aosTime = requireArguments().getLong("aosTime")
|
||||||
viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
|
viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
|
||||||
polarView = PolarView(requireContext()).apply { setPass(pass) }
|
passInfoView = PassInfoView(requireContext()).apply { setPass(pass) }
|
||||||
binding.frame.addView(polarView)
|
binding.frame.addView(passInfoView)
|
||||||
observeTransmitters(pass, transAdapter, binding)
|
observeTransmitters(pass, satTransAdapter, binding)
|
||||||
}
|
}
|
||||||
viewModel.orientation.observe(viewLifecycleOwner, { orientation ->
|
viewModel.orientation.observe(viewLifecycleOwner, { orientation ->
|
||||||
polarView?.setOrientation(orientation.first, orientation.second, orientation.third)
|
passInfoView?.setOrientation(orientation.first, orientation.second, orientation.third)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeTransmitters(
|
private fun observeTransmitters(
|
||||||
satPass: SatPass,
|
satPass: SatPass,
|
||||||
transAdapter: TransAdapter,
|
satTransAdapter: SatTransAdapter,
|
||||||
binding: FragmentPolarBinding
|
binding: FragmentPolarBinding
|
||||||
) {
|
) {
|
||||||
viewModel.transmitters.observe(viewLifecycleOwner, { list ->
|
viewModel.transmitters.observe(viewLifecycleOwner, { list ->
|
||||||
if (list.isNotEmpty()) {
|
if (list.isNotEmpty()) {
|
||||||
transAdapter.submitList(list)
|
satTransAdapter.submitList(list)
|
||||||
binding.recycler.visibility = View.VISIBLE
|
binding.recycler.visibility = View.VISIBLE
|
||||||
binding.noTransMsg.visibility = View.INVISIBLE
|
binding.noTransMsg.visibility = View.INVISIBLE
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,6 +93,7 @@ class PolarFragment : Fragment(R.layout.fragment_polar) {
|
||||||
binding.noTransMsg.visibility = View.VISIBLE
|
binding.noTransMsg.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
setPassText(satPass, binding)
|
setPassText(satPass, binding)
|
||||||
|
passInfoView?.invalidate()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.polarScreen
|
package com.rtbishop.look4sat.presentation.satPassInfoScreen
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.*
|
import android.graphics.*
|
||||||
|
@ -27,7 +27,7 @@ import java.util.*
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
class PolarView(context: Context) : View(context) {
|
class PassInfoView(context: Context) : View(context) {
|
||||||
|
|
||||||
private lateinit var satPass: SatPass
|
private lateinit var satPass: SatPass
|
||||||
private val polarWidth = resources.displayMetrics.widthPixels
|
private val polarWidth = resources.displayMetrics.widthPixels
|
|
@ -15,13 +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.polarScreen
|
package com.rtbishop.look4sat.presentation.satPassInfoScreen
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import com.rtbishop.look4sat.data.PassesRepo
|
import com.rtbishop.look4sat.data.SatPassRepository
|
||||||
import com.rtbishop.look4sat.data.PreferenceSource
|
import com.rtbishop.look4sat.data.PreferencesSource
|
||||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
import com.rtbishop.look4sat.data.SatDataRepository
|
||||||
import com.rtbishop.look4sat.di.IoDispatcher
|
import com.rtbishop.look4sat.injection.IoDispatcher
|
||||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||||
import com.rtbishop.look4sat.framework.OrientationProvider
|
import com.rtbishop.look4sat.framework.OrientationProvider
|
||||||
|
@ -35,11 +35,11 @@ import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class PolarViewModel @Inject constructor(
|
class PassInfoViewModel @Inject constructor(
|
||||||
private val orientationProvider: OrientationProvider,
|
private val orientationProvider: OrientationProvider,
|
||||||
private val preferenceSource: PreferenceSource,
|
private val preferencesSource: PreferencesSource,
|
||||||
private val passesRepo: PassesRepo,
|
private val satPassRepository: SatPassRepository,
|
||||||
private val satelliteRepo: SatelliteRepo,
|
private val satDataRepository: SatDataRepository,
|
||||||
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
||||||
) : ViewModel(), OrientationProvider.OrientationListener {
|
) : ViewModel(), OrientationProvider.OrientationListener {
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ class PolarViewModel @Inject constructor(
|
||||||
val orientation: LiveData<Triple<Float, Float, Float>> = _orientation
|
val orientation: LiveData<Triple<Float, Float, Float>> = _orientation
|
||||||
|
|
||||||
fun getPass(catNum: Int, aosTime: Long) = liveData {
|
fun getPass(catNum: Int, aosTime: Long) = liveData {
|
||||||
passesRepo.passes.collect { passes ->
|
satPassRepository.passes.collect { passes ->
|
||||||
val pass = passes.find { it.catNum == catNum && it.aosDate.time == aosTime }
|
val pass = passes.find { it.catNum == catNum && it.aosDate.time == aosTime }
|
||||||
pass?.let { satPass ->
|
pass?.let { satPass ->
|
||||||
processTransmitters(satPass)
|
processTransmitters(satPass)
|
||||||
|
@ -60,20 +60,20 @@ class PolarViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun enableSensor() {
|
fun enableSensor() {
|
||||||
if (preferenceSource.shouldUseCompass()) orientationProvider.startListening(this)
|
if (preferencesSource.shouldUseCompass()) orientationProvider.startListening(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableSensor() {
|
fun disableSensor() {
|
||||||
if (preferenceSource.shouldUseCompass()) orientationProvider.stopListening()
|
if (preferencesSource.shouldUseCompass()) orientationProvider.stopListening()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
|
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
|
||||||
_orientation.value = Triple(azimuth + preferenceSource.getMagDeclination(), pitch, roll)
|
_orientation.value = Triple(azimuth + preferencesSource.getMagDeclination(), pitch, roll)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initRotatorControl(satPass: SatPass) {
|
private fun initRotatorControl(satPass: SatPass) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val rotatorPrefs = preferenceSource.getRotatorServer()
|
val rotatorPrefs = preferencesSource.getRotatorServer()
|
||||||
if (rotatorPrefs != null) {
|
if (rotatorPrefs != null) {
|
||||||
runCatching {
|
runCatching {
|
||||||
withContext(ioDispatcher) {
|
withContext(ioDispatcher) {
|
||||||
|
@ -97,7 +97,7 @@ class PolarViewModel @Inject constructor(
|
||||||
|
|
||||||
private fun processTransmitters(satPass: SatPass) {
|
private fun processTransmitters(satPass: SatPass) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
satelliteRepo.getSatTransmitters(satPass.catNum).collect { transList ->
|
satDataRepository.getSatTransmitters(satPass.catNum).collect { transList ->
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
val timeNow = Date()
|
val timeNow = Date()
|
||||||
val copiedList = transList.map { it.copy() }
|
val copiedList = transList.map { it.copy() }
|
|
@ -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.polarScreen
|
package com.rtbishop.look4sat.presentation.satPassInfoScreen
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -27,7 +27,7 @@ import com.rtbishop.look4sat.databinding.ItemTransBinding
|
||||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class TransAdapter : RecyclerView.Adapter<TransAdapter.TransHolder>() {
|
class SatTransAdapter : RecyclerView.Adapter<SatTransAdapter.TransHolder>() {
|
||||||
|
|
||||||
private val diffCallback = object : DiffUtil.ItemCallback<SatTrans>() {
|
private val diffCallback = object : DiffUtil.ItemCallback<SatTrans>() {
|
||||||
override fun areItemsTheSame(oldItem: SatTrans, newItem: SatTrans): Boolean {
|
override fun areItemsTheSame(oldItem: SatTrans, newItem: SatTrans): Boolean {
|
|
@ -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.satPassScreen
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -29,7 +29,7 @@ import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PassesAdapter(private val isUTC: Boolean, private val clickListener: PassesClickListener) :
|
class SatPassAdapter(private val isUTC: Boolean, private val clickListener: PassesClickListener) :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
private val diffCallback = object : DiffUtil.ItemCallback<SatPass>() {
|
private val diffCallback = object : DiffUtil.ItemCallback<SatPass>() {
|
|
@ -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.satPassScreen
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -36,9 +36,9 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesClickListener {
|
class SatPassFragment : Fragment(R.layout.fragment_passes), SatPassAdapter.PassesClickListener {
|
||||||
|
|
||||||
private val viewModel: PassesViewModel by viewModels()
|
private val viewModel: SatPassViewModel by viewModels()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
@ -46,7 +46,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupComponents(view: View) {
|
private fun setupComponents(view: View) {
|
||||||
val passesAdapter = PassesAdapter(viewModel.shouldUseUTC(), this)
|
val passesAdapter = SatPassAdapter(viewModel.shouldUseUTC(), this)
|
||||||
val binding = FragmentPassesBinding.bind(view).apply {
|
val binding = FragmentPassesBinding.bind(view).apply {
|
||||||
passesRecycler.apply {
|
passesRecycler.apply {
|
||||||
setHasFixedSize(true)
|
setHasFixedSize(true)
|
||||||
|
@ -65,12 +65,12 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
|
||||||
|
|
||||||
private fun handleNewPasses(
|
private fun handleNewPasses(
|
||||||
result: Result<List<SatPass>>,
|
result: Result<List<SatPass>>,
|
||||||
passesAdapter: PassesAdapter,
|
satPassAdapter: SatPassAdapter,
|
||||||
binding: FragmentPassesBinding
|
binding: FragmentPassesBinding
|
||||||
) {
|
) {
|
||||||
when (result) {
|
when (result) {
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
passesAdapter.submitList(result.data)
|
satPassAdapter.submitList(result.data)
|
||||||
binding.apply {
|
binding.apply {
|
||||||
passesError.visibility = View.INVISIBLE
|
passesError.visibility = View.INVISIBLE
|
||||||
passesProgress.visibility = View.INVISIBLE
|
passesProgress.visibility = View.INVISIBLE
|
|
@ -15,16 +15,16 @@
|
||||||
* 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.satPassScreen
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rtbishop.look4sat.data.PassesRepo
|
import com.rtbishop.look4sat.data.PreferencesSource
|
||||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
import com.rtbishop.look4sat.data.SatDataRepository
|
||||||
|
import com.rtbishop.look4sat.data.SatPassRepository
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
import com.rtbishop.look4sat.framework.model.Result
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
@ -32,10 +32,10 @@ import kotlinx.coroutines.flow.collect
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class PassesViewModel @Inject constructor(
|
class SatPassViewModel @Inject constructor(
|
||||||
private val satelliteRepo: SatelliteRepo,
|
private val satDataRepository: SatDataRepository,
|
||||||
private val passesRepo: PassesRepo,
|
private val satPassRepository: SatPassRepository,
|
||||||
private val preferenceSource: PreferencesProvider
|
private val preferenceSource: PreferencesSource
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _passes = MutableLiveData<Result<List<SatPass>>>(Result.InProgress)
|
private val _passes = MutableLiveData<Result<List<SatPass>>>(Result.InProgress)
|
||||||
|
@ -45,10 +45,10 @@ class PassesViewModel @Inject constructor(
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_passes.postValue(Result.InProgress)
|
_passes.postValue(Result.InProgress)
|
||||||
passesRepo.triggerCalculation(satelliteRepo.getSelectedSatellites())
|
satPassRepository.triggerCalculation(satDataRepository.getSelectedSatellites())
|
||||||
}
|
}
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
passesRepo.passes.collect { passes ->
|
satPassRepository.passes.collect { passes ->
|
||||||
passesProcessing?.cancelAndJoin()
|
passesProcessing?.cancelAndJoin()
|
||||||
passesProcessing = viewModelScope.launch { tickPasses(passes) }
|
passesProcessing = viewModelScope.launch { tickPasses(passes) }
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ class PassesViewModel @Inject constructor(
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_passes.postValue(Result.InProgress)
|
_passes.postValue(Result.InProgress)
|
||||||
passesProcessing?.cancelAndJoin()
|
passesProcessing?.cancelAndJoin()
|
||||||
passesRepo.forceCalculation(satelliteRepo.getSelectedSatellites())
|
satPassRepository.forceCalculation(satDataRepository.getSelectedSatellites())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".presentation.infoScreen.InfoFragment">
|
tools:context=".presentation.appInfoScreen.AppInfoFragment">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_entries"
|
android:id="@+id/nav_entries"
|
||||||
android:name="com.rtbishop.look4sat.presentation.entriesScreen.EntriesFragment"
|
android:name="com.rtbishop.look4sat.presentation.satItemScreen.SatItemFragment"
|
||||||
tools:layout="@layout/fragment_entries">
|
tools:layout="@layout/fragment_entries">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_entries_to_passes"
|
android:id="@+id/action_entries_to_passes"
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_passes"
|
android:id="@+id/nav_passes"
|
||||||
android:name="com.rtbishop.look4sat.presentation.passesScreen.PassesFragment"
|
android:name="com.rtbishop.look4sat.presentation.satPassScreen.SatPassFragment"
|
||||||
tools:layout="@layout/fragment_passes">
|
tools:layout="@layout/fragment_passes">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_passes_to_polar"
|
android:id="@+id/action_passes_to_polar"
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_polar"
|
android:id="@+id/nav_polar"
|
||||||
android:name="com.rtbishop.look4sat.presentation.polarScreen.PolarFragment"
|
android:name="com.rtbishop.look4sat.presentation.satPassInfoScreen.PassInfoFragment"
|
||||||
tools:layout="@layout/fragment_polar">
|
tools:layout="@layout/fragment_polar">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_polar_to_passes"
|
android:id="@+id/action_polar_to_passes"
|
||||||
|
@ -48,20 +48,20 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_map"
|
android:id="@+id/nav_map"
|
||||||
android:name="com.rtbishop.look4sat.presentation.mapScreen.MapFragment"
|
android:name="com.rtbishop.look4sat.presentation.satMapScreen.SatMapFragment"
|
||||||
tools:layout="@layout/fragment_map" />
|
tools:layout="@layout/fragment_map" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_prefs"
|
android:id="@+id/nav_prefs"
|
||||||
android:name="com.rtbishop.look4sat.presentation.prefsScreen.PrefsFragment" />
|
android:name="com.rtbishop.look4sat.presentation.appSettingsScreen.AppSettingsFragment" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_info"
|
android:id="@+id/nav_info"
|
||||||
android:name="com.rtbishop.look4sat.presentation.infoScreen.InfoFragment"
|
android:name="com.rtbishop.look4sat.presentation.appInfoScreen.AppInfoFragment"
|
||||||
tools:layout="@layout/fragment_info" />
|
tools:layout="@layout/fragment_info" />
|
||||||
<dialog
|
<dialog
|
||||||
android:id="@+id/nav_dialog_splash"
|
android:id="@+id/nav_dialog_splash"
|
||||||
android:name="com.rtbishop.look4sat.presentation.splashDialog.SplashDialog"
|
android:name="com.rtbishop.look4sat.presentation.appSplashDialog.AppSplashDialog"
|
||||||
tools:layout="@layout/dialog_splash" />
|
tools:layout="@layout/dialog_splash" />
|
||||||
|
|
||||||
</navigation>
|
</navigation>
|
||||||
|
|
|
@ -2,7 +2,7 @@ package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||||
|
|
||||||
interface PreferenceSource {
|
interface PreferencesSource {
|
||||||
|
|
||||||
fun positionToQTH(lat: Double, lon: Double): String?
|
fun positionToQTH(lat: Double, lon: Double): String?
|
||||||
|
|
|
@ -6,7 +6,7 @@ import com.rtbishop.look4sat.domain.model.SatTrans
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface LocalDataSource {
|
interface SatDataLocalSource {
|
||||||
|
|
||||||
fun getSatItems(): Flow<List<SatItem>>
|
fun getSatItems(): Flow<List<SatItem>>
|
||||||
|
|
|
@ -3,7 +3,7 @@ package com.rtbishop.look4sat.data
|
||||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
interface RemoteDataSource {
|
interface SatDataRemoteSource {
|
||||||
|
|
||||||
suspend fun fetchDataStream(url: String): InputStream?
|
suspend fun fetchDataStream(url: String): InputStream?
|
||||||
|
|
|
@ -12,9 +12,10 @@ import kotlinx.coroutines.withContext
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
class SatelliteRepo(
|
class SatDataRepository(
|
||||||
private val localSource: LocalDataSource,
|
private val preferencesSource: PreferencesSource,
|
||||||
private val remoteSource: RemoteDataSource,
|
private val satLocalSource: SatDataLocalSource,
|
||||||
|
private val satRemoteSource: SatDataRemoteSource,
|
||||||
private val ioDispatcher: CoroutineDispatcher
|
private val ioDispatcher: CoroutineDispatcher
|
||||||
) {
|
) {
|
||||||
private val defaultSources = listOf(
|
private val defaultSources = listOf(
|
||||||
|
@ -24,20 +25,40 @@ class SatelliteRepo(
|
||||||
"https://www.prismnet.com/~mmccants/tles/inttles.zip"
|
"https://www.prismnet.com/~mmccants/tles/inttles.zip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val transmittersModes = arrayOf(
|
||||||
|
"AFSK", "AFSK S-Net", "AFSK SALSAT", "AHRPT", "AM", "APT", "BPSK", "BPSK PMT-A3",
|
||||||
|
"CERTO", "CW", "DQPSK", "DSTAR", "DUV", "FFSK", "FM", "FMN", "FSK", "FSK AX.100 Mode 5",
|
||||||
|
"FSK AX.100 Mode 6", "FSK AX.25 G3RUH", "GFSK", "GFSK Rktr", "GMSK", "HRPT", "LoRa",
|
||||||
|
"LRPT", "LSB", "MFSK", "MSK", "MSK AX.100 Mode 5", "MSK AX.100 Mode 6", "OFDM", "OQPSK",
|
||||||
|
"PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT"
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getAllModes(): Array<String> {
|
||||||
|
return transmittersModes
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveModesSelection(modes: List<String>) {
|
||||||
|
preferencesSource.saveModesSelection(modes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadModesSelection(): List<String> {
|
||||||
|
return preferencesSource.loadModesSelection()
|
||||||
|
}
|
||||||
|
|
||||||
fun getSatItems(): Flow<List<SatItem>> {
|
fun getSatItems(): Flow<List<SatItem>> {
|
||||||
return localSource.getSatItems()
|
return satLocalSource.getSatItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
|
fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
|
||||||
return localSource.getSatTransmitters(catNum)
|
return satLocalSource.getSatTransmitters(catNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getSelectedSatellites(): List<Satellite> {
|
suspend fun getSelectedSatellites(): List<Satellite> {
|
||||||
return localSource.getSelectedSatellites()
|
return satLocalSource.getSelectedSatellites()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateEntriesFromFile(stream: InputStream) = withContext(ioDispatcher) {
|
suspend fun updateEntriesFromFile(stream: InputStream) = withContext(ioDispatcher) {
|
||||||
localSource.updateEntries(importSatEntries(stream))
|
satLocalSource.updateEntries(importSatEntries(stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateEntriesFromWeb(sources: List<String> = defaultSources) {
|
suspend fun updateEntriesFromWeb(sources: List<String> = defaultSources) {
|
||||||
|
@ -46,7 +67,7 @@ class SatelliteRepo(
|
||||||
val streams = mutableListOf<InputStream>()
|
val streams = mutableListOf<InputStream>()
|
||||||
val entries = mutableListOf<SatEntry>()
|
val entries = mutableListOf<SatEntry>()
|
||||||
sources.forEach { source ->
|
sources.forEach { source ->
|
||||||
remoteSource.fetchDataStream(source)?.let { stream ->
|
satRemoteSource.fetchDataStream(source)?.let { stream ->
|
||||||
if (source.contains(".zip", true)) {
|
if (source.contains(".zip", true)) {
|
||||||
val zipStream = ZipInputStream(stream).apply { nextEntry }
|
val zipStream = ZipInputStream(stream).apply { nextEntry }
|
||||||
streams.add(zipStream)
|
streams.add(zipStream)
|
||||||
|
@ -56,17 +77,17 @@ class SatelliteRepo(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
streams.forEach { stream -> entries.addAll(importSatEntries(stream)) }
|
streams.forEach { stream -> entries.addAll(importSatEntries(stream)) }
|
||||||
localSource.updateEntries(entries)
|
satLocalSource.updateEntries(entries)
|
||||||
}
|
}
|
||||||
launch(ioDispatcher) {
|
launch(ioDispatcher) {
|
||||||
val transmitters = remoteSource.fetchTransmitters().filter { it.isAlive }
|
val transmitters = satRemoteSource.fetchTransmitters().filter { it.isAlive }
|
||||||
localSource.updateTransmitters(transmitters)
|
satLocalSource.updateTransmitters(transmitters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
|
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
|
||||||
localSource.updateEntriesSelection(catNums, isSelected)
|
satLocalSource.updateEntriesSelection(catNums, isSelected)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun importSatEntries(stream: InputStream): List<SatEntry> {
|
private fun importSatEntries(stream: InputStream): List<SatEntry> {
|
|
@ -25,8 +25,8 @@ import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PassesRepo(
|
class SatPassRepository(
|
||||||
private val preferenceSource: PreferenceSource,
|
private val preferencesSource: PreferencesSource,
|
||||||
private val defaultDispatcher: CoroutineDispatcher
|
private val defaultDispatcher: CoroutineDispatcher
|
||||||
) {
|
) {
|
||||||
private val _passes = MutableSharedFlow<List<SatPass>>(replay = 1)
|
private val _passes = MutableSharedFlow<List<SatPass>>(replay = 1)
|
||||||
|
@ -57,15 +57,15 @@ class PassesRepo(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPasses(satellite: Satellite, refDate: Date): List<SatPass> {
|
private fun getPasses(satellite: Satellite, refDate: Date): List<SatPass> {
|
||||||
val predictor = satellite.getPredictor(preferenceSource.loadStationPosition())
|
val predictor = satellite.getPredictor(preferencesSource.loadStationPosition())
|
||||||
return predictor.getPasses(refDate, preferenceSource.getHoursAhead(), true)
|
return predictor.getPasses(refDate, preferencesSource.getHoursAhead(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterPasses(passes: List<SatPass>, refDate: Date): List<SatPass> {
|
private fun filterPasses(passes: List<SatPass>, refDate: Date): List<SatPass> {
|
||||||
val timeFuture = Date(refDate.time + (preferenceSource.getHoursAhead() * 3600 * 1000))
|
val timeFuture = Date(refDate.time + (preferencesSource.getHoursAhead() * 3600 * 1000))
|
||||||
return passes.filter { it.losDate.after(refDate) }
|
return passes.filter { it.losDate.after(refDate) }
|
||||||
.filter { it.aosDate.before(timeFuture) }
|
.filter { it.aosDate.before(timeFuture) }
|
||||||
.filter { it.maxElevation > preferenceSource.getMinElevation() }
|
.filter { it.maxElevation > preferencesSource.getMinElevation() }
|
||||||
.sortedBy { it.aosDate }
|
.sortedBy { it.aosDate }
|
||||||
}
|
}
|
||||||
}
|
}
|
Ładowanie…
Reference in New Issue