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 5c3226649..840b04066 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 @@ -66,6 +66,7 @@ import com.kylecorry.trail_sense.shared.Position import com.kylecorry.trail_sense.shared.QuickActionType import com.kylecorry.trail_sense.shared.UserPreferences import com.kylecorry.trail_sense.shared.colors.AppColor +import com.kylecorry.trail_sense.shared.data.TrackedState import com.kylecorry.trail_sense.shared.declination.DeclinationFactory import com.kylecorry.trail_sense.shared.declination.DeclinationUtils import com.kylecorry.trail_sense.shared.extensions.onDefault @@ -130,8 +131,6 @@ class NavigatorFragment : BoundFragment() { R.drawable.ic_compass_icon ) } - private var gpsStatusBadge: StatusBadge? = null - private var compassStatusBadge: StatusBadge? = null // Diagnostics private val errors by lazy { NavigatorUserErrors(this) } @@ -146,9 +145,6 @@ class NavigatorFragment : BoundFragment() { ) { declination } } - - private var hasGpsUpdate = true - private var astronomyDataLoaded = false private var lastOrientation: DeviceOrientation.Orientation? = null @@ -181,6 +177,16 @@ class NavigatorFragment : BoundFragment() { private val styleChooser by lazy { CompassStyleChooser(userPrefs.navigation, hasCompass) } private val useTrueNorth by lazy { userPrefs.compass.useTrueNorth } + + // State + private val bearingState = TrackedState(0f) + private val speedState = TrackedState(0f) + private val altitudeState = TrackedState(0f) + private val locationState = TrackedState(Coordinate.zero) + private val compassStatusState = TrackedState(null) + private val gpsStatusState = TrackedState(null) + + private val northReferenceHideTimer = CoroutineTimer { if (isBound) { binding.northReferenceIndicator.showLabel = false @@ -293,11 +299,11 @@ class NavigatorFragment : BoundFragment() { navController = findNavController() - observe(compass) {} + observe(compass) { bearingState.write(compass.rawBearing) } observe(orientation) { onOrientationUpdate() } - observe(altimeter) { } - observe(gps) { onLocationUpdate() } - observe(speedometer) { } + observe(altimeter) { altitudeState.write(altimeter.altitude) } + observe(gps) { locationState.write(gps.location) } + observe(speedometer) { speedState.write(speedometer.speed.speed) } binding.navigationTitle.subtitle.setOnLongClickListener { Share.shareLocation( @@ -496,6 +502,7 @@ class NavigatorFragment : BoundFragment() { } // Populate the last known location + locationState.write(gps.location) layerManager?.onLocationChanged(gps.location, gps.horizontalAccuracy) // Resume navigation @@ -608,6 +615,7 @@ class NavigatorFragment : BoundFragment() { return } + // TODO: Move selected beacon updating to a coroutine val selectedBeacon = getSelectedBeacon(nearbyBeacons) if (selectedBeacon != null) { @@ -621,37 +629,74 @@ class NavigatorFragment : BoundFragment() { binding.navigationSheet.hide() } - gpsStatusBadge?.let { - binding.gpsStatus.setStatusText(it.name) - binding.gpsStatus.setBackgroundTint(it.color) + // GPS Status + if (gpsStatusState.hasChanges) { + gpsStatusState.read()?.let { + binding.gpsStatus.setStatusText(it.name) + binding.gpsStatus.setBackgroundTint(it.color) + } } - compassStatusBadge?.let { - binding.compassStatus.setStatusText(it.name) - binding.compassStatus.setBackgroundTint(it.color) + // Compass Status + if (compassStatusState.hasChanges) { + compassStatusState.read()?.let { + binding.compassStatus.setStatusText(it.name) + binding.compassStatus.setBackgroundTint(it.color) + } } // Speed - binding.speed.title = formatService.formatSpeed(speedometer.speed.speed) + if (speedState.hasChanges) { + binding.speed.title = formatService.formatSpeed(speedState.read()) + } + + // Azimuth + if (bearingState.hasChanges) { + updateCompassBearing() + } + + // Altitude + if (altitudeState.hasChanges) { + binding.altitude.title = formatService.formatDistance( + Distance.meters(altitudeState.read()).convertTo(baseDistanceUnits) + ) + } + + // Location + if (locationState.hasChanges) { + updateLocation() + } + + updateNavigationButton() + + // show on lock screen + if (lockScreenPresence && (destination != null || destinationBearing != null)) { + activity?.let { + tryOrNothing { + Screen.setShowWhenLocked(it, true) + } + } + } + + sightingCompass?.update() + } + + private fun updateCompassBearing() { + val bearing = Bearing(bearingState.read()) // Azimuth if (hasCompass) { val azimuthText = - formatService.formatDegrees(compass.bearing.value, replace360 = true) + formatService.formatDegrees(bearing.value, replace360 = true) .padStart(4, ' ') - val directionText = formatService.formatDirection(compass.bearing.direction) + val directionText = formatService.formatDirection(bearing.direction) .padStart(2, ' ') binding.navigationTitle.title.setTextDistinct("$azimuthText $directionText") } else { binding.navigationTitle.title.setTextDistinct(getString(R.string.dash)) } - // Altitude - binding.altitude.title = formatService.formatDistance( - Distance.meters(altimeter.altitude).convertTo(baseDistanceUnits) - ) - - layerManager?.onBearingChanged(compass.bearing) + layerManager?.onBearingChanged(bearing) // Compass listOf( @@ -659,33 +704,44 @@ class NavigatorFragment : BoundFragment() { binding.radarCompass, binding.linearCompass ).forEach { - it.azimuth = compass.bearing + it.azimuth = bearing it.declination = declination } + } - // Location - if (hasGpsUpdate) { - binding.navigationTitle.subtitle.setTextDistinct( - formatService.formatLocation( - gps.location - ) - ) - } + private fun updateLocation() { + val location = locationState.read() - updateNavigationButton() + binding.navigationTitle.subtitle.setTextDistinct( + formatService.formatLocation(location) + ) - // show on lock screen - if (lockScreenPresence && (destination != null || destinationBearing != null)) { - activity?.let { - tryOrNothing { - Screen.setShowWhenLocked(it, true) - } - } + layerManager?.onLocationChanged(location, gps.horizontalAccuracy) + + // Compass center point + listOf( + binding.roundCompass, + binding.radarCompass, + binding.linearCompass + ).forEach { + it.compassCenter = location } - sightingCompass?.update() + updateNearbyBeacons() + updateDeclination() - hasGpsUpdate = false + if (!astronomyDataLoaded) { + updateAstronomyData() + } + + if (useRadarCompass) { + val loadGeofence = Geofence( + location, + Distance.meters(nearbyDistance + 10) + ) + val bounds = CoordinateBounds.from(loadGeofence) + layerManager?.onBoundsChanged(bounds) + } } private fun updateCompassLayers() { @@ -719,6 +775,7 @@ class NavigatorFragment : BoundFragment() { } private fun getPosition(): Position { + // TODO: Remove this concept return Position( gps.location, altimeter.altitude, @@ -746,10 +803,9 @@ class NavigatorFragment : BoundFragment() { } } - private fun onOrientationUpdate(): Boolean { - + private fun onOrientationUpdate() { if (orientation.orientation == lastOrientation) { - return true + return } lastOrientation = orientation.orientation @@ -768,44 +824,12 @@ class NavigatorFragment : BoundFragment() { } else { disableSightingCompass() } - return true - } - - private fun onLocationUpdate() { - layerManager?.onLocationChanged(gps.location, gps.horizontalAccuracy) - - // Compass center point - listOf( - binding.roundCompass, - binding.radarCompass, - binding.linearCompass - ).forEach { - it.compassCenter = gps.location - } - - updateNearbyBeacons() - updateDeclination() - - if (!astronomyDataLoaded) { - updateAstronomyData() - } - - if (useRadarCompass) { - val loadGeofence = Geofence( - gps.location, - Distance.meters(nearbyDistance + 10) - ) - val bounds = CoordinateBounds.from(loadGeofence) - layerManager?.onBoundsChanged(bounds) - } - - hasGpsUpdate = true } private fun updateSensorStatus() { inBackground { - compassStatusBadge = compassStatusBadgeProvider.getBadge() - gpsStatusBadge = gpsStatusBadgeProvider.getBadge() + compassStatusState.write(compassStatusBadgeProvider.getBadge()) + gpsStatusState.write(gpsStatusBadgeProvider.getBadge()) val codes = onDefault { diagnostics.flatMap { it.scan() } @@ -835,7 +859,6 @@ class NavigatorFragment : BoundFragment() { private fun updateNavigator() { handleShowWhenLocked() - onLocationUpdate() updateNavigationButton() } diff --git a/app/src/main/java/com/kylecorry/trail_sense/shared/data/TrackedState.kt b/app/src/main/java/com/kylecorry/trail_sense/shared/data/TrackedState.kt index dbe89910f..f9e6b23ac 100644 --- a/app/src/main/java/com/kylecorry/trail_sense/shared/data/TrackedState.kt +++ b/app/src/main/java/com/kylecorry/trail_sense/shared/data/TrackedState.kt @@ -1,16 +1,18 @@ package com.kylecorry.trail_sense.shared.data -data class TrackedState(val initialState: T) { +class TrackedState(initialState: T) { private var state: T = initialState set(value) { + if (value != field) { + hasChanges = true + } field = value - hasChanges = true } /** * True if the state has changed since the last read */ - var hasChanges = false + var hasChanges = true /** * Read the state @@ -28,4 +30,11 @@ data class TrackedState(val initialState: T) { fun write(value: T) { state = value } + + /** + * Reset the read state + */ + fun resetReadState() { + hasChanges = true + } } \ No newline at end of file diff --git a/app/src/main/java/com/kylecorry/trail_sense/shared/views/DataPointView.kt b/app/src/main/java/com/kylecorry/trail_sense/shared/views/DataPointView.kt index 3d29dfd15..a64e3f234 100644 --- a/app/src/main/java/com/kylecorry/trail_sense/shared/views/DataPointView.kt +++ b/app/src/main/java/com/kylecorry/trail_sense/shared/views/DataPointView.kt @@ -8,6 +8,7 @@ import androidx.annotation.DrawableRes import androidx.core.view.isVisible import com.kylecorry.andromeda.core.system.Resources import com.kylecorry.andromeda.core.ui.Colors +import com.kylecorry.andromeda.core.ui.setTextDistinct import com.kylecorry.trail_sense.R import com.kylecorry.trail_sense.databinding.ViewDataPointBinding @@ -19,13 +20,13 @@ class DataPointView(context: Context, attrs: AttributeSet?) : FrameLayout(contex var title: String get() = binding.dataPointTitle.text.toString() set(value) { - binding.dataPointTitle.text = value + binding.dataPointTitle.setTextDistinct(value) } var description: String get() = binding.dataPointDesc.text.toString() set(value) { - binding.dataPointDesc.text = value + binding.dataPointDesc.setTextDistinct(value) } init {