diff --git a/app/src/main/java/org/nitri/opentopo/CacheSettingsFragment.kt b/app/src/main/java/org/nitri/opentopo/CacheSettingsFragment.kt index f447b41..fd8e1b9 100644 --- a/app/src/main/java/org/nitri/opentopo/CacheSettingsFragment.kt +++ b/app/src/main/java/org/nitri/opentopo/CacheSettingsFragment.kt @@ -14,6 +14,7 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.SwitchCompat import androidx.fragment.app.DialogFragment import androidx.localbroadcastmanager.content.LocalBroadcastManager +import androidx.preference.PreferenceManager import org.osmdroid.config.Configuration import java.io.File @@ -28,8 +29,7 @@ class CacheSettingsFragment : DialogFragment() { val inflater = requireActivity().layoutInflater @SuppressLint("InflateParams") val view = inflater.inflate(R.layout.fragment_cache_settings, null) - val prefs = - requireActivity().getSharedPreferences(MapFragment.MAP_PREFS, Context.MODE_PRIVATE) + val prefs = PreferenceManager.getDefaultSharedPreferences(requireActivity().applicationContext) val tvExternalStorageRoot = view.findViewById(R.id.tvExternalStorageRoot) val swExternalStorage = view.findViewById(R.id.swExternalStorage) etTileCache = view.findViewById(R.id.etTileCache) diff --git a/app/src/main/java/org/nitri/opentopo/MapFragment.kt b/app/src/main/java/org/nitri/opentopo/MapFragment.kt index 6c535c1..c30bf09 100644 --- a/app/src/main/java/org/nitri/opentopo/MapFragment.kt +++ b/app/src/main/java/org/nitri/opentopo/MapFragment.kt @@ -26,6 +26,7 @@ import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.Window +import android.view.WindowManager import android.widget.PopupMenu import android.widget.TextView import android.widget.Toast @@ -36,6 +37,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import androidx.lifecycle.ViewModelProvider +import androidx.preference.PreferenceManager import io.ticofab.androidgpxparser.parser.domain.Gpx import org.nitri.opentopo.SettingsActivity.Companion.PREF_FULLSCREEN import org.nitri.opentopo.SettingsActivity.Companion.PREF_KEEP_SCREEN_ON @@ -47,6 +49,7 @@ import org.nitri.opentopo.overlay.ClickableCompassOverlay import org.nitri.opentopo.overlay.GestureOverlay import org.nitri.opentopo.overlay.GestureOverlay.GestureCallback import org.nitri.opentopo.overlay.OverlayHelper +import org.nitri.opentopo.util.MapOrientation import org.nitri.opentopo.util.Util import org.osmdroid.config.Configuration import org.osmdroid.events.DelayedMapListener @@ -69,7 +72,8 @@ import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay import java.io.File class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListener, - GestureCallback { + GestureCallback, ClickableCompassOverlay.OnCompassClickListener { + private var mapRotation: Boolean = false private lateinit var mMapView: MapView private var mLocationOverlay: MyLocationNewOverlay? = null private var mCompassOverlay: CompassOverlay? = null @@ -109,7 +113,13 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe } fun setKeepScreenOn(value: Boolean) { + Log.d(TAG, "keepScreenOn: $value") mMapView.keepScreenOn = value + if (value) { + requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } else { + requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } } private var mFollow = false @@ -132,7 +142,7 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe super.onCreate(savedInstanceState) setHasOptionsMenu(true) val context = requireActivity().applicationContext - mPrefs = requireActivity().getSharedPreferences(MAP_PREFS, Context.MODE_PRIVATE) + mPrefs = PreferenceManager.getDefaultSharedPreferences(context) val configuration = Configuration.getInstance() configuration.userAgentValue = BuildConfig.APPLICATION_ID val basePath = Util.getOsmdroidBasePath(context, mPrefs.getBoolean(CacheSettingsFragment.PREF_EXTERNAL_STORAGE, false)) @@ -206,7 +216,11 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe } })) - mCompassOverlay = ClickableCompassOverlay( +// TODO: mCompassOverlay = ClickableCompassOverlay( +// activity, InternalCompassOrientationProvider(activity), +// mMapView, this +// ) + mCompassOverlay = CompassOverlay( activity, InternalCompassOrientationProvider(activity), mMapView ) @@ -810,6 +824,9 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe String.format("Location: %f, %f", location.latitude, location.longitude) ) mLocationViewModel?.currentLocation?.value = location + if (mapRotation) { + MapOrientation.setTargetMapOrientation(mMapView, location.bearing) + } } @Deprecated("Deprecated in Java") @@ -856,6 +873,16 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe } } + override fun onCompassClicked() { + mapRotation = !mapRotation + if (mapRotation) { + Toast.makeText(requireContext(), R.string.rotation_on, Toast.LENGTH_SHORT).show() + } else { + MapOrientation.setTargetMapOrientation(mMapView, 0f) + Toast.makeText(requireContext(), R.string.rotation_off, Toast.LENGTH_SHORT).show() + } + } + interface OnFragmentInteractionListener { /** * Start GPX file selection flow @@ -935,7 +962,6 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe private const val STATE_LATITUDE = "latitude" private const val STATE_LONGITUDE = "longitude" private const val STATE_ZOOM = "zoom" - const val MAP_PREFS = "map_prefs" private const val PREF_BASE_MAP = "base_map" private const val PREF_OVERLAY = "overlay" private const val PREF_LATITUDE = "latitude" @@ -958,4 +984,5 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe return mapFragment } } + } \ No newline at end of file diff --git a/app/src/main/java/org/nitri/opentopo/overlay/ClickableCompassOverlay.kt b/app/src/main/java/org/nitri/opentopo/overlay/ClickableCompassOverlay.kt index d153c45..6061fe8 100644 --- a/app/src/main/java/org/nitri/opentopo/overlay/ClickableCompassOverlay.kt +++ b/app/src/main/java/org/nitri/opentopo/overlay/ClickableCompassOverlay.kt @@ -10,7 +10,8 @@ import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider class ClickableCompassOverlay( context: Context, orientationProvider: InternalCompassOrientationProvider, - mapView: MapView + mapView: MapView, + private val onCompassClickListener: OnCompassClickListener ) : CompassOverlay(context, orientationProvider, mapView) { @@ -18,11 +19,13 @@ class ClickableCompassOverlay( val reuse = Point() mapView.projection.rotateAndScalePoint(e.x.toInt(), e.y.toInt(), reuse) if (reuse.x < mCompassFrameCenterX * 2 && reuse.y < mCompassFrameCenterY * 2) { - mapView.controller?.animateTo(null, null, 300, 0f) + onCompassClickListener.onCompassClicked() return true } - return super.onSingleTapConfirmed(e, mapView) } + interface OnCompassClickListener { + fun onCompassClicked() + } } \ No newline at end of file diff --git a/app/src/main/java/org/nitri/opentopo/util/MapOrientation.kt b/app/src/main/java/org/nitri/opentopo/util/MapOrientation.kt index 15137dd..5eaf7df 100644 --- a/app/src/main/java/org/nitri/opentopo/util/MapOrientation.kt +++ b/app/src/main/java/org/nitri/opentopo/util/MapOrientation.kt @@ -1,6 +1,5 @@ package org.nitri.opentopo.util -import android.util.Log import android.view.animation.AccelerateDecelerateInterpolator import android.view.animation.Interpolator import kotlinx.coroutines.CoroutineScope @@ -13,33 +12,41 @@ import kotlin.math.abs import kotlin.math.roundToInt -class MapOrientation { +object MapOrientation { + + private val TAG = MapOrientation::class.java.simpleName + private const val ORIENTATION_ANIMATION_STEP_SIZE: Float = 0.1f // degrees + private const val ORIENTATION_ANIMATION_DELTA_TIME: Int = 3 // ms + private const val ORIENTATION_EPSILON: Int = 10 // noise threshold value private lateinit var animationJob: Job - private var mMapOrientation = 0f - private var mTargetMapOrientation = 0f - private var mPreviousMapOrientation = 0f + private var mapOrientation = 0f + private var targetMapOrientation = 0f + private var previousMapOrientation = 0f private val orientationAnimationInterpolator: Interpolator = AccelerateDecelerateInterpolator() private var mMapOrientationAnimationRunning = false + val currentMapOrientation: Float + get() = mapOrientation + /** * Target orientation based on heading. Start orientation animation on change above noise threshold. * * @param degrees 0 - 360 degrees */ fun setTargetMapOrientation(mapView: MapView, degrees: Float) { - mTargetMapOrientation = degrees + targetMapOrientation = degrees - val roundedTargetMapOrientation = mTargetMapOrientation.roundToInt() - val roundedPreviousMapOrientation = mPreviousMapOrientation.roundToInt() + val roundedTargetMapOrientation = targetMapOrientation.roundToInt() + val roundedPreviousMapOrientation = previousMapOrientation.roundToInt() - if (abs(mTargetMapOrientation - mPreviousMapOrientation) > ORIENTATION_EPSILON + if (abs(targetMapOrientation - previousMapOrientation) > ORIENTATION_EPSILON && roundedTargetMapOrientation != roundedPreviousMapOrientation ) { if (!mMapOrientationAnimationRunning) { - animateToMapOrientation(mapView, mMapOrientation, 360 - mTargetMapOrientation) + animateToMapOrientation(mapView, mapOrientation, 360 - targetMapOrientation) } } } @@ -50,7 +57,11 @@ class MapOrientation { * @param originalOrientation deg * @param targetMapOrientation deg */ - private fun animateToMapOrientation(mapView: MapView, originalOrientation: Float, targetMapOrientation: Float) { + private fun animateToMapOrientation( + mapView: MapView, + originalOrientation: Float, + targetMapOrientation: Float + ) { animationJob.cancel() @@ -63,12 +74,12 @@ class MapOrientation { for (step in 1..numberOfSteps) { val timeIndex = step.toFloat() / numberOfSteps val angularProgress = orientationAnimationInterpolator.getInterpolation(timeIndex) - mMapOrientation = originalOrientation + angularDistance * angularProgress + mapOrientation = originalOrientation + angularDistance * angularProgress - mMapOrientation = (mMapOrientation + 360) % 360 // Keep within 0-360 range + mapOrientation = (mapOrientation + 360) % 360 // Keep within 0-360 range - mPreviousMapOrientation = mMapOrientation - mapView.mapOrientation = mMapOrientation + previousMapOrientation = mapOrientation + mapView.mapOrientation = mapOrientation delay(ORIENTATION_ANIMATION_DELTA_TIME.toLong()) } @@ -82,11 +93,4 @@ class MapOrientation { val distance = if (phi > 180) 360 - phi else phi return distance * if ((alpha - beta + 360) % 360 > 180) -1 else 1 } - - companion object { - private val TAG = MapOrientation::class.java.simpleName - const val ORIENTATION_ANIMATION_STEP_SIZE: Float = 0.1f // degrees - const val ORIENTATION_ANIMATION_DELTA_TIME: Int = 3 // ms - const val ORIENTATION_EPSILON: Int = 10 // noise threshold value - } } \ No newline at end of file diff --git a/app/src/main/java/org/nitri/opentopo/util/Util.kt b/app/src/main/java/org/nitri/opentopo/util/Util.kt index fc44037..7b10204 100644 --- a/app/src/main/java/org/nitri/opentopo/util/Util.kt +++ b/app/src/main/java/org/nitri/opentopo/util/Util.kt @@ -155,7 +155,6 @@ object Util { * @param source * @return */ - @JvmStatic @Suppress("deprecation") fun fromHtml(source: String?): Spanned { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { @@ -171,7 +170,6 @@ object Util { * @param nmea NMEA * @return antenna altitude */ - @JvmStatic fun elevationFromNmea(nmea: String): Double { if (!TextUtils.isEmpty(nmea) && nmea.startsWith("\$GPGGA")) { val tokens = nmea.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 6257398..7f7db7e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -4,6 +4,8 @@ Folgen Folgen aktiviert Folgen deaktiviert + Rotation ein + Rotation aus GPX Die aktuelle GPX wird verworfen. GPX Details diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 899785a..7ca1257 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -4,6 +4,8 @@ Seguir Seguimiento activado Seguimiento desactivado + Rotación activada + Rotación desactivada GPX El GPX actual será descartado. Detalles del GPX diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index eb5fb5e..798d96e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -4,6 +4,8 @@ Suivre Suivi activé Suivi désactivé + Rotation activée + Rotation désactivée GPX Le GPX actuel sera supprimé. Détails du GPX diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index d99ee0f..f3f3e3d 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -4,6 +4,8 @@ Volgen Volgen ingeschakeld Volgen uitgeschakeld + Rotatie aan + Rotatie uit GPX De huidige GPX wordt verwijderd. GPX details diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8bab291..5c72395 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,6 +4,8 @@ Follow Follow enabled Follow disabled + Rotation on + Rotation off GPX The current GPX will be discarded. GPX details