Moved and renamed several classes

This commit is contained in:
Arty Bishop committed 2021-09-18 16:48:05 +01:00
1 parent f295b3b224
commit 1fafd04190
43 files changed
+424 -403

No files matched your search

@@ -33,19 +33,19 @@ object Converters {
@JvmStatic
@TypeConverter
fun tleToString(tle: TLE): String {
fun paramsToString(tle: TLE): String {
return paramsAdapter.toJson(tle)
}
@JvmStatic
@TypeConverter
fun tleFromString(string: String): TLE? {
fun paramsFromString(string: String): TLE? {
return paramsAdapter.fromJson(string)
}
@JvmStatic
@TypeConverter
fun satFromString(string: String): Satellite? {
fun satelliteFromString(string: String): Satellite? {
return paramsAdapter.fromJson(string)?.createSat()
}
}
@@ -37,7 +37,7 @@ class Look4SatActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navHost = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
binding.navBottom.setupWithNavController(navHost.navController)
val navHost = supportFragmentManager.findFragmentById(R.id.main_nav_host) as NavHostFragment
binding.mainNavBottom.setupWithNavController(navHost.navController)
}
}
@@ -15,17 +15,17 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satItemScreen
package com.rtbishop.look4sat.presentation.entriesScreen
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.databinding.SatItemBinding
import com.rtbishop.look4sat.data.SatItem
import com.rtbishop.look4sat.databinding.ItemEntryBinding
class SatItemAdapter : RecyclerView.Adapter<SatItemAdapter.SatItemHolder>() {
class EntriesAdapter : RecyclerView.Adapter<EntriesAdapter.SatItemHolder>() {
private val diffCallback = object : DiffUtil.ItemCallback<SatItem>() {
override fun areItemsTheSame(oldItem: SatItem, newItem: SatItem): Boolean {
@@ -61,12 +61,12 @@ class SatItemAdapter : RecyclerView.Adapter<SatItemAdapter.SatItemHolder>() {
holder.bind(differ.currentList[position], clickListener)
}
class SatItemHolder private constructor(private val binding: SatItemBinding) :
class SatItemHolder private constructor(private val binding: ItemEntryBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: SatItem, listener: EntriesClickListener) {
binding.satItemCheckbox.text = item.name
binding.satItemCheckbox.isChecked = item.isSelected
binding.entryCheckbox.text = item.name
binding.entryCheckbox.isChecked = item.isSelected
itemView.setOnClickListener {
listener.updateSelection(listOf(item.catNum), item.isSelected.not())
}
@@ -75,7 +75,7 @@ class SatItemAdapter : RecyclerView.Adapter<SatItemAdapter.SatItemHolder>() {
companion object {
fun from(parent: ViewGroup): SatItemHolder {
val inflater = LayoutInflater.from(parent.context)
return SatItemHolder(SatItemBinding.inflate(inflater, parent, false))
return SatItemHolder(ItemEntryBinding.inflate(inflater, parent, false))
}
}
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satItemScreen
package com.rtbishop.look4sat.presentation.entriesScreen
import android.os.Bundle
import android.view.View
@@ -27,8 +27,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
import com.rtbishop.look4sat.data.SatItem
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
import com.rtbishop.look4sat.framework.model.Result
import com.rtbishop.look4sat.utility.RecyclerDivider
import com.rtbishop.look4sat.utility.getNavResult
@@ -37,9 +37,9 @@ import com.rtbishop.look4sat.utility.showSnack
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class SatItemFragment : Fragment(R.layout.fragment_entries) {
class EntriesFragment : Fragment(R.layout.fragment_entries) {
private val viewModel: SatItemViewModel by viewModels()
private val viewModel: EntriesViewModel by viewModels()
private val contentContract = ActivityResultContracts.GetContent()
private val filePicker = registerForActivityResult(contentContract) { uri ->
uri?.let { viewModel.updateEntriesFromFile(uri) }
@@ -51,7 +51,7 @@ class SatItemFragment : Fragment(R.layout.fragment_entries) {
}
private fun setupComponents(view: View) {
val entriesAdapter = SatItemAdapter().apply {
val entriesAdapter = EntriesAdapter().apply {
setEntriesClickListener(viewModel)
}
val binding = FragmentEntriesBinding.bind(view).apply {
@@ -62,13 +62,13 @@ class SatItemFragment : Fragment(R.layout.fragment_entries) {
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_light))
}
importWeb.setOnClickListener {
entriesImportWeb.setOnClickListener {
findNavController().navigateSafe(R.id.action_entries_to_sources)
}
importFile.setOnClickListener { filePicker.launch("*/*") }
selectMode.setOnClickListener { showModesDialog() }
selectAll.setOnClickListener { viewModel.selectCurrentItems() }
searchBar.setOnQueryTextListener(viewModel)
entriesImportFile.setOnClickListener { filePicker.launch("*/*") }
entriesSelectMode.setOnClickListener { showModesDialog() }
entriesSelectAll.setOnClickListener { viewModel.selectCurrentItems() }
entriesSearchBar.setOnQueryTextListener(viewModel)
}
viewModel.satData.observe(viewLifecycleOwner, { satData ->
handleSatData(satData, binding, entriesAdapter)
@@ -81,11 +81,11 @@ class SatItemFragment : Fragment(R.layout.fragment_entries) {
private fun handleSatData(
result: Result<List<SatItem>>,
binding: FragmentEntriesBinding,
satItemAdapter: SatItemAdapter
entriesAdapter: EntriesAdapter
) {
when (result) {
is Result.Success -> {
satItemAdapter.submitList(result.data)
entriesAdapter.submitList(result.data)
binding.entriesProgress.visibility = View.INVISIBLE
binding.entriesRecycler.visibility = View.VISIBLE
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satItemScreen
package com.rtbishop.look4sat.presentation.entriesScreen
import android.content.ContentResolver
import android.net.Uri
@@ -32,11 +32,11 @@ import java.util.*
import javax.inject.Inject
@HiltViewModel
class SatItemViewModel @Inject constructor(
class EntriesViewModel @Inject constructor(
private val preferencesSource: PreferencesSource,
private val resolver: ContentResolver,
private val satelliteRepo: SatelliteRepo,
) : ViewModel(), SatItemAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
) : ViewModel(), EntriesAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
private val transModes = MutableLiveData(satelliteRepo.loadSelectedModes())
private val currentQuery = MutableLiveData(String())
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.appInfoScreen
package com.rtbishop.look4sat.presentation.infoScreen
import android.content.Intent
import android.net.Uri
@@ -27,20 +27,20 @@ import com.rtbishop.look4sat.BuildConfig
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentInfoBinding
class AppInfoFragment : Fragment(R.layout.fragment_info) {
class InfoFragment : Fragment(R.layout.fragment_info) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
FragmentInfoBinding.bind(view).apply {
infoVersion.text =
String.format(getString(R.string.info_version), BuildConfig.VERSION_NAME)
infoGithub.setOnClickListener {
infoBtnGithub.setOnClickListener {
gotoUrl("https://github.com/rt-bishop/Look4Sat/")
}
infoFdroid.setOnClickListener {
infoBtnFdroid.setOnClickListener {
gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/")
}
infoBmc.setOnClickListener {
infoBtnDonate.setOnClickListener {
gotoUrl("https://www.buymeacoffee.com/rtbishop")
}
val moveMethod = LinkMovementMethod.getInstance()
@@ -0,0 +1,32 @@
/*
* Look4Sat. Amateur radio satellite tracker and pass predictor.
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.mapScreen
import com.rtbishop.look4sat.domain.GeoPos
import com.rtbishop.look4sat.domain.Satellite
data class MapData(
val pass: Satellite,
val catNum: Int,
val name: String,
val range: Double,
val altitude: Double,
val velocity: Double,
val qthLoc: String,
val osmPos: GeoPos
)
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satMapScreen
package com.rtbishop.look4sat.presentation.mapScreen
import android.content.SharedPreferences
import android.graphics.Color
@@ -31,7 +31,6 @@ import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentMapBinding
import com.rtbishop.look4sat.domain.GeoPos
import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.data.SatData
import dagger.hilt.android.AndroidEntryPoint
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
@@ -44,12 +43,12 @@ import java.util.*
import javax.inject.Inject
@AndroidEntryPoint
class SatMapFragment : Fragment(R.layout.fragment_map) {
class MapFragment : Fragment(R.layout.fragment_map) {
@Inject
lateinit var sharedPreferences: SharedPreferences
private val viewModel: SatMapViewModel by viewModels()
private val viewModel: MapViewModel by viewModels()
private val minLat = MapView.getTileSystem().minLatitude
private val maxLat = MapView.getTileSystem().maxLatitude
private val trackPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
@@ -83,8 +82,8 @@ class SatMapFragment : Fragment(R.layout.fragment_map) {
overlays.addAll(Array(4) { FolderOverlay() })
}
}
binding.fabPrev.setOnClickListener { viewModel.scrollSelection(true) }
binding.fabNext.setOnClickListener { viewModel.scrollSelection(false) }
binding.mapBtnPrev.setOnClickListener { viewModel.scrollSelection(true) }
binding.mapBtnNext.setOnClickListener { viewModel.scrollSelection(false) }
setupObservers(binding)
}
@@ -93,7 +92,7 @@ class SatMapFragment : Fragment(R.layout.fragment_map) {
viewModel.satPositions.observe(viewLifecycleOwner, { renderSatPositions(it, binding) })
viewModel.satTrack.observe(viewLifecycleOwner, { renderSatTrack(it, binding) })
viewModel.satFootprint.observe(viewLifecycleOwner, { renderSatFootprint(it, binding) })
viewModel.satData.observe(viewLifecycleOwner, { renderSatData(it, binding) })
viewModel.mapData.observe(viewLifecycleOwner, { renderSatData(it, binding) })
}
private fun renderStationPos(stationPos: GeoPos, binding: FragmentMapBinding) {
@@ -183,16 +182,18 @@ class SatMapFragment : Fragment(R.layout.fragment_map) {
binding.mapView.overlays[2] = footprintOverlay
}
private fun renderSatData(satData: SatData, binding: FragmentMapBinding) {
private fun renderSatData(mapData: MapData, binding: FragmentMapBinding) {
binding.apply {
idName.text =
String.format(getString(R.string.pat_osm_idName), satData.catNum, satData.name)
qthLocator.text = String.format(getString(R.string.map_qth), satData.qthLoc)
altitude.text = String.format(getString(R.string.pat_altitude), satData.altitude)
distance.text = String.format(getString(R.string.pat_distance), satData.range)
velocity.text = String.format(getString(R.string.pat_osm_vel), satData.velocity)
mapLat.text = String.format(getString(R.string.pat_osm_lat), satData.osmPos.latitude)
mapLon.text = String.format(getString(R.string.pat_osm_lon), satData.osmPos.longitude)
mapDataName.text =
String.format(getString(R.string.pat_osm_idName), mapData.catNum, mapData.name)
mapDataQth.text = String.format(getString(R.string.map_qth), mapData.qthLoc)
mapDataAlt.text = String.format(getString(R.string.pat_altitude), mapData.altitude)
mapDataDst.text = String.format(getString(R.string.pat_distance), mapData.range)
mapDataVel.text = String.format(getString(R.string.pat_osm_vel), mapData.velocity)
mapDataLat.text =
String.format(getString(R.string.pat_osm_lat), mapData.osmPos.latitude)
mapDataLon.text =
String.format(getString(R.string.pat_osm_lon), mapData.osmPos.longitude)
}
binding.mapView.invalidate()
}
@@ -15,12 +15,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satMapScreen
package com.rtbishop.look4sat.presentation.mapScreen
import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.Predictor
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatData
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.domain.*
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -31,7 +30,7 @@ import kotlin.math.max
import kotlin.math.min
@HiltViewModel
class SatMapViewModel @Inject constructor(
class MapViewModel @Inject constructor(
private val satelliteRepo: SatelliteRepo,
private val predictor: Predictor,
private val preferences: PreferencesSource,
@@ -54,8 +53,8 @@ class SatMapViewModel @Inject constructor(
private val _satFootprint = MutableLiveData<List<GeoPos>>()
val satFootprint: LiveData<List<GeoPos>> = _satFootprint
private val _satData = MutableLiveData<SatData>()
val satData: LiveData<SatData> = this._satData
private val _satData = MutableLiveData<MapData>()
val mapData: LiveData<MapData> = this._satData
private val _satPositions = MutableLiveData<Map<Satellite, GeoPos>>()
val satPositions: LiveData<Map<Satellite, GeoPos>> = _satPositions
@@ -162,7 +161,7 @@ class SatMapViewModel @Inject constructor(
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
val osmPos = GeoPos(osmLat, osmLon)
val qthLoc = QthConverter.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
val satData = SatData(
val satData = MapData(
satellite, satellite.params.catnum, satellite.params.name, satPos.range,
satPos.altitude, satPos.getOrbitalVelocity(), qthLoc, osmPos
)
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satPassScreen
package com.rtbishop.look4sat.presentation.passesScreen
import android.view.LayoutInflater
import android.view.ViewGroup
@@ -29,7 +29,7 @@ import com.rtbishop.look4sat.domain.SatPass
import java.text.SimpleDateFormat
import java.util.*
class SatPassAdapter(private val isUTC: Boolean, private val clickListener: PassesClickListener) :
class PassesAdapter(private val isUTC: Boolean, private val clickListener: PassesClickListener) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val diffCallback = object : DiffUtil.ItemCallback<SatPass>() {
@@ -94,13 +94,13 @@ class SatPassAdapter(private val isUTC: Boolean, private val clickListener: Pass
startFormat.timeZone = timeZoneUTC
endFormat.timeZone = timeZoneUTC
}
passLeoSatName.text = satPass.name
passLeoSatId.text = String.format(satIdFormat, satPass.catNum)
passLeoAosAz.text = String.format(aosAzFormat, satPass.aosAzimuth)
passLeoMaxEl.text = String.format(maxElFormat, satPass.maxElevation)
passLeoLosAz.text = String.format(losAzFormat, satPass.losAzimuth)
passLeoName.text = satPass.name
passLeoId.text = String.format(satIdFormat, satPass.catNum)
passLeoAos.text = String.format(aosAzFormat, satPass.aosAzimuth)
passLeoElev.text = String.format(maxElFormat, satPass.maxElevation)
passLeoLos.text = String.format(losAzFormat, satPass.losAzimuth)
passLeoStart.text = startFormat.format(Date(satPass.aosTime))
passLeoTcaAz.text = String.format(tcaAzFormat, satPass.tcaAzimuth)
passLeoTca.text = String.format(tcaAzFormat, satPass.tcaAzimuth)
passLeoEnd.text = endFormat.format(Date(satPass.losTime))
passLeoProgress.progress = satPass.progress
}
@@ -128,8 +128,8 @@ class SatPassAdapter(private val isUTC: Boolean, private val clickListener: Pass
fun bind(satPass: SatPass, listener: PassesClickListener) {
binding.apply {
passGeoSatName.text = satPass.name
passGeoSatId.text = String.format(satIdFormat, satPass.catNum)
passGeoName.text = satPass.name
passGeoId.text = String.format(satIdFormat, satPass.catNum)
passGeoAz.text = String.format(azFormat, satPass.tcaAzimuth)
passGeoAlt.text = String.format(altFormat, satPass.altitude)
passGeoEl.text = String.format(elevFormat, satPass.maxElevation)
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satPassScreen
package com.rtbishop.look4sat.presentation.passesScreen
import android.Manifest
import android.os.Bundle
@@ -38,12 +38,12 @@ import dagger.hilt.android.AndroidEntryPoint
import java.util.*
@AndroidEntryPoint
class SatPassFragment : Fragment(R.layout.fragment_passes), SatPassAdapter.PassesClickListener {
class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesClickListener {
private val viewModel: SatPassViewModel by viewModels()
private val passesViewModel: PassesViewModel by viewModels()
private val permRequest = ActivityResultContracts.RequestPermission()
private val permRequestLauncher = registerForActivityResult(permRequest) {
viewModel.triggerInitialSetup()
passesViewModel.triggerInitialSetup()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -52,7 +52,7 @@ class SatPassFragment : Fragment(R.layout.fragment_passes), SatPassAdapter.Passe
}
private fun setupComponents(view: View) {
val passesAdapter = SatPassAdapter(viewModel.shouldUseUTC(), this)
val passesAdapter = PassesAdapter(passesViewModel.shouldUseUTC(), this)
val binding = FragmentPassesBinding.bind(view).apply {
passesRecycler.apply {
setHasFixedSize(true)
@@ -62,24 +62,24 @@ class SatPassFragment : Fragment(R.layout.fragment_passes), SatPassAdapter.Passe
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark))
}
passesRefresh.setOnClickListener { viewModel.forceCalculation() }
passesRefresh.setOnClickListener { passesViewModel.forceCalculation() }
}
viewModel.passes.observe(viewLifecycleOwner, { passesResult ->
passesViewModel.passes.observe(viewLifecycleOwner, { passesResult ->
handleNewPasses(passesResult, passesAdapter, binding)
})
viewModel.isFirstLaunchDone.observe(viewLifecycleOwner, { setupDone ->
passesViewModel.isFirstLaunchDone.observe(viewLifecycleOwner, { setupDone ->
if (!setupDone) permRequestLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
})
}
private fun handleNewPasses(
result: Result<List<SatPass>>,
satPassAdapter: SatPassAdapter,
passesAdapter: PassesAdapter,
binding: FragmentPassesBinding
) {
when (result) {
is Result.Success -> {
satPassAdapter.submitList(result.data)
passesAdapter.submitList(result.data)
binding.apply {
passesError.visibility = View.INVISIBLE
passesProgress.visibility = View.INVISIBLE
@@ -126,7 +126,7 @@ class SatPassFragment : Fragment(R.layout.fragment_passes), SatPassAdapter.Passe
override fun navigateToPass(satPass: SatPass) {
if (satPass.progress < 100) {
val bundle = bundleOf("catNum" to satPass.catNum, "aosTime" to satPass.aosTime)
findNavController().navigateSafe(R.id.action_passes_to_polar, bundle)
findNavController().navigateSafe(R.id.action_passes_to_radar, bundle)
}
}
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satPassScreen
package com.rtbishop.look4sat.presentation.passesScreen
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
@@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.collect
import javax.inject.Inject
@HiltViewModel
class SatPassViewModel @Inject constructor(
class PassesViewModel @Inject constructor(
private val satelliteRepo: SatelliteRepo,
private val predictor: Predictor,
private val preferencesSource: PreferencesSource
@@ -0,0 +1,5 @@
package com.rtbishop.look4sat.presentation.radarScreen
import com.rtbishop.look4sat.domain.SatPos
data class RadarData(val satPos: SatPos, val satTrack: List<SatPos> = emptyList())
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satPassInfoScreen
package com.rtbishop.look4sat.presentation.radarScreen
import android.os.Bundle
import android.view.View
@@ -26,7 +26,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.databinding.FragmentPolarBinding
import com.rtbishop.look4sat.databinding.FragmentRadarBinding
import com.rtbishop.look4sat.domain.SatPass
import com.rtbishop.look4sat.domain.SatPos
import com.rtbishop.look4sat.utility.RecyclerDivider
@@ -36,18 +36,18 @@ import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class PassInfoFragment : Fragment(R.layout.fragment_polar) {
class RadarFragment : Fragment(R.layout.fragment_radar) {
@Inject
lateinit var preferences: PreferencesSource
private val viewModel: PassInfoViewModel by viewModels()
private var passInfoView: PassInfoView? = null
private val viewModel: RadarViewModel by viewModels()
private var radarView: RadarView? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
FragmentPolarBinding.bind(view).apply {
val transAdapter = SatTransAdapter()
recycler.apply {
FragmentRadarBinding.bind(view).apply {
val transAdapter = TransmittersAdapter()
radarRecycler.apply {
setHasFixedSize(true)
adapter = transAdapter
isVerticalScrollBarEnabled = false
@@ -69,33 +69,36 @@ class PassInfoFragment : Fragment(R.layout.fragment_polar) {
viewModel.disableSensor()
}
private fun setupObservers(transAdapter: SatTransAdapter, binding: FragmentPolarBinding) {
private fun setupObservers(
transmittersAdapter: TransmittersAdapter,
binding: FragmentRadarBinding
) {
val catNum = requireArguments().getInt("catNum")
val aosTime = requireArguments().getLong("aosTime")
viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
passInfoView = PassInfoView(requireContext()).apply {
radarView = RadarView(requireContext()).apply {
setShowAim(preferences.shouldUseCompass())
setScanning(preferences.shouldShowSweep())
}
binding.frame.addView(passInfoView)
viewModel.passData.observe(viewLifecycleOwner, { passData ->
passInfoView?.setPosition(passData.position)
passInfoView?.setPositions(passData.positions)
setPassText(pass, passData.position, binding)
binding.radarFrame.addView(radarView)
viewModel.radarData.observe(viewLifecycleOwner, { passData ->
radarView?.setPosition(passData.satPos)
radarView?.setPositions(passData.satTrack)
setPassText(pass, passData.satPos, binding)
})
viewModel.transmitters.observe(viewLifecycleOwner, { list ->
if (list.isNotEmpty()) {
transAdapter.submitList(list)
binding.recycler.visibility = View.VISIBLE
binding.noTransMsg.visibility = View.INVISIBLE
transmittersAdapter.submitList(list)
binding.radarRecycler.visibility = View.VISIBLE
binding.radarRecyclerMsg.visibility = View.INVISIBLE
} else {
binding.recycler.visibility = View.INVISIBLE
binding.noTransMsg.visibility = View.VISIBLE
binding.radarRecycler.visibility = View.INVISIBLE
binding.radarRecyclerMsg.visibility = View.VISIBLE
}
passInfoView?.invalidate()
radarView?.invalidate()
})
viewModel.orientation.observe(viewLifecycleOwner, { orientation ->
passInfoView?.setOrientation(
radarView?.setOrientation(
orientation.first,
orientation.second,
orientation.third
@@ -104,32 +107,32 @@ class PassInfoFragment : Fragment(R.layout.fragment_polar) {
}
}
private fun setPassText(satPass: SatPass, satPos: SatPos, binding: FragmentPolarBinding) {
private fun setPassText(satPass: SatPass, satPos: SatPos, binding: FragmentRadarBinding) {
val timeNow = System.currentTimeMillis()
val polarAz = getString(R.string.pat_azimuth)
val polarEl = getString(R.string.pat_elevation)
val polarRng = getString(R.string.pat_distance)
val polarAlt = getString(R.string.pat_altitude)
binding.azimuth.text = String.format(polarAz, Math.toDegrees(satPos.azimuth))
binding.elevation.text = String.format(polarEl, Math.toDegrees(satPos.elevation))
binding.distance.text = String.format(polarRng, satPos.range)
binding.altitude.text = String.format(polarAlt, satPos.altitude)
binding.satName.text = satPass.name
binding.radarAz.text = String.format(polarAz, Math.toDegrees(satPos.azimuth))
binding.radarEl.text = String.format(polarEl, Math.toDegrees(satPos.elevation))
binding.radarDst.text = String.format(polarRng, satPos.range)
binding.radarAlt.text = String.format(polarAlt, satPos.altitude)
binding.radarName.text = satPass.name
if (!satPass.isDeepSpace) {
if (timeNow < satPass.aosTime) {
val millisBeforeStart = satPass.aosTime.minus(timeNow)
binding.polarTimer.text = millisBeforeStart.toTimerString()
binding.radarTimer.text = millisBeforeStart.toTimerString()
} else {
val millisBeforeEnd = satPass.losTime.minus(timeNow)
binding.polarTimer.text = millisBeforeEnd.toTimerString()
binding.radarTimer.text = millisBeforeEnd.toTimerString()
if (timeNow > satPass.losTime) {
binding.polarTimer.text = 0L.toTimerString()
findNavController().navigateSafe(R.id.action_polar_to_passes)
binding.radarTimer.text = 0L.toTimerString()
findNavController().navigateSafe(R.id.action_radar_to_passes)
}
}
} else {
binding.polarTimer.text = 0L.toTimerString()
binding.radarTimer.text = 0L.toTimerString()
}
}
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satPassInfoScreen
package com.rtbishop.look4sat.presentation.radarScreen
import android.content.Context
import android.graphics.*
@@ -27,7 +27,7 @@ import kotlin.math.cos
import kotlin.math.min
import kotlin.math.sin
class PassInfoView(context: Context) : View(context) {
class RadarView(context: Context) : View(context) {
private val defaultColor = ContextCompat.getColor(context, R.color.themeLight)
private val scale = resources.displayMetrics.density
@@ -15,11 +15,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satPassInfoScreen
package com.rtbishop.look4sat.presentation.radarScreen
import androidx.lifecycle.*
import androidx.navigation.fragment.findNavController
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.domain.Predictor
@@ -28,9 +26,7 @@ import com.rtbishop.look4sat.domain.SatPos
import com.rtbishop.look4sat.domain.Transmitter
import com.rtbishop.look4sat.framework.OrientationProvider
import com.rtbishop.look4sat.injection.IoDispatcher
import com.rtbishop.look4sat.utility.navigateSafe
import com.rtbishop.look4sat.utility.round
import com.rtbishop.look4sat.utility.toTimerString
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect
@@ -40,7 +36,7 @@ import java.util.*
import javax.inject.Inject
@HiltViewModel
class PassInfoViewModel @Inject constructor(
class RadarViewModel @Inject constructor(
private val orientationProvider: OrientationProvider,
private val preferences: PreferencesSource,
private val predictor: Predictor,
@@ -49,10 +45,10 @@ class PassInfoViewModel @Inject constructor(
) : ViewModel(), OrientationProvider.OrientationListener {
private val stationPos = preferences.loadStationPosition()
private val _passData = MutableLiveData<PassData>()
private val _passData = MutableLiveData<RadarData>()
private val _transmitters = MutableLiveData<List<Transmitter>>()
private val _orientation = MutableLiveData<Triple<Float, Float, Float>>()
val passData: LiveData<PassData> = _passData
val radarData: LiveData<RadarData> = _passData
val transmitters: LiveData<List<Transmitter>> = _transmitters
val orientation: LiveData<Triple<Float, Float, Float>> = _orientation
@@ -90,7 +86,7 @@ class PassInfoViewModel @Inject constructor(
}
while (isActive) {
val pos = predictor.getSatPos(satPass.satellite, stationPos, Date())
_passData.postValue(PassData(pos, track))
_passData.postValue(RadarData(pos, track))
delay(1000)
}
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satPassInfoScreen
package com.rtbishop.look4sat.presentation.radarScreen
import android.view.LayoutInflater
import android.view.ViewGroup
@@ -27,7 +27,7 @@ import com.rtbishop.look4sat.databinding.ItemTransBinding
import com.rtbishop.look4sat.domain.Transmitter
import java.util.*
class SatTransAdapter : RecyclerView.Adapter<SatTransAdapter.TransHolder>() {
class TransmittersAdapter : RecyclerView.Adapter<TransmittersAdapter.TransHolder>() {
private val diffCallback = object : DiffUtil.ItemCallback<Transmitter>() {
override fun areItemsTheSame(oldItem: Transmitter, newItem: Transmitter): Boolean {
@@ -66,27 +66,38 @@ class SatTransAdapter : RecyclerView.Adapter<SatTransAdapter.TransHolder>() {
private val isInverted = itemView.context.getString(R.string.trans_inverted)
fun bind(transmitter: Transmitter) {
binding.description.text = transmitter.info
binding.transDesc.text = transmitter.info
transmitter.downlink.let { downlink ->
if (downlink != null) {
val downlinkFreq = downlink / divider
binding.downlink.text = String.format(Locale.ENGLISH, formatLink, downlinkFreq)
} else binding.downlink.text = formatLinkNull
binding.transDownlink.text =
String.format(Locale.ENGLISH, formatLink, downlinkFreq)
} else {
binding.transDownlink.text = formatLinkNull
}
}
transmitter.uplink.let { uplink ->
if (uplink != null) {
val uplinkFreq = uplink / divider
binding.uplink.text = String.format(Locale.ENGLISH, formatLink, uplinkFreq)
} else binding.uplink.text = formatLinkNull
binding.transUplink.text = String.format(Locale.ENGLISH, formatLink, uplinkFreq)
} else {
binding.transUplink.text = formatLinkNull
}
}
if (transmitter.mode != null) binding.mode.text = String.format(mode, transmitter.mode)
else binding.mode.text = String.format(mode, strNo)
if (transmitter.mode != null) {
binding.transMode.text = String.format(mode, transmitter.mode)
} else {
binding.transMode.text = String.format(mode, strNo)
}
if (transmitter.isInverted) binding.isInverted.text = String.format(isInverted, strYes)
else binding.isInverted.text = String.format(isInverted, strNo)
if (transmitter.isInverted) {
binding.transInverted.text = String.format(isInverted, strYes)
} else {
binding.transInverted.text = String.format(isInverted, strNo)
}
}
companion object {
@@ -1,5 +0,0 @@
package com.rtbishop.look4sat.presentation.satPassInfoScreen
import com.rtbishop.look4sat.domain.SatPos
data class PassData(val position: SatPos, val positions: List<SatPos> = emptyList())
@@ -15,13 +15,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.appSettingsScreen
package com.rtbishop.look4sat.presentation.settingsScreen
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.text.InputType
import android.util.Patterns
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
@@ -36,7 +35,7 @@ import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class AppSettingsFragment : PreferenceFragmentCompat() {
class SettingsFragment : PreferenceFragmentCompat() {
@Inject
lateinit var preferencesSource: PreferencesSource
@@ -72,7 +71,8 @@ class AppSettingsFragment : PreferenceFragmentCompat() {
findPreference<EditTextPreference>(PreferencesProvider.keyRotatorAddress)?.apply {
setOnPreferenceChangeListener { _, newValue ->
if (Patterns.IP_ADDRESS.matcher(newValue.toString()).matches()) {
val ip4 = "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!\$)|\$)){4}\$"
if (newValue.toString().matches(ip4.toRegex())) {
return@setOnPreferenceChangeListener true
} else {
showSnack(getString(R.string.tracking_rotator_address_invalid))
@@ -119,7 +119,7 @@ class AppSettingsFragment : PreferenceFragmentCompat() {
private fun showSnack(message: String) {
Snackbar.make(requireView(), message, Snackbar.LENGTH_SHORT).apply {
setAnchorView(R.id.nav_bottom)
setAnchorView(R.id.main_nav_bottom)
}.show()
}
}
@@ -15,6 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satSourcesScreen
package com.rtbishop.look4sat.presentation.sourcesScreen
class TleSource(var url: String = String())
class DataSource(var url: String = String())
@@ -15,33 +15,33 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satSourcesScreen
package com.rtbishop.look4sat.presentation.sourcesScreen
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.databinding.ItemTleSourceBinding
import com.rtbishop.look4sat.databinding.ItemSourceBinding
class SourcesAdapter(private val sources: MutableList<TleSource> = mutableListOf()) :
class SourcesAdapter(private val sources: MutableList<DataSource> = mutableListOf()) :
RecyclerView.Adapter<SourcesAdapter.TleSourceHolder>() {
fun getSources(): List<TleSource> {
fun getSources(): List<DataSource> {
return sources.filter { it.url.contains("https://") }
}
fun setSources(list: List<TleSource>) {
fun setSources(list: List<DataSource>) {
sources.clear()
sources.addAll(list)
}
fun addSource() {
sources.add(TleSource())
sources.add(DataSource())
notifyItemInserted(itemCount - 1)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TleSourceHolder {
val binding = ItemTleSourceBinding
val binding = ItemSourceBinding
.inflate(LayoutInflater.from(parent.context), parent, false)
return TleSourceHolder(binding)
}
@@ -54,13 +54,13 @@ class SourcesAdapter(private val sources: MutableList<TleSource> = mutableListOf
return sources.size
}
inner class TleSourceHolder(private val binding: ItemTleSourceBinding) :
inner class TleSourceHolder(private val binding: ItemSourceBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(source: TleSource) {
binding.tleSourceUrl.setText(source.url)
binding.tleSourceUrl.doOnTextChanged { text, _, _, _ -> source.url = text.toString() }
binding.tleSourceInputLayout.setEndIconOnClickListener {
fun bind(source: DataSource) {
binding.sourceUrl.setText(source.url)
binding.sourceUrl.doOnTextChanged { text, _, _, _ -> source.url = text.toString() }
binding.sourceInput.setEndIconOnClickListener {
sources.remove(source)
notifyItemRemoved(adapterPosition)
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.satSourcesScreen
package com.rtbishop.look4sat.presentation.sourcesScreen
import android.os.Bundle
import android.view.LayoutInflater
@@ -43,7 +43,7 @@ class SourcesDialog : AppCompatDialogFragment() {
override fun onViewCreated(view: View, state: Bundle?) {
super.onViewCreated(view, state)
val sources = prefsManager.loadTleSources().map { TleSource(it) }
val sources = prefsManager.loadTleSources().map { DataSource(it) }
val sourcesAdapter = SourcesAdapter().apply { setSources(sources) }
DialogSourcesBinding.bind(view).apply {
dialog?.window?.setLayout(
@@ -54,7 +54,7 @@ class SourcesDialog : AppCompatDialogFragment() {
adapter = sourcesAdapter
layoutManager = LinearLayoutManager(requireContext())
}
sourceBtnAdd.setOnClickListener {
sourcesBtnAdd.setOnClickListener {
sourcesAdapter.addSource()
}
sourcesBtnPos.setOnClickListener {
@@ -43,7 +43,7 @@ import java.util.regex.Pattern
fun View.showSnack(message: String, isAnchored: Boolean = true) {
Snackbar.make(this, message, Snackbar.LENGTH_SHORT).apply {
if (isAnchored) setAnchorView(R.id.nav_bottom)
if (isAnchored) setAnchorView(R.id.main_nav_bottom)
}.show()
}