From cb4eea7b5d1c316d5602b8b19c8c57fa5e2a9244 Mon Sep 17 00:00:00 2001 From: Kyle Corry Date: Mon, 4 Sep 2023 09:02:07 -0400 Subject: [PATCH] Use map layer management for radar compass --- .../navigation/ui/NavigatorFragment.kt | 131 ++++++------------ .../layers/MultiLayerManager.kt | 6 + .../infrastructure/layers/PathLayerManager.kt | 1 + 3 files changed, 49 insertions(+), 89 deletions(-) diff --git a/app/src/main/java/com/kylecorry/trail_sense/navigation/ui/NavigatorFragment.kt b/app/src/main/java/com/kylecorry/trail_sense/navigation/ui/NavigatorFragment.kt index 4e3bcb17d..68ef2f058 100644 --- a/app/src/main/java/com/kylecorry/trail_sense/navigation/ui/NavigatorFragment.kt +++ b/app/src/main/java/com/kylecorry/trail_sense/navigation/ui/NavigatorFragment.kt @@ -50,12 +50,7 @@ import com.kylecorry.trail_sense.navigation.infrastructure.Navigator import com.kylecorry.trail_sense.navigation.infrastructure.share.LocationCopy import com.kylecorry.trail_sense.navigation.infrastructure.share.LocationGeoSender import com.kylecorry.trail_sense.navigation.infrastructure.share.LocationSharesheet -import com.kylecorry.trail_sense.navigation.paths.domain.Path -import com.kylecorry.trail_sense.navigation.paths.infrastructure.PathLoader -import com.kylecorry.trail_sense.navigation.paths.infrastructure.persistence.PathService -import com.kylecorry.trail_sense.navigation.paths.ui.asMappable import com.kylecorry.trail_sense.navigation.ui.data.UpdateAstronomyLayerCommand -import com.kylecorry.trail_sense.navigation.ui.data.UpdateTideLayerCommand import com.kylecorry.trail_sense.navigation.ui.errors.NavigatorUserErrors import com.kylecorry.trail_sense.navigation.ui.layers.* import com.kylecorry.trail_sense.navigation.ui.layers.compass.BeaconCompassLayer @@ -73,8 +68,12 @@ import com.kylecorry.trail_sense.shared.permissions.alertNoCameraPermission import com.kylecorry.trail_sense.shared.permissions.requestCamera import com.kylecorry.trail_sense.shared.preferences.PreferencesSubsystem import com.kylecorry.trail_sense.shared.sensors.SensorService -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import com.kylecorry.trail_sense.tools.maps.infrastructure.layers.ILayerManager +import com.kylecorry.trail_sense.tools.maps.infrastructure.layers.MultiLayerManager +import com.kylecorry.trail_sense.tools.maps.infrastructure.layers.MyAccuracyLayerManager +import com.kylecorry.trail_sense.tools.maps.infrastructure.layers.MyLocationLayerManager +import com.kylecorry.trail_sense.tools.maps.infrastructure.layers.PathLayerManager +import com.kylecorry.trail_sense.tools.maps.infrastructure.layers.TideLayerManager import java.time.Duration import java.time.Instant import java.util.* @@ -102,7 +101,6 @@ class NavigatorFragment : BoundFragment() { private lateinit var navController: NavController private val beaconRepo by lazy { BeaconRepo.getInstance(requireContext()) } - private val pathService by lazy { PathService.getInstance(requireContext()) } private val sensorService by lazy { SensorService(requireContext()) } private val cache by lazy { PreferencesSubsystem.getInstance(requireContext()).preferences } @@ -111,7 +109,6 @@ class NavigatorFragment : BoundFragment() { private val formatService by lazy { FormatService.getInstance(requireContext()) } private var beacons: Collection = listOf() - private var paths: List = emptyList() private var nearbyBeacons: List = listOf() private var destination: Beacon? = null @@ -135,12 +132,6 @@ class NavigatorFragment : BoundFragment() { private lateinit var diagnostics: List // Data commands - private val updateTideLayerCommand by lazy { - UpdateTideLayerCommand( - requireContext(), - tideLayer - ) - } private val updateAstronomyLayerCommand by lazy { UpdateAstronomyLayerCommand( astronomyCompassLayer, @@ -154,9 +145,6 @@ class NavigatorFragment : BoundFragment() { private var lastOrientation: DeviceOrientation.Orientation? = null - private val pathLoader by lazy { PathLoader(pathService) } - - private val loadPathRunner = CoroutineQueueRunner() private val loadBeaconsRunner = CoroutineQueueRunner() private val pathLayer = PathLayer() @@ -164,6 +152,7 @@ class NavigatorFragment : BoundFragment() { private val myLocationLayer = MyLocationLayer() private val myAccuracyLayer = MyAccuracyLayer() private val tideLayer = TideLayer() + private var layerManager: ILayerManager? = null // Compass layers private val beaconCompassLayer = BeaconCompassLayer() @@ -179,6 +168,7 @@ class NavigatorFragment : BoundFragment() { private val nearbyCount by lazy { userPrefs.navigation.numberOfVisibleBeacons } private val nearbyDistance get() = userPrefs.navigation.maxBeaconDistance + private var lastNearbyDistance: Float? = null private val useRadarCompass by lazy { userPrefs.navigation.useRadarCompass } private val lockScreenPresence by lazy { userPrefs.navigation.lockScreenPresence } private val styleChooser by lazy { CompassStyleChooser(userPrefs.navigation, hasCompass) } @@ -194,7 +184,6 @@ class NavigatorFragment : BoundFragment() { } } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val beaconId = arguments?.getLong("destination") ?: 0L @@ -239,7 +228,6 @@ class NavigatorFragment : BoundFragment() { // Initialize layers beaconLayer.setOutlineColor(Resources.color(requireContext(), R.color.colorSecondary)) - myAccuracyLayer.setColors(AppColor.Orange.color, Color.TRANSPARENT, 25) binding.radarCompass.setLayers( listOf( pathLayer, @@ -288,16 +276,9 @@ class NavigatorFragment : BoundFragment() { updateNearbyBeacons() } - observeFlow(pathService.getPaths()) { - onIO { - paths = it.filter { path -> path.style.visible } - updateCompassPaths(true) - } - } - navController = findNavController() - observe(compass) { } + observe(compass) {} observe(orientation) { onOrientationUpdate() } observe(altimeter) { } observe(gps) { onLocationUpdate() } @@ -480,7 +461,6 @@ class NavigatorFragment : BoundFragment() { return@inBackground } - updateTideLayerCommand.execute() updateAstronomyLayerCommand.execute() astronomyDataLoaded = true } @@ -490,6 +470,21 @@ class NavigatorFragment : BoundFragment() { super.onResume() lastOrientation = null + layerManager = MultiLayerManager( + listOf( + PathLayerManager(requireContext(), pathLayer), + MyAccuracyLayerManager(myAccuracyLayer, AppColor.Orange.color, 25), + MyLocationLayerManager(myLocationLayer, Color.WHITE), + TideLayerManager(requireContext(), tideLayer) + ) + ) + if (useRadarCompass) { + layerManager?.start() + } + + // Populate the last known location + layerManager?.onLocationChanged(gps.location, gps.horizontalAccuracy) + // Resume navigation inBackground { destination = navigator.getDestination() @@ -513,10 +508,11 @@ class NavigatorFragment : BoundFragment() { override fun onPause() { super.onPause() - loadPathRunner.cancel() loadBeaconsRunner.cancel() sightingCompass?.stop() errors.reset() + layerManager?.stop() + layerManager = null } private fun updateNearbyBeacons() { @@ -635,6 +631,8 @@ class NavigatorFragment : BoundFragment() { Distance.meters(altimeter.altitude).convertTo(baseDistanceUnits) ) + layerManager?.onBearingChanged(compass.bearing) + // Compass listOf( binding.roundCompass, @@ -646,11 +644,6 @@ class NavigatorFragment : BoundFragment() { it.compassCenter = gps.location } - // This gets set with the other compass layers as well, but also set it here to keep it up to date since this changes more often - myLocationLayer.setLocation(gps.location) - myLocationLayer.setAzimuth(compass.bearing) - myAccuracyLayer.setLocation(gps.location, gps.horizontalAccuracy) - // Location binding.navigationTitle.subtitle.text = formatService.formatLocation(gps.location) @@ -679,10 +672,6 @@ class NavigatorFragment : BoundFragment() { ) } - myLocationLayer.setAzimuth(compass.bearing) - myLocationLayer.setLocation(gps.location) - myAccuracyLayer.setLocation(gps.location, gps.horizontalAccuracy) - // Update beacon layers beaconLayer.setBeacons(nearbyBeacons) beaconCompassLayer.setBeacons(nearbyBeacons) @@ -700,48 +689,6 @@ class NavigatorFragment : BoundFragment() { } } - private fun updateCompassPaths(reload: Boolean = false) { - inBackground { - loadPathRunner.skipIfRunning { - - if (!useRadarCompass) { - return@skipIfRunning - } - - val mappablePaths = onIO { - val loadGeofence = Geofence( - gps.location, - Distance.meters(nearbyDistance + 10) - ) - val load = CoordinateBounds.from(loadGeofence) - - val unloadGeofence = - loadGeofence.copy(radius = Distance.meters(loadGeofence.radius.distance + 1000)) - val unload = CoordinateBounds.from(unloadGeofence) - - pathLoader.update(paths, load, unload, reload) - - val mappablePaths = - pathLoader.getPointsWithBacktrack(requireContext()).mapNotNull { - val path = - paths.firstOrNull { p -> p.id == it.key } ?: return@mapNotNull null - it.value.asMappable(requireContext(), path) - } - - mappablePaths - } - - withContext(Dispatchers.Main) { - if (isBound) { - pathLayer.setPaths(mappablePaths) - } - } - } - } - - - } - private fun getPosition(): Position { return Position( gps.location, @@ -796,6 +743,8 @@ class NavigatorFragment : BoundFragment() { } private fun onLocationUpdate() { + layerManager?.onLocationChanged(gps.location, gps.horizontalAccuracy) + updateNearbyBeacons() updateDeclination() @@ -803,8 +752,14 @@ class NavigatorFragment : BoundFragment() { updateAstronomyData() } - if (paths.any()) { - updateCompassPaths() + if (useRadarCompass && lastNearbyDistance != nearbyDistance) { + lastNearbyDistance = nearbyDistance + val loadGeofence = Geofence( + gps.location, + Distance.meters(nearbyDistance + 10) + ) + val bounds = CoordinateBounds.from(loadGeofence) + layerManager?.onBoundsChanged(bounds) } } @@ -824,7 +779,6 @@ class NavigatorFragment : BoundFragment() { } } - private fun updateNavigationButton() { if (destination != null) { binding.beaconBtn.setImageResource(R.drawable.ic_cancel) @@ -839,11 +793,6 @@ class NavigatorFragment : BoundFragment() { updateNavigationButton() } - companion object { - const val LAST_DEST_BEARING = "last_dest_bearing" - const val CACHE_CAMERA_ZOOM = "sighting_compass_camera_zoom" - } - override fun generateBinding( layoutInflater: LayoutInflater, container: ViewGroup? @@ -851,4 +800,8 @@ class NavigatorFragment : BoundFragment() { return ActivityNavigatorBinding.inflate(layoutInflater, container, false) } + companion object { + const val LAST_DEST_BEARING = "last_dest_bearing" + const val CACHE_CAMERA_ZOOM = "sighting_compass_camera_zoom" + } } diff --git a/app/src/main/java/com/kylecorry/trail_sense/tools/maps/infrastructure/layers/MultiLayerManager.kt b/app/src/main/java/com/kylecorry/trail_sense/tools/maps/infrastructure/layers/MultiLayerManager.kt index eba0128b0..c45f3018b 100644 --- a/app/src/main/java/com/kylecorry/trail_sense/tools/maps/infrastructure/layers/MultiLayerManager.kt +++ b/app/src/main/java/com/kylecorry/trail_sense/tools/maps/infrastructure/layers/MultiLayerManager.kt @@ -6,6 +6,8 @@ import com.kylecorry.sol.units.Coordinate class MultiLayerManager(private val managers: List) : ILayerManager { + private var lastBounds: CoordinateBounds? = null + override fun start() { managers.forEach { it.start() } } @@ -15,6 +17,10 @@ class MultiLayerManager(private val managers: List) : ILayerManag } override fun onBoundsChanged(bounds: CoordinateBounds?) { + if (bounds == lastBounds) { + return + } + lastBounds = bounds managers.forEach { it.onBoundsChanged(bounds) } diff --git a/app/src/main/java/com/kylecorry/trail_sense/tools/maps/infrastructure/layers/PathLayerManager.kt b/app/src/main/java/com/kylecorry/trail_sense/tools/maps/infrastructure/layers/PathLayerManager.kt index 2d0d359ba..700c6b4f0 100644 --- a/app/src/main/java/com/kylecorry/trail_sense/tools/maps/infrastructure/layers/PathLayerManager.kt +++ b/app/src/main/java/com/kylecorry/trail_sense/tools/maps/infrastructure/layers/PathLayerManager.kt @@ -68,6 +68,7 @@ class PathLayerManager(private val context: Context, private val layer: PathLaye private suspend fun loadPaths(reload: Boolean) = onDefault { if (reload || !loaded) { val bounds = bounds ?: return@onDefault + // TODO: Make unload bounds larger than load bounds pathLoader.update(paths, bounds, bounds, true) loaded = true }