diff --git a/app/build.gradle b/app/build.gradle index 186935cb..0c872475 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,19 +5,7 @@ plugins { id "dagger.hilt.android.plugin" } -def keystorePropertiesFile = rootProject.file("keystore.properties") -def keystoreProperties = new Properties() -keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) - android { - signingConfigs { - release { - storeFile file(keystoreProperties['storeFile']) - storePassword keystoreProperties['storePassword'] - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - } - } compileSdkVersion 30 buildToolsVersion "30.0.3" @@ -25,8 +13,8 @@ android { applicationId "com.rtbishop.look4sat" minSdkVersion 21 targetSdkVersion 30 - versionCode 222 - versionName "2.2.2" + versionCode 230 + versionName "2.3.0" kapt { arguments { arg("room.schemaLocation", "$projectDir/schemas") @@ -36,7 +24,6 @@ android { buildTypes { release { - signingConfig signingConfigs.release postprocessing { removeUnusedCode true removeUnusedResources true diff --git a/app/src/main/java/com/rtbishop/look4sat/data/database/SatelliteDao.kt b/app/src/main/java/com/rtbishop/look4sat/data/database/SatelliteDao.kt index 32649739..de6ee3f4 100644 --- a/app/src/main/java/com/rtbishop/look4sat/data/database/SatelliteDao.kt +++ b/app/src/main/java/com/rtbishop/look4sat/data/database/SatelliteDao.kt @@ -58,17 +58,17 @@ interface SatelliteDao { @Transaction suspend fun restoreEntriesSelection(catNums: List, isSelected: Boolean) { clearEntriesSelection() - catNums.forEach { catNum -> updateItemSelection(catNum, isSelected) } + catNums.forEach { catNum -> updateEntrySelection(catNum, isSelected) } } @Transaction suspend fun updateEntriesSelection(catNums: List, isSelected: Boolean) { - catNums.forEach { catNum -> updateItemSelection(catNum, isSelected) } + catNums.forEach { catNum -> updateEntrySelection(catNum, isSelected) } } @Query("UPDATE entries SET isSelected = 0") suspend fun clearEntriesSelection() @Query("UPDATE entries SET isSelected = :isSelected WHERE catNum = :catNum") - suspend fun updateItemSelection(catNum: Int, isSelected: Boolean) + suspend fun updateEntrySelection(catNum: Int, isSelected: Boolean) } diff --git a/app/src/main/java/com/rtbishop/look4sat/data/model/SatEntry.kt b/app/src/main/java/com/rtbishop/look4sat/data/model/SatEntry.kt index 60734a6a..f8b4e528 100644 --- a/app/src/main/java/com/rtbishop/look4sat/data/model/SatEntry.kt +++ b/app/src/main/java/com/rtbishop/look4sat/data/model/SatEntry.kt @@ -22,7 +22,7 @@ import androidx.room.PrimaryKey import com.github.amsacode.predict4java.TLE @Entity(tableName = "entries") -class SatEntry( +data class SatEntry( val tle: TLE, var isSelected: Boolean = false, @PrimaryKey val catNum: Int = tle.catnum, diff --git a/app/src/main/java/com/rtbishop/look4sat/data/model/SatTrans.kt b/app/src/main/java/com/rtbishop/look4sat/data/model/SatTrans.kt index f9997471..9af320c7 100644 --- a/app/src/main/java/com/rtbishop/look4sat/data/model/SatTrans.kt +++ b/app/src/main/java/com/rtbishop/look4sat/data/model/SatTrans.kt @@ -22,7 +22,7 @@ import androidx.room.PrimaryKey import com.squareup.moshi.Json @Entity(tableName = "transmitters") -class SatTrans( +data class SatTrans( @PrimaryKey @field:Json(name = "uuid") val uuid: String, @field:Json(name = "description") val info: String, @field:Json(name = "alive") val isAlive: Boolean, diff --git a/app/src/main/java/com/rtbishop/look4sat/data/model/SelectedSat.kt b/app/src/main/java/com/rtbishop/look4sat/data/model/SelectedSat.kt index e0f42203..98e8e9ec 100644 --- a/app/src/main/java/com/rtbishop/look4sat/data/model/SelectedSat.kt +++ b/app/src/main/java/com/rtbishop/look4sat/data/model/SelectedSat.kt @@ -21,7 +21,7 @@ import com.github.amsacode.predict4java.Position import com.github.amsacode.predict4java.Satellite import org.osmdroid.views.overlay.Overlay -class SelectedSat( +data class SelectedSat( val pass: Satellite, val catNum: Int, val name: String, diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/Look4SatApplication.kt b/app/src/main/java/com/rtbishop/look4sat/ui/Look4SatApplication.kt index 6f11a9ff..b15536c2 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/Look4SatApplication.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/Look4SatApplication.kt @@ -27,8 +27,6 @@ class Look4SatApplication : Application() { override fun onCreate() { super.onCreate() - if (BuildConfig.DEBUG) { - Timber.plant(Timber.DebugTree()) - } + if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree()) } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesFragment.kt index 30911003..c343c338 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesFragment.kt @@ -25,7 +25,6 @@ import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator -import com.google.android.material.snackbar.Snackbar import com.rtbishop.look4sat.R import com.rtbishop.look4sat.data.model.Result import com.rtbishop.look4sat.data.model.SatItem @@ -33,6 +32,7 @@ import com.rtbishop.look4sat.data.model.TleSource import com.rtbishop.look4sat.databinding.FragmentEntriesBinding import com.rtbishop.look4sat.utility.RecyclerDivider import com.rtbishop.look4sat.utility.getNavResult +import com.rtbishop.look4sat.utility.showSnack import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -63,7 +63,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) { } importWeb.setOnClickListener { findNavController().navigate(R.id.nav_dialog_sources) } importFile.setOnClickListener { filePicker.launch("*/*") } - selectMode.setOnClickListener { showModesDialog() } + selectMode.setOnClickListener { viewModel.createModesDialog(requireContext()).show() } selectAll.setOnClickListener { viewModel.selectCurrentItems() } searchBar.setOnQueryTextListener(viewModel) } @@ -75,10 +75,6 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) { } } - private fun showModesDialog() { - viewModel.createModesDialog(requireContext()).show() - } - private fun handleSatData( result: Result>, binding: FragmentEntriesBinding, @@ -98,8 +94,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) { is Result.Error -> { binding.entriesProgress.visibility = View.INVISIBLE binding.entriesRecycler.visibility = View.VISIBLE - val errorMsg = getString(R.string.entries_update_error) - Snackbar.make(requireView(), errorMsg, Snackbar.LENGTH_SHORT).show() + requireView().showSnack(getString(R.string.entries_update_error)) } } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt index 6ad30638..f0c17610 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt @@ -142,6 +142,7 @@ class EntriesViewModel @Inject constructor( } private fun filterByQuery(items: List, query: String): List { + shouldSelectAll = true if (query.isBlank()) return items return try { items.filter { it.catNum == query.toInt() } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapFragment.kt index 70f118d8..8d74082c 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapFragment.kt @@ -126,7 +126,11 @@ class MapFragment : Fragment(R.layout.fragment_map) { ContextCompat.getColor(requireContext(), R.color.themeLight) setTextIcon(it.key.tle.name) setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER) - position = GeoPoint(it.value.lat, it.value.lon) + try { + position = GeoPoint(it.value.lat, it.value.lon) + } catch (e: IllegalArgumentException) { + Timber.d("Position: $position") + } setOnMarkerClickListener { _, _ -> mapViewModel.selectSatellite(it.key) return@setOnMarkerClickListener true @@ -138,7 +142,11 @@ class MapFragment : Fragment(R.layout.fragment_map) { setInfoWindow(null) setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER) icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_map_sat) - position = GeoPoint(it.value.lat, it.value.lon) + try { + position = GeoPoint(it.value.lat, it.value.lon) + } catch (e: IllegalArgumentException) { + Timber.d("Position: $position") + } setOnMarkerClickListener { _, _ -> mapViewModel.selectSatellite(it.key) return@setOnMarkerClickListener true diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/Orientation.kt b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/Orientation.kt index ae3005b1..9d647663 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/Orientation.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/Orientation.kt @@ -40,17 +40,13 @@ class Orientation @Inject constructor( private val mRotationMatrix = FloatArray(9) private val mOrientationValues = FloatArray(3) private val mOneRadDegrees = 57.295779513f - private var mLastAccuracy: Int = SensorManager.SENSOR_STATUS_UNRELIABLE private var mListener: OrientationListener? = null fun startListening(listener: OrientationListener) { - when { - mListener === listener -> return - else -> { - mListener = listener - mSensorManager.registerListener(this, mRotationSensor, 16000) - } - } + if (mListener !== listener) { + mListener = listener + mSensorManager.registerListener(this, mRotationSensor, 16000) + } else return } fun stopListening() { @@ -58,16 +54,11 @@ class Orientation @Inject constructor( mListener = null } - override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) { - mLastAccuracy = accuracy - } + override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {} override fun onSensorChanged(event: SensorEvent) { - when { - mListener == null -> return - mLastAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE -> return - event.sensor == mRotationSensor -> updateOrientation(event.values) - } + if (mListener == null) return + else if (event.sensor == mRotationSensor) updateOrientation(event.values) } @Suppress("DEPRECATION") diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarFragment.kt index f8de9777..77c1deaf 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarFragment.kt @@ -31,43 +31,36 @@ import com.rtbishop.look4sat.utility.RecyclerDivider import com.rtbishop.look4sat.utility.formatForTimer import dagger.hilt.android.AndroidEntryPoint import java.util.* -import javax.inject.Inject @AndroidEntryPoint -class PolarFragment : Fragment(R.layout.fragment_polar), Orientation.OrientationListener { - - @Inject - lateinit var orientation: Orientation +class PolarFragment : Fragment(R.layout.fragment_polar) { private val viewModel: PolarViewModel by viewModels() private var polarView: PolarView? = null - private var magneticDeclination = 0f override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val binding = FragmentPolarBinding.bind(view) val catNum = requireArguments().getInt("catNum") val aosTime = requireArguments().getLong("aosTime") - magneticDeclination = viewModel.getMagDeclination() viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass -> polarView = PolarView(requireContext()).apply { setPass(pass) } binding.frame.addView(polarView) observeTransmitters(pass, binding) } + viewModel.azimuth.observe(viewLifecycleOwner, { trueNorthAzimuth -> + polarView?.rotation = -trueNorthAzimuth + }) } override fun onResume() { super.onResume() - if (viewModel.shouldUseCompass()) orientation.startListening(this) + viewModel.enableSensor() } override fun onPause() { super.onPause() - if (viewModel.shouldUseCompass()) orientation.stopListening() - } - - override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) { - polarView?.rotation = -(azimuth + magneticDeclination) + viewModel.disableSensor() } private fun observeTransmitters(satPass: SatPass, binding: FragmentPolarBinding) { diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarViewModel.kt index 20622aab..83ce0831 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarViewModel.kt @@ -17,10 +17,7 @@ */ package com.rtbishop.look4sat.ui.polarScreen -import androidx.lifecycle.ViewModel -import androidx.lifecycle.asLiveData -import androidx.lifecycle.liveData -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.* import com.rtbishop.look4sat.data.model.Result import com.rtbishop.look4sat.data.repository.PassesRepo import com.rtbishop.look4sat.data.repository.SatelliteRepo @@ -32,10 +29,15 @@ import javax.inject.Inject @HiltViewModel class PolarViewModel @Inject constructor( + private val orientation: Orientation, private val prefsManager: PrefsManager, private val passesRepo: PassesRepo, private val satelliteRepo: SatelliteRepo -) : ViewModel() { +) : ViewModel(), Orientation.OrientationListener { + + private val magDeclination = prefsManager.getMagDeclination() + private val _azimuth = MutableLiveData() + val azimuth: LiveData = _azimuth fun getAppTimer() = liveData { while (true) { @@ -53,14 +55,18 @@ class PolarViewModel @Inject constructor( } } - fun shouldUseCompass(): Boolean { - return prefsManager.shouldUseCompass() + fun enableSensor() { + if (prefsManager.shouldUseCompass()) orientation.startListening(this) } - fun getMagDeclination(): Float { - return prefsManager.getMagDeclination() + fun disableSensor() { + if (prefsManager.shouldUseCompass()) orientation.stopListening() } fun getSatTransmitters(satId: Int) = satelliteRepo.getSatTransmitters(satId).asLiveData(viewModelScope.coroutineContext) + + override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) { + _azimuth.value = azimuth + magDeclination + } } \ No newline at end of file diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/prefsScreen/PrefsFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/prefsScreen/PrefsFragment.kt index 5b0eb9a2..64533961 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/prefsScreen/PrefsFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/prefsScreen/PrefsFragment.kt @@ -26,11 +26,11 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat -import com.google.android.material.snackbar.Snackbar import com.rtbishop.look4sat.R import com.rtbishop.look4sat.utility.PrefsManager import com.rtbishop.look4sat.utility.QthConverter import com.rtbishop.look4sat.utility.round +import com.rtbishop.look4sat.utility.showSnack import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -39,20 +39,15 @@ class PrefsFragment : PreferenceFragmentCompat() { @Inject lateinit var locationManager: LocationManager - @Inject lateinit var prefsManager: PrefsManager - @Inject lateinit var qthConverter: QthConverter private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> - if (isGranted) { - setPositionFromGPS() - } else { - showSnack(getString(R.string.pref_pos_gps_error)) - } + if (isGranted) setPositionFromGPS() + else requireView().showSnack(getString(R.string.pref_pos_gps_error)) } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { @@ -79,10 +74,10 @@ class PrefsFragment : PreferenceFragmentCompat() { private fun setPositionFromQth(qthString: String): Boolean { qthConverter.qthToLocation(qthString)?.let { gsp -> prefsManager.setStationPosition(gsp.latitude, gsp.longitude, gsp.heightAMSL) - showSnack(getString(R.string.pref_pos_success)) + requireView().showSnack(getString(R.string.pref_pos_success)) return true } - showSnack(getString(R.string.pref_pos_qth_error)) + requireView().showSnack(getString(R.string.pref_pos_qth_error)) return false } @@ -96,14 +91,8 @@ class PrefsFragment : PreferenceFragmentCompat() { val longitude = location.longitude.round(4) val altitude = location.altitude.round(1) prefsManager.setStationPosition(latitude, longitude, altitude) - showSnack(getString(R.string.pref_pos_success)) - } else showSnack(getString(R.string.pref_pos_gps_null)) + requireView().showSnack(getString(R.string.pref_pos_success)) + } else requireView().showSnack(getString(R.string.pref_pos_gps_null)) } else requestPermissionLauncher.launch(locPermString) } - - private fun showSnack(message: String) { - Snackbar.make(requireView(), message, Snackbar.LENGTH_SHORT) - .setAnchorView(R.id.nav_bottom) - .show() - } } diff --git a/app/src/main/java/com/rtbishop/look4sat/utility/Extensions.kt b/app/src/main/java/com/rtbishop/look4sat/utility/Extensions.kt index d3857932..99c6dc99 100644 --- a/app/src/main/java/com/rtbishop/look4sat/utility/Extensions.kt +++ b/app/src/main/java/com/rtbishop/look4sat/utility/Extensions.kt @@ -23,6 +23,7 @@ import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest import android.os.Bundle +import android.view.View import androidx.annotation.IdRes import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle @@ -33,6 +34,8 @@ import androidx.navigation.Navigator import androidx.navigation.fragment.findNavController import com.github.amsacode.predict4java.GroundStationPosition import com.github.amsacode.predict4java.Satellite +import com.google.android.material.snackbar.Snackbar +import com.rtbishop.look4sat.R import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -77,6 +80,12 @@ fun Satellite.getPredictor(stationPosition: GroundStationPosition): PassPredicto return PassPredictor(this, stationPosition) } +fun View.showSnack(message: String) { + Snackbar.make(this, message, Snackbar.LENGTH_SHORT) + .setAnchorView(R.id.nav_bottom) + .show() +} + fun NavController.navigateSafe( @IdRes resId: Int, args: Bundle? = null, diff --git a/fastlane/metadata/android/en-US/changelogs/230.txt b/fastlane/metadata/android/en-US/changelogs/230.txt new file mode 100644 index 00000000..395b171e --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/230.txt @@ -0,0 +1,6 @@ +Added satellite items filtering by transmitter mode +Now updating recyclers views asyncronously +Switched to concurrent satellite data update +Minor visual changes to map info +Separated application screens logic +Bug fixes, huge code cleanup \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/whatsnew/whatsnew-en-US b/fastlane/metadata/android/en-US/whatsnew/whatsnew-en-US index 4f057a3b..395b171e 100644 --- a/fastlane/metadata/android/en-US/whatsnew/whatsnew-en-US +++ b/fastlane/metadata/android/en-US/whatsnew/whatsnew-en-US @@ -1,8 +1,6 @@ -Fixed NullPointerException in EntriesFragment's update from file -Fixed IllegalArgumentException on passes navigate action -Fixed select all logic in Entries adapter -Now correctly popping back stack on PolarView pass end -Now using passes screen as a start destination -Added zipped TLE import from Mike McCants' web site -Added McCants' classified and integrated TLEs to default sources -Added privacy policy to info screen, switched to GPL v3 licence \ No newline at end of file +Added satellite items filtering by transmitter mode +Now updating recyclers views asyncronously +Switched to concurrent satellite data update +Minor visual changes to map info +Separated application screens logic +Bug fixes, huge code cleanup \ No newline at end of file