Moved and renamed various classes to simplify structure

pull/65/head
Arty Bishop 2021-05-08 15:44:19 +01:00
rodzic c91c58ac69
commit fdb5752408
33 zmienionych plików z 224 dodań i 214 usunięć

Wyświetl plik

@ -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"

Wyświetl plik

@ -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
)
}
}
}

Wyświetl plik

@ -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())
}
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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")

Wyświetl plik

@ -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
} }

Wyświetl plik

@ -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)
} }
} }

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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)
} }
} }

Wyświetl plik

@ -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?) {

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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 {

Wyświetl plik

@ -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)

Wyświetl plik

@ -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> {

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)
} }
} }

Wyświetl plik

@ -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()
}) })
} }

Wyświetl plik

@ -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

Wyświetl plik

@ -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() }

Wyświetl plik

@ -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 {

Wyświetl plik

@ -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>() {

Wyświetl plik

@ -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

Wyświetl plik

@ -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())
} }
} }

Wyświetl plik

@ -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"

Wyświetl plik

@ -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>

Wyświetl plik

@ -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?

Wyświetl plik

@ -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>>

Wyświetl plik

@ -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?

Wyświetl plik

@ -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> {

Wyświetl plik

@ -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 }
} }
} }