checkpoint

This commit is contained in:
voussoir 2023-03-09 22:25:21 -08:00
parent 04fa76249b
commit 5dad3d6209
2 changed files with 283 additions and 323 deletions

View file

@ -17,20 +17,39 @@
package org.y20k.trackbook package org.y20k.trackbook
import android.Manifest import android.Manifest
import android.app.Activity
import android.content.* import android.content.*
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.location.Location import android.location.Location
import android.os.* import android.os.*
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import org.y20k.trackbook.Track import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import org.osmdroid.api.IMapController
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.FolderOverlay
import org.osmdroid.views.overlay.ItemizedIconOverlay
import org.osmdroid.views.overlay.OverlayItem
import org.osmdroid.views.overlay.Polygon
import org.osmdroid.views.overlay.TilesOverlay
import org.osmdroid.views.overlay.compass.CompassOverlay
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider
import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlay
import org.y20k.trackbook.helpers.* import org.y20k.trackbook.helpers.*
import org.y20k.trackbook.ui.MapFragmentLayoutHolder
/* /*
* MapFragment class * MapFragment class
@ -48,11 +67,25 @@ class MapFragment : Fragment()
private var networkProviderActive: Boolean = false private var networkProviderActive: Boolean = false
private lateinit var track: Track private lateinit var track: Track
private lateinit var currentBestLocation: Location private lateinit var currentBestLocation: Location
private lateinit var layout: MapFragmentLayoutHolder
private lateinit var trackerService: TrackerService private lateinit var trackerService: TrackerService
lateinit var rootView: View
var userInteraction: Boolean = false
lateinit var currentLocationButton: FloatingActionButton
lateinit var mainButton: ExtendedFloatingActionButton
private lateinit var mapView: MapView
private lateinit var current_position_folder: FolderOverlay
private var currentTrackOverlay: SimpleFastPointOverlay? = null
private var currentTrackSpecialMarkerOverlay: ItemizedIconOverlay<OverlayItem>? = null
private lateinit var locationErrorBar: Snackbar
private lateinit var controller: IMapController
private var zoomLevel: Double = Keys.DEFAULT_ZOOM_LEVEL
private lateinit var homepoints_overlay_folder: FolderOverlay
/* Overrides onCreate from Fragment */ /* Overrides onCreate from Fragment */
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?)
{
Log.i("VOUSSOIR", "MapFragment.onCreate")
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// TODO make only MapFragment's status bar transparent - see: // TODO make only MapFragment's status bar transparent - see:
// https://gist.github.com/Dvik/a3de88d39da9d1d6d175025a56c5e797#file-viewextension-kt and // https://gist.github.com/Dvik/a3de88d39da9d1d6d175025a56c5e797#file-viewextension-kt and
@ -61,28 +94,84 @@ class MapFragment : Fragment()
currentBestLocation = getLastKnownLocation(activity as Context) currentBestLocation = getLastKnownLocation(activity as Context)
// get saved tracking state // get saved tracking state
trackingState = PreferencesHelper.loadTrackingState() trackingState = PreferencesHelper.loadTrackingState()
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} }
/* Overrides onStop from Fragment */ /* Overrides onStop from Fragment */
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
// initialize layout {
val statusBarHeight: Int = UiHelper.getStatusBarHeight(activity as Context) Log.i("VOUSSOIR", "MapFragment.onCreateView")
layout = MapFragmentLayoutHolder(activity as Context, inflater, container, statusBarHeight, currentBestLocation, trackingState) val context = activity as Context
// find views
rootView = inflater.inflate(R.layout.fragment_map, container, false)
mapView = rootView.findViewById(R.id.map)
currentLocationButton = rootView.findViewById(R.id.location_button)
mainButton = rootView.findViewById(R.id.main_button)
locationErrorBar = Snackbar.make(mapView, String(), Snackbar.LENGTH_INDEFINITE)
// basic map setup
controller = mapView.controller
mapView.isTilesScaledToDpi = true
mapView.setTileSource(TileSourceFactory.MAPNIK)
mapView.setMultiTouchControls(true)
mapView.zoomController.setVisibility(org.osmdroid.views.CustomZoomButtonsController.Visibility.NEVER)
zoomLevel = PreferencesHelper.loadZoomLevel()
controller.setZoom(zoomLevel)
// set dark map tiles, if necessary
if (AppThemeHelper.isDarkModeOn(requireActivity()))
{
mapView.overlayManager.tilesOverlay.setColorFilter(TilesOverlay.INVERT_COLORS)
}
// store Density Scaling Factor
val densityScalingFactor: Float = UiHelper.getDensityScalingFactor(context)
// add compass to map
val compassOverlay = CompassOverlay(context, InternalCompassOrientationProvider(context), mapView)
compassOverlay.enableCompass()
// compassOverlay.setCompassCenter(36f, 36f + (statusBarHeight / densityScalingFactor)) // TODO uncomment when transparent status bar is re-implemented
val screen_width = Resources.getSystem().displayMetrics.widthPixels;
compassOverlay.setCompassCenter((screen_width / densityScalingFactor) - 36f, 36f)
mapView.overlays.add(compassOverlay)
val app: Trackbook = (context.applicationContext as Trackbook)
app.load_homepoints()
homepoints_overlay_folder = FolderOverlay()
mapView.overlays.add(homepoints_overlay_folder)
createHomepointOverlays(context, mapView, app.homepoints)
// add my location overlay
current_position_folder = FolderOverlay()
mapView.overlays.add(current_position_folder)
centerMap(currentBestLocation)
// initialize track overlays
currentTrackOverlay = null
currentTrackSpecialMarkerOverlay = null
// initialize main button state
updateMainButton(trackingState)
// listen for user interaction
addInteractionListener()
// set up buttons // set up buttons
layout.currentLocationButton.setOnClickListener { currentLocationButton.setOnClickListener {
layout.centerMap(currentBestLocation, animated = true) centerMap(currentBestLocation, animated = true)
} }
layout.mainButton.setOnClickListener { mainButton.setOnClickListener {
handleTrackingManagementMenu() handleTrackingManagementMenu()
} }
return layout.rootView requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
return rootView
} }
/* Overrides onStart from Fragment */ /* Overrides onStart from Fragment */
override fun onStart() { override fun onStart()
{
super.onStart() super.onStart()
// request location permission if denied // request location permission if denied
if (ContextCompat.checkSelfPermission(activity as Context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) { if (ContextCompat.checkSelfPermission(activity as Context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) {
@ -93,8 +182,11 @@ class MapFragment : Fragment()
} }
/* Overrides onResume from Fragment */ /* Overrides onResume from Fragment */
override fun onResume() { override fun onResume()
{
Log.i("VOUSSOIR", "MapFragment.onResume")
super.onResume() super.onResume()
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
// if (bound) { // if (bound) {
// trackerService.addGpsLocationListener() // trackerService.addGpsLocationListener()
// trackerService.addNetworkLocationListener() // trackerService.addNetworkLocationListener()
@ -102,18 +194,22 @@ class MapFragment : Fragment()
} }
/* Overrides onPause from Fragment */ /* Overrides onPause from Fragment */
override fun onPause() { override fun onPause()
{
Log.i("VOUSSOIR", "MapFragment.onPause")
super.onPause() super.onPause()
layout.saveState(currentBestLocation) saveBestLocationState(currentBestLocation)
if (bound && trackingState != Keys.STATE_TRACKING_ACTIVE) { if (bound && trackingState != Keys.STATE_TRACKING_ACTIVE) {
trackerService.removeGpsLocationListener() trackerService.removeGpsLocationListener()
trackerService.removeNetworkLocationListener() trackerService.removeNetworkLocationListener()
trackerService.trackbook.database.commit() trackerService.trackbook.database.commit()
} }
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} }
/* Overrides onStop from Fragment */ /* Overrides onStop from Fragment */
override fun onStop() { override fun onStop()
{
super.onStop() super.onStop()
// unbind from TrackerService // unbind from TrackerService
if (bound) if (bound)
@ -123,6 +219,13 @@ class MapFragment : Fragment()
} }
} }
override fun onDestroy()
{
Log.i("VOUSSOIR", "MapFragment.onDestroy")
super.onDestroy()
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
/* Register the permission launcher for requesting location */ /* Register the permission launcher for requesting location */
private val requestLocationPermissionLauncher = registerForActivityResult(RequestPermission()) { isGranted: Boolean -> private val requestLocationPermissionLauncher = registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
if (isGranted) { if (isGranted) {
@ -134,26 +237,24 @@ class MapFragment : Fragment()
// permission denied - unbind service // permission denied - unbind service
activity?.unbindService(connection) activity?.unbindService(connection)
} }
layout.toggleLocationErrorBar(gpsProviderActive, networkProviderActive) toggleLocationErrorBar(gpsProviderActive, networkProviderActive)
} }
/* Register the permission launcher for starting the tracking service */ /* Register the permission launcher for starting the tracking service */
private val startTrackingPermissionLauncher = registerForActivityResult(RequestPermission()) { isGranted: Boolean -> private val startTrackingPermissionLauncher = registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
logPermissionRequestResult(isGranted) if (isGranted)
{
LogHelper.i(TAG, "Request result: Activity Recognition permission has been granted.")
}
else
{
LogHelper.i(TAG, "Request result: Activity Recognition permission has NOT been granted.")
}
// start service via intent so that it keeps running after unbind // start service via intent so that it keeps running after unbind
startTrackerService() startTrackerService()
trackerService.startTracking() trackerService.startTracking()
} }
/* Logs the request result of the Activity Recognition permission launcher */
private fun logPermissionRequestResult(isGranted: Boolean) {
if (isGranted) {
LogHelper.i(TAG, "Request result: Activity Recognition permission has been granted.")
} else {
LogHelper.i(TAG, "Request result: Activity Recognition permission has NOT been granted.")
}
}
/* Start recording waypoints */ /* Start recording waypoints */
private fun startTracking() { private fun startTracking() {
// request activity recognition permission on Android Q+ if denied // request activity recognition permission on Android Q+ if denied
@ -211,11 +312,153 @@ class MapFragment : Fragment()
if (activity != null) if (activity != null)
{ {
trackingState = PreferencesHelper.loadTrackingState() trackingState = PreferencesHelper.loadTrackingState()
layout.updateMainButton(trackingState) updateMainButton(trackingState)
} }
} }
} }
} }
private fun addInteractionListener() {
mapView.setOnTouchListener { v, event ->
userInteraction = true
false
}
}
fun centerMap(location: Location, animated: Boolean = false) {
val position = GeoPoint(location.latitude, location.longitude)
when (animated) {
true -> controller.animateTo(position)
false -> controller.setCenter(position)
}
userInteraction = false
}
fun saveBestLocationState(currentBestLocation: Location) {
PreferencesHelper.saveCurrentBestLocation(currentBestLocation)
PreferencesHelper.saveZoomLevel(mapView.zoomLevelDouble)
// reset user interaction state
userInteraction = false
}
/* Mark current position on map */
fun markCurrentPosition(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED)
{
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.markCurrentPosition")
val locationIsOld: Boolean = !(isRecentEnough(location))
// create marker
val newMarker: Drawable
val fillcolor: Int
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
{
fillcolor = Color.argb(64, 220, 61, 51)
if (locationIsOld)
{
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_black_24dp)!!
}
else
{
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_red_24dp)!!
}
}
else
{
fillcolor = Color.argb(64, 60, 152, 219)
if(locationIsOld)
{
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_black_24dp)!!
}
else
{
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_blue_24dp)!!
}
}
current_position_folder.items.clear()
val current_location_radius = Polygon()
current_location_radius.points = Polygon.pointsAsCircle(GeoPoint(location.latitude, location.longitude), location.accuracy.toDouble())
current_location_radius.fillPaint.color = fillcolor
current_location_radius.outlinePaint.color = Color.argb(0, 0, 0, 0)
current_position_folder.add(current_location_radius)
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
val overlayItem: OverlayItem = createOverlayItem(requireContext(), location.latitude, location.longitude, location.accuracy, location.provider.toString(), location.time)
overlayItem.setMarker(newMarker)
overlayItems.add(overlayItem)
current_position_folder.add(createOverlay(requireContext(), overlayItems))
}
fun createHomepointOverlays(context: Context, map_view: MapView, homepoints: List<Homepoint>)
{
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.createHomepointOverlays")
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
val newMarker: Drawable = ContextCompat.getDrawable(context, R.drawable.ic_homepoint_24dp)!!
homepoints_overlay_folder.items.clear()
for (homepoint in homepoints)
{
val overlayItem: OverlayItem = createOverlayItem(context, homepoint.location.latitude, homepoint.location.longitude, homepoint.location.accuracy, homepoint.location.provider.toString(), homepoint.location.time)
overlayItem.setMarker(newMarker)
overlayItems.add(overlayItem)
homepoints_overlay_folder.add(createOverlay(context, overlayItems))
val p = Polygon()
p.points = Polygon.pointsAsCircle(GeoPoint(homepoint.location.latitude, homepoint.location.longitude), homepoint.location.accuracy.toDouble())
p.fillPaint.color = Color.argb(64, 255, 193, 7)
p.outlinePaint.color = Color.argb(0, 0, 0, 0)
homepoints_overlay_folder.add(p)
}
}
/* Overlay current track on map */
fun overlayCurrentTrack(track: Track, trackingState: Int) {
if (currentTrackOverlay != null) {
mapView.overlays.remove(currentTrackOverlay)
}
if (currentTrackSpecialMarkerOverlay != null) {
mapView.overlays.remove(currentTrackSpecialMarkerOverlay)
}
if (track.trkpts.isNotEmpty()) {
createTrackOverlay(requireContext(), mapView, track, trackingState)
createSpecialMakersTrackOverlay(requireContext(), mapView, track, trackingState)
}
}
/* Toggles state of main button and additional buttons (save & resume) */
fun updateMainButton(trackingState: Int)
{
when (trackingState) {
Keys.STATE_TRACKING_STOPPED -> {
mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp)
mainButton.text = requireContext().getString(R.string.button_start)
mainButton.contentDescription = requireContext().getString(R.string.descr_button_start)
currentLocationButton.isVisible = true
}
Keys.STATE_TRACKING_ACTIVE -> {
mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp)
mainButton.text = requireContext().getString(R.string.button_pause)
mainButton.contentDescription = requireContext().getString(R.string.descr_button_pause)
currentLocationButton.isVisible = true
}
}
}
fun toggleLocationErrorBar(gpsProviderActive: Boolean, networkProviderActive: Boolean) {
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) {
// CASE: Location permission not granted
locationErrorBar.setText(R.string.snackbar_message_location_permission_denied)
if (!locationErrorBar.isShown) locationErrorBar.show()
} else if (!gpsProviderActive && !networkProviderActive) {
// CASE: Location setting is off
locationErrorBar.setText(R.string.snackbar_message_location_offline)
if (!locationErrorBar.isShown) locationErrorBar.show()
} else {
if (locationErrorBar.isShown) locationErrorBar.dismiss()
}
}
/* /*
* End of declaration * End of declaration
*/ */
@ -231,7 +474,7 @@ class MapFragment : Fragment()
trackerService = binder.service trackerService = binder.service
// get state of tracking and update button if necessary // get state of tracking and update button if necessary
trackingState = trackerService.trackingState trackingState = trackerService.trackingState
layout.updateMainButton(trackingState) updateMainButton(trackingState)
// register listener for changes in shared preferences // register listener for changes in shared preferences
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener) PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
// start listening for location updates // start listening for location updates
@ -259,15 +502,15 @@ class MapFragment : Fragment()
networkProviderActive = trackerService.networkProviderActive networkProviderActive = trackerService.networkProviderActive
trackingState = trackerService.trackingState trackingState = trackerService.trackingState
// update location and track // update location and track
layout.markCurrentPosition(currentBestLocation, trackingState) markCurrentPosition(currentBestLocation, trackingState)
layout.overlayCurrentTrack(track, trackingState) overlayCurrentTrack(track, trackingState)
// center map, if it had not been dragged/zoomed before // center map, if it had not been dragged/zoomed before
if (!layout.userInteraction) if (!userInteraction)
{ {
layout.centerMap(currentBestLocation, true) centerMap(currentBestLocation, true)
} }
// show error snackbar if necessary // show error snackbar if necessary
layout.toggleLocationErrorBar(gpsProviderActive, networkProviderActive) toggleLocationErrorBar(gpsProviderActive, networkProviderActive)
// use the handler to start runnable again after specified delay // use the handler to start runnable again after specified delay
handler.postDelayed(this, Keys.REQUEST_CURRENT_LOCATION_INTERVAL) handler.postDelayed(this, Keys.REQUEST_CURRENT_LOCATION_INTERVAL)
} }

View file

@ -1,283 +0,0 @@
/*
* MapFragmentLayoutHolder.kt
* Implements the MapFragmentLayoutHolder class
* A MapFragmentLayoutHolder hold references to the main views of a map fragment
*
* This file is part of
* TRACKBOOK - Movement Recorder for Android
*
* Copyright (c) 2016-22 - Y20K.org
* Licensed under the MIT-License
* http://opensource.org/licenses/MIT
*
* Trackbook uses osmdroid - OpenStreetMap-Tools for Android
* https://github.com/osmdroid/osmdroid
*/
package org.y20k.trackbook.ui
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.content.res.Resources
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.location.Location
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import org.osmdroid.api.IMapController
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.ItemizedIconOverlay
import org.osmdroid.views.overlay.OverlayItem
import org.osmdroid.views.overlay.Polygon
import org.osmdroid.views.overlay.TilesOverlay
import org.osmdroid.views.overlay.compass.CompassOverlay
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider
import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlay
import org.y20k.trackbook.Homepoint
import org.y20k.trackbook.Keys
import org.y20k.trackbook.R
import org.y20k.trackbook.Trackbook
import org.y20k.trackbook.Track
import org.y20k.trackbook.helpers.*
/*
* MapFragmentLayoutHolder class
*/
data class MapFragmentLayoutHolder(
private var context: Context,
private var inflater: LayoutInflater,
private var container: ViewGroup?,
private var statusBarHeight: Int,
private val startLocation: Location,
private val trackingState: Int
)
{
val rootView: View
var userInteraction: Boolean = false
val currentLocationButton: FloatingActionButton
val mainButton: ExtendedFloatingActionButton
private val mapView: MapView
private var currentPositionOverlay: ItemizedIconOverlay<OverlayItem>
private var current_location_radius: Polygon = Polygon()
private var currentTrackOverlay: SimpleFastPointOverlay?
private var currentTrackSpecialMarkerOverlay: ItemizedIconOverlay<OverlayItem>?
private var locationErrorBar: Snackbar
private var controller: IMapController
private var zoomLevel: Double
init
{
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.init")
// find views
rootView = inflater.inflate(R.layout.fragment_map, container, false)
mapView = rootView.findViewById(R.id.map)
currentLocationButton = rootView.findViewById(R.id.location_button)
mainButton = rootView.findViewById(R.id.main_button)
locationErrorBar = Snackbar.make(mapView, String(), Snackbar.LENGTH_INDEFINITE)
// basic map setup
controller = mapView.controller
mapView.isTilesScaledToDpi = true
mapView.setTileSource(TileSourceFactory.MAPNIK)
mapView.setMultiTouchControls(true)
mapView.zoomController.setVisibility(org.osmdroid.views.CustomZoomButtonsController.Visibility.NEVER)
zoomLevel = PreferencesHelper.loadZoomLevel()
controller.setZoom(zoomLevel)
// set dark map tiles, if necessary
if (AppThemeHelper.isDarkModeOn(context as Activity)) {
mapView.overlayManager.tilesOverlay.setColorFilter(TilesOverlay.INVERT_COLORS)
}
// store Density Scaling Factor
val densityScalingFactor: Float = UiHelper.getDensityScalingFactor(context)
// add compass to map
val compassOverlay = CompassOverlay(context, InternalCompassOrientationProvider(context), mapView)
compassOverlay.enableCompass()
// compassOverlay.setCompassCenter(36f, 36f + (statusBarHeight / densityScalingFactor)) // TODO uncomment when transparent status bar is re-implemented
val screen_width = Resources.getSystem().getDisplayMetrics().widthPixels;
compassOverlay.setCompassCenter((screen_width / densityScalingFactor) - 36f, 36f)
mapView.overlays.add(compassOverlay)
val app: Trackbook = (context.applicationContext as Trackbook)
app.load_homepoints()
createHomepointOverlays(context, mapView, app.homepoints)
// add my location overlay
currentPositionOverlay = createOverlay(context, ArrayList<OverlayItem>())
mapView.overlays.add(currentPositionOverlay)
centerMap(startLocation)
// initialize track overlays
currentTrackOverlay = null
currentTrackSpecialMarkerOverlay = null
// initialize main button state
updateMainButton(trackingState)
// listen for user interaction
addInteractionListener()
}
/* Listen for user interaction */
@SuppressLint("ClickableViewAccessibility")
private fun addInteractionListener() {
mapView.setOnTouchListener { v, event ->
userInteraction = true
false
}
}
/* Set map center */
fun centerMap(location: Location, animated: Boolean = false) {
val position = GeoPoint(location.latitude, location.longitude)
when (animated) {
true -> controller.animateTo(position)
false -> controller.setCenter(position)
}
userInteraction = false
}
/* Save current best location and state of map to shared preferences */
fun saveState(currentBestLocation: Location) {
PreferencesHelper.saveCurrentBestLocation(currentBestLocation)
PreferencesHelper.saveZoomLevel(mapView.zoomLevelDouble)
// reset user interaction state
userInteraction = false
}
/* Mark current position on map */
fun markCurrentPosition(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED)
{
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.markCurrentPosition")
val locationIsOld: Boolean = !(isRecentEnough(location))
// create marker
val newMarker: Drawable
val fillcolor: Int
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
{
fillcolor = Color.argb(64, 220, 61, 51)
if (locationIsOld)
{
newMarker = ContextCompat.getDrawable(context, R.drawable.ic_marker_location_black_24dp)!!
}
else
{
newMarker = ContextCompat.getDrawable(context, R.drawable.ic_marker_location_red_24dp)!!
}
}
else
{
fillcolor = Color.argb(64, 60, 152, 219)
if(locationIsOld)
{
newMarker = ContextCompat.getDrawable(context, R.drawable.ic_marker_location_black_24dp)!!
}
else
{
newMarker = ContextCompat.getDrawable(context, R.drawable.ic_marker_location_blue_24dp)!!
}
}
// add marker to list of overlay items
val overlayItem: OverlayItem = createOverlayItem(context, location.latitude, location.longitude, location.accuracy, location.provider.toString(), location.time)
overlayItem.setMarker(newMarker)
currentPositionOverlay.removeAllItems()
currentPositionOverlay.addItem(overlayItem)
if (current_location_radius in mapView.overlays)
{
mapView.overlays.remove(current_location_radius)
}
current_location_radius = Polygon()
current_location_radius.points = Polygon.pointsAsCircle(GeoPoint(location.latitude, location.longitude), location.accuracy.toDouble())
current_location_radius.fillPaint.color = fillcolor
current_location_radius.outlinePaint.color = Color.argb(0, 0, 0, 0)
mapView.overlays.add(current_location_radius)
}
fun createHomepointOverlays(context: Context, map_view: MapView, homepoints: List<Homepoint>)
{
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.createHomepointOverlays")
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
val newMarker: Drawable = ContextCompat.getDrawable(context, R.drawable.ic_homepoint_24dp)!!
for (homepoint in homepoints)
{
val overlayItem: OverlayItem = createOverlayItem(context, homepoint.location.latitude, homepoint.location.longitude, homepoint.location.accuracy, homepoint.location.provider.toString(), homepoint.location.time)
overlayItem.setMarker(newMarker)
overlayItems.add(overlayItem)
map_view.overlays.add(createOverlay(context, overlayItems))
val p = Polygon()
p.points = Polygon.pointsAsCircle(GeoPoint(homepoint.location.latitude, homepoint.location.longitude), homepoint.location.accuracy.toDouble())
p.fillPaint.color = Color.argb(64, 255, 193, 7)
p.outlinePaint.color = Color.argb(0, 0, 0, 0)
map_view.overlays.add(p)
}
}
/* Overlay current track on map */
fun overlayCurrentTrack(track: Track, trackingState: Int) {
if (currentTrackOverlay != null) {
mapView.overlays.remove(currentTrackOverlay)
}
if (currentTrackSpecialMarkerOverlay != null) {
mapView.overlays.remove(currentTrackSpecialMarkerOverlay)
}
if (track.trkpts.isNotEmpty()) {
createTrackOverlay(context, mapView, track, trackingState)
createSpecialMakersTrackOverlay(context, mapView, track, trackingState)
}
}
/* Toggles state of main button and additional buttons (save & resume) */
fun updateMainButton(trackingState: Int)
{
when (trackingState) {
Keys.STATE_TRACKING_STOPPED -> {
mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp)
mainButton.text = context.getString(R.string.button_start)
mainButton.contentDescription = context.getString(R.string.descr_button_start)
currentLocationButton.isVisible = true
}
Keys.STATE_TRACKING_ACTIVE -> {
mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp)
mainButton.text = context.getString(R.string.button_pause)
mainButton.contentDescription = context.getString(R.string.descr_button_pause)
currentLocationButton.isVisible = true
}
}
}
/* Toggles content and visibility of the location error snackbar */
fun toggleLocationErrorBar(gpsProviderActive: Boolean, networkProviderActive: Boolean) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) {
// CASE: Location permission not granted
locationErrorBar.setText(R.string.snackbar_message_location_permission_denied)
if (!locationErrorBar.isShown) locationErrorBar.show()
} else if (!gpsProviderActive && !networkProviderActive) {
// CASE: Location setting is off
locationErrorBar.setText(R.string.snackbar_message_location_offline)
if (!locationErrorBar.isShown) locationErrorBar.show()
} else {
if (locationErrorBar.isShown) locationErrorBar.dismiss()
}
}
}