Extracted logic into SettingsViewModel.kt

This commit is contained in:
Arty Bishop committed 2022-01-30 20:32:49 +00:00
1 parent 794d132086
commit b8bb6d41f9
22 files changed
+148 -104

No files matched your search

@@ -26,7 +26,7 @@ import android.location.LocationManager
import android.os.Bundle
import androidx.core.content.ContextCompat
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.LocationHandler
import com.rtbishop.look4sat.domain.ILocationHandler
import com.rtbishop.look4sat.domain.QthConverter
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.predict.GeoPos
@@ -38,10 +38,10 @@ import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class LocationProvider @Inject constructor(
class LocationHandler @Inject constructor(
@ApplicationContext private val context: Context,
private val settingsProvider: SettingsProvider,
) : LocationListener, LocationHandler {
private val settingsHandler: SettingsHandler,
) : LocationListener, ILocationHandler {
private val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
private val providerDef = LocationManager.PASSIVE_PROVIDER
@@ -50,7 +50,7 @@ class LocationProvider @Inject constructor(
private val locationCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
private val locationFine = Manifest.permission.ACCESS_FINE_LOCATION
private val _stationPosition = MutableStateFlow<DataState<GeoPos>>(DataState.Handled)
private var currentPosition = settingsProvider.loadStationPosition()
private var currentPosition = settingsHandler.loadStationPosition()
override val stationPosition: StateFlow<DataState<GeoPos>> = _stationPosition
@@ -61,7 +61,7 @@ class LocationProvider @Inject constructor(
val newLat = latitude.round(4)
val newLon = longitude.round(4)
currentPosition = GeoPos(newLat, newLon)
settingsProvider.saveStationPosition(newLat, newLon)
settingsHandler.saveStationPosition(newLat, newLon)
_stationPosition.value = DataState.Success(currentPosition)
} else _stationPosition.value =
DataState.Error(context.getString(R.string.pref_pos_gps_null))
@@ -26,7 +26,7 @@ import javax.inject.Singleton
import kotlin.math.round
@Singleton
class OrientationSource @Inject constructor(private val sensorManager: SensorManager) :
class OrientationHandler @Inject constructor(private val sensorManager: SensorManager) :
SensorEventListener {
interface OrientationListener {
@@ -20,13 +20,13 @@ package com.rtbishop.look4sat.framework
import android.content.SharedPreferences
import androidx.core.content.edit
import com.rtbishop.look4sat.BuildConfig
import com.rtbishop.look4sat.data.SettingsHandler
import com.rtbishop.look4sat.data.ISettingsHandler
import com.rtbishop.look4sat.domain.predict.GeoPos
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SettingsProvider @Inject constructor(private val prefs: SharedPreferences) : SettingsHandler {
class SettingsHandler @Inject constructor(private val prefs: SharedPreferences) : ISettingsHandler {
private val keyInitialSetup = "${BuildConfig.VERSION_NAME}update"
@@ -17,7 +17,7 @@
*/
package com.rtbishop.look4sat.framework.local
import com.rtbishop.look4sat.data.LocalDataSource
import com.rtbishop.look4sat.data.ILocalSource
import com.rtbishop.look4sat.domain.model.SatEntry
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.domain.model.Transmitter
@@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.map
class LocalSource(
private val entriesDao: EntriesDao,
private val transmittersDao: TransmittersDao
) : LocalDataSource {
) : ILocalSource {
override fun getSatelliteItems(): Flow<List<SatItem>> {
return entriesDao.getSatelliteItems().map { items -> items.toDomainItems() }
@@ -1,19 +1,15 @@
package com.rtbishop.look4sat.framework.remote
import com.rtbishop.look4sat.data.RemoteDataSource
import com.rtbishop.look4sat.data.IRemoteSource
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import java.io.InputStream
import java.net.URL
class RemoteSource(private val ioDispatcher: CoroutineDispatcher) : RemoteDataSource {
class RemoteSource(private val ioDispatcher: CoroutineDispatcher) : IRemoteSource {
@Suppress("BlockingMethodInNonBlockingContext")
override suspend fun fetchFileStream(url: String): InputStream? {
return try {
withContext(ioDispatcher) { URL(url).openStream() }
} catch (e: Exception) {
null
}
return withContext(ioDispatcher) { URL(url).openStream() }
}
}
@@ -20,15 +20,15 @@ package com.rtbishop.look4sat.injection
import android.content.Context
import android.content.SharedPreferences
import androidx.room.Room
import com.rtbishop.look4sat.data.DefaultRepository
import com.rtbishop.look4sat.data.SettingsHandler
import com.rtbishop.look4sat.data.DataRepository
import com.rtbishop.look4sat.data.ISettingsHandler
import com.rtbishop.look4sat.domain.DataParser
import com.rtbishop.look4sat.domain.DataReporter
import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.LocationHandler
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.ILocationHandler
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.framework.LocationProvider
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.LocationHandler
import com.rtbishop.look4sat.framework.SettingsHandler
import com.rtbishop.look4sat.framework.local.*
import com.rtbishop.look4sat.framework.remote.RemoteSource
import dagger.Module
@@ -46,33 +46,33 @@ object CoreModule {
@Provides
@Singleton
fun provideSatelliteRepo(
settingsHandler: SettingsHandler,
settingsHandler: ISettingsHandler,
@ApplicationContext context: Context,
@IoDispatcher ioDispatcher: CoroutineDispatcher,
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
): DataRepository {
): IDataRepository {
val dataParser = DataParser(defaultDispatcher)
val db = Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5)
.fallbackToDestructiveMigration().build()
val localSource = LocalSource(db.entriesDao(), db.transmittersDao())
val remoteSource = RemoteSource(ioDispatcher)
return DefaultRepository(dataParser, localSource, remoteSource, settingsHandler)
return DataRepository(dataParser, localSource, remoteSource, settingsHandler)
}
@Provides
@Singleton
fun provideSettingsHandler(sharedPreferences: SharedPreferences): SettingsHandler {
return SettingsProvider(sharedPreferences)
fun provideSettingsHandler(sharedPreferences: SharedPreferences): ISettingsHandler {
return SettingsHandler(sharedPreferences)
}
@Provides
@Singleton
fun provideLocationHandler(
@ApplicationContext context: Context,
settingsProvider: SettingsProvider
): LocationHandler {
return LocationProvider(context, settingsProvider)
settingsHandler: SettingsHandler
): ILocationHandler {
return LocationHandler(context, settingsHandler)
}
@Provides
@@ -2,9 +2,9 @@ package com.rtbishop.look4sat.presentation
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.SettingsHandler
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -12,8 +12,8 @@ import javax.inject.Inject
@HiltViewModel
class MainViewModel @Inject constructor(
private val predictor: Predictor,
private val preferences: SettingsProvider,
private val dataRepository: DataRepository
private val preferences: SettingsHandler,
private val dataRepository: IDataRepository
) : ViewModel() {
fun calculatePasses(
@@ -19,10 +19,10 @@ package com.rtbishop.look4sat.presentation.entriesScreen
import android.widget.SearchView
import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.SettingsHandler
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import java.util.*
@@ -30,8 +30,8 @@ import javax.inject.Inject
@HiltViewModel
class EntriesViewModel @Inject constructor(
private val preferences: SettingsProvider,
private val dataRepository: DataRepository
private val preferences: SettingsHandler,
private val dataRepository: IDataRepository
) : ViewModel(), SearchView.OnQueryTextListener, EntriesAdapter.EntriesClickListener {
private val transModes = MutableLiveData(preferences.loadModesSelection())
@@ -18,12 +18,12 @@
package com.rtbishop.look4sat.presentation.mapScreen
import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.QthConverter
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.domain.predict.Satellite
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.SettingsHandler
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import java.util.*
@@ -33,9 +33,9 @@ import kotlin.math.min
@HiltViewModel
class MapViewModel @Inject constructor(
private val dataRepository: DataRepository,
private val dataRepository: IDataRepository,
private val predictor: Predictor,
preferences: SettingsProvider,
preferences: SettingsHandler,
) : ViewModel() {
private val stationPos = preferences.loadStationPosition()
@@ -8,7 +8,7 @@ import android.view.WindowManager
import androidx.appcompat.app.AppCompatDialogFragment
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.DialogPassesBinding
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.SettingsHandler
import com.rtbishop.look4sat.presentation.setNavResult
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@@ -17,7 +17,7 @@ import javax.inject.Inject
class PassesPrefsDialog : AppCompatDialogFragment() {
@Inject
lateinit var preferences: SettingsProvider
lateinit var preferences: SettingsHandler
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
return inflater.inflate(R.layout.dialog_passes, group, false)
@@ -21,20 +21,20 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.SettingsHandler
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import javax.inject.Inject
@HiltViewModel
class PassesViewModel @Inject constructor(
private val dataRepository: DataRepository,
private val dataRepository: IDataRepository,
private val predictor: Predictor,
private val preferences: SettingsProvider
private val preferences: SettingsHandler
) : ViewModel() {
private val _passes = MutableLiveData<DataState<List<SatPass>>>()
@@ -30,7 +30,7 @@ import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentRadarBinding
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.SettingsHandler
import com.rtbishop.look4sat.presentation.navigateSafe
import com.rtbishop.look4sat.presentation.toTimerString
import dagger.hilt.android.AndroidEntryPoint
@@ -40,7 +40,7 @@ import javax.inject.Inject
class RadarFragment : Fragment(R.layout.fragment_radar) {
@Inject
lateinit var preferences: SettingsProvider
lateinit var preferences: SettingsHandler
private val viewModel: RadarViewModel by viewModels()
private var radarView: RadarView? = null
@@ -20,14 +20,14 @@ package com.rtbishop.look4sat.presentation.radarScreen
import android.hardware.GeomagneticField
import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.DataReporter
import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.model.Transmitter
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.framework.OrientationSource
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.OrientationHandler
import com.rtbishop.look4sat.framework.SettingsHandler
import com.rtbishop.look4sat.presentation.round
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
@@ -38,12 +38,12 @@ import javax.inject.Inject
@HiltViewModel
class RadarViewModel @Inject constructor(
private val orientationSource: OrientationSource,
private val preferences: SettingsProvider,
private val orientationHandler: OrientationHandler,
private val preferences: SettingsHandler,
private val predictor: Predictor,
private val dataRepository: DataRepository,
private val dataRepository: IDataRepository,
private val dataReporter: DataReporter
) : ViewModel(), OrientationSource.OrientationListener {
) : ViewModel(), OrientationHandler.OrientationListener {
private val stationPos = preferences.loadStationPosition()
private val _passData = MutableLiveData<RadarData>()
@@ -65,11 +65,11 @@ class RadarViewModel @Inject constructor(
}
fun enableSensor() {
if (preferences.getUseCompass()) orientationSource.startListening(this)
if (preferences.getUseCompass()) orientationHandler.startListening(this)
}
fun disableSensor() {
if (preferences.getUseCompass()) orientationSource.stopListening()
if (preferences.getUseCompass()) orientationHandler.stopListening()
}
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
@@ -18,7 +18,6 @@
package com.rtbishop.look4sat.presentation.settingsScreen
import android.Manifest
import android.content.ContentResolver
import android.content.Intent
import android.net.Uri
import android.os.Bundle
@@ -30,17 +29,15 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.asLiveData
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.rtbishop.look4sat.BuildConfig
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentSettingsBinding
import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.LocationHandler
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.SettingsHandler
import com.rtbishop.look4sat.presentation.*
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@@ -49,33 +46,22 @@ import javax.inject.Inject
class SettingsFragment : Fragment(R.layout.fragment_settings) {
@Inject
lateinit var preferences: SettingsProvider
@Inject
lateinit var locationHandler: LocationHandler
@Inject
lateinit var resolver: ContentResolver
@Inject
lateinit var dataRepository: DataRepository
lateinit var preferences: SettingsHandler
private val viewModel: SettingsViewModel by viewModels()
private val locationFine = Manifest.permission.ACCESS_FINE_LOCATION
private val locationCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
private val locationContract = ActivityResultContracts.RequestMultiplePermissions()
private val locationRequest = registerForActivityResult(locationContract) { permissions ->
when {
permissions[locationFine] == true -> locationHandler.setPositionFromGps()
permissions[locationCoarse] == true -> locationHandler.setPositionFromNet()
permissions[locationFine] == true -> viewModel.setPositionFromGps()
permissions[locationCoarse] == true -> viewModel.setPositionFromNet()
else -> showToast(getString(R.string.pref_pos_gps_error))
}
}
private val contentContract = ActivityResultContracts.GetContent()
private val contentRequest = registerForActivityResult(contentContract) { uri ->
lifecycleScope.launchWhenResumed {
@Suppress("BlockingMethodInNonBlockingContext")
resolver.openInputStream(uri)?.use { dataRepository.updateDataFromFile(it) }
}
viewModel.updateDataFromFile(uri)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -88,7 +74,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
setupTrackingCard(settingsBinding)
setupOtherCard(settingsBinding)
setupWarrantyCard(settingsBinding)
locationHandler.stationPosition.asLiveData().observe(viewLifecycleOwner) { stationPos ->
viewModel.stationPosition.asLiveData().observe(viewLifecycleOwner) { stationPos ->
stationPos?.let { handleStationPosition(it, settingsBinding) }
}
}
@@ -108,7 +94,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
}
private fun setupLocationCard(binding: FragmentSettingsBinding) {
setPositionText(locationHandler.getStationPosition(), binding)
setPositionText(viewModel.getStationPosition(), binding)
binding.prefsLocation.locationBtnGps.setOnClickListener {
locationRequest.launch(arrayOf(locationFine, locationCoarse))
}
@@ -119,7 +105,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
.setEditText(editText)
.setPositiveButton("OK") { _, _ ->
val editTextInput = editText.text.toString()
locationHandler.setPositionFromQth(editTextInput)
viewModel.setPositionFromQth(editTextInput)
}
.setNeutralButton("Cancel", null)
.create()
@@ -133,7 +119,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
findNavController().navigateSafe(R.id.action_prefs_to_sources)
}
getNavResult<List<String>>(R.id.nav_settings, "sources") { sources ->
lifecycleScope.launchWhenResumed { dataRepository.updateDataFromWeb(sources) }
viewModel.updateDataFromWeb(sources)
}
}
@@ -191,12 +177,12 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
setPositionText(pos.data, binding)
binding.prefsLocation.locationProgress.isIndeterminate = false
showToast(getString(R.string.pref_pos_success))
locationHandler.setPositionHandled()
viewModel.setPositionHandled()
}
is DataState.Error -> {
binding.prefsLocation.locationProgress.isIndeterminate = false
showToast(pos.message.toString())
locationHandler.setPositionHandled()
viewModel.setPositionHandled()
}
DataState.Loading -> {
binding.prefsLocation.locationProgress.isIndeterminate = true
@@ -0,0 +1,62 @@
package com.rtbishop.look4sat.presentation.settingsScreen
import android.content.ContentResolver
import android.net.Uri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.ILocationHandler
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.framework.SettingsHandler
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class SettingsViewModel @Inject constructor(
private val resolver: ContentResolver,
private val settingsHandler: SettingsHandler,
private val dataRepository: IDataRepository,
private val locationHandler: ILocationHandler
) : ViewModel(), ILocationHandler {
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Handled $exception in CoroutineExceptionHandler")
}
fun updateDataFromFile(uri: Uri) {
viewModelScope.launch(exceptionHandler) {
@Suppress("BlockingMethodInNonBlockingContext")
resolver.openInputStream(uri)?.use { fileUri ->
dataRepository.updateDataFromFile(fileUri)
}
}
}
fun updateDataFromWeb(sources: List<String>) {
viewModelScope.launch(exceptionHandler) {
dataRepository.updateDataFromWeb(sources)
}
}
override val stationPosition: SharedFlow<DataState<GeoPos>> = locationHandler.stationPosition
override fun getStationPosition(): GeoPos = locationHandler.getStationPosition()
override fun setStationPosition(latitude: Double, longitude: Double) {
locationHandler.setStationPosition(latitude, longitude)
}
override fun setPositionFromGps() = locationHandler.setPositionFromGps()
override fun setPositionFromNet() = locationHandler.setPositionFromNet()
override fun setPositionFromQth(qthString: String) {
locationHandler.setPositionFromQth(qthString)
}
override fun setPositionHandled() = locationHandler.setPositionHandled()
}
@@ -25,7 +25,7 @@ import android.view.WindowManager
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.SettingsHandler
import com.rtbishop.look4sat.data.ISettingsHandler
import com.rtbishop.look4sat.databinding.DialogSourcesBinding
import com.rtbishop.look4sat.framework.model.Source
import com.rtbishop.look4sat.presentation.setNavResult
@@ -36,7 +36,7 @@ import javax.inject.Inject
class SourcesDialog : AppCompatDialogFragment() {
@Inject
lateinit var settings: SettingsHandler
lateinit var settings: ISettingsHandler
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
return inflater.inflate(R.layout.dialog_sources, group, false)