diff --git a/app/src/main/java/it/reyboz/bustorino/ActivityExperiments.java b/app/src/main/java/it/reyboz/bustorino/ActivityExperiments.java
index b2a91d0..2bcfeb3 100644
--- a/app/src/main/java/it/reyboz/bustorino/ActivityExperiments.java
+++ b/app/src/main/java/it/reyboz/bustorino/ActivityExperiments.java
@@ -1,93 +1,93 @@
/*
BusTO - Data components
Copyright (C) 2021 Fabio Mazza
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 .
*/
package it.reyboz.bustorino;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.ActionBar;
import androidx.fragment.app.FragmentTransaction;
import it.reyboz.bustorino.backend.Stop;
import it.reyboz.bustorino.fragments.*;
import it.reyboz.bustorino.middleware.GeneralActivity;
public class ActivityExperiments extends GeneralActivity implements CommonFragmentListener {
final static String DEBUG_TAG = "ExperimentsActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_container_fragment);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setIcon(R.drawable.ic_launcher);
}
if (savedInstanceState==null) {
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
/* .add(R.id.fragment_container_view, LinesDetailFragment.class,
LinesDetailFragment.Companion.makeArgs("gtt:4U"))
*/
//.add(R.id.fragment_container_view, LinesGridShowingFragment.class, null)
//.add(R.id.fragment_container_view, IntroFragment.class, IntroFragment.makeArguments(0))
//.commit();
//.add(R.id.fragment_container_view, LinesDetailFragment.class,
// LinesDetailFragment.Companion.makeArgs("gtt:4U"))
- .add(R.id.fragment_container_view, BackupImportFragment.class, null)
+ .add(R.id.fragment_container_view, MapLibreFragment.class, null)
.commit();
}
}
@Override
public void showFloatingActionButton(boolean yes) {
Log.d(DEBUG_TAG, "Asked to show the action button");
}
@Override
public void readyGUIfor(FragmentKind fragmentType) {
Log.d(DEBUG_TAG, "Asked to prepare the GUI for fragmentType "+fragmentType);
}
@Override
public void requestArrivalsForStopID(String ID) {
}
@Override
public void showMapCenteredOnStop(Stop stop) {
}
@Override
public void showLineOnMap(String routeGtfsId){
readyGUIfor(FragmentKind.LINES);
FragmentTransaction tr = getSupportFragmentManager().beginTransaction();
tr.replace(R.id.fragment_container_view, LinesDetailFragment.class,
LinesDetailFragment.Companion.makeArgs(routeGtfsId));
tr.addToBackStack("LineonMap-"+routeGtfsId);
tr.commit();
}
}
\ No newline at end of file
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
index 865476f..12cebde 100644
--- a/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
@@ -1,767 +1,142 @@
-/*
- BusTO - Fragments components
- Copyright (C) 2020 Andrea Ugo
- Copyright (C) 2021 Fabio Mazza
-
- 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 .
- */
package it.reyboz.bustorino.fragments
-import android.Manifest
-import android.animation.ObjectAnimator
-import android.annotation.SuppressLint
-import android.content.Context
-import android.location.LocationManager
import android.os.Bundle
-import android.util.Log
+import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.ImageButton
-import android.widget.Toast
-import androidx.activity.result.ActivityResultCallback
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.coordinatorlayout.widget.CoordinatorLayout
-import androidx.core.content.res.ResourcesCompat
-import androidx.lifecycle.ViewModelProvider
-import androidx.preference.PreferenceManager
import it.reyboz.bustorino.R
-import it.reyboz.bustorino.backend.Stop
-import it.reyboz.bustorino.backend.gtfs.LivePositionUpdate
-import it.reyboz.bustorino.backend.mato.MQTTMatoClient
-import it.reyboz.bustorino.backend.utils
-import it.reyboz.bustorino.data.gtfs.MatoPattern
-import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops
-import it.reyboz.bustorino.map.BusInfoWindow
-import it.reyboz.bustorino.map.CustomInfoWindow
-import it.reyboz.bustorino.map.CustomInfoWindow.TouchResponder
-import it.reyboz.bustorino.map.LocationOverlay
-import it.reyboz.bustorino.map.LocationOverlay.OverlayCallbacks
-import it.reyboz.bustorino.map.MarkerUtils
-import it.reyboz.bustorino.middleware.GeneralActivity
-import it.reyboz.bustorino.util.Permissions
-import it.reyboz.bustorino.viewmodels.LivePositionsViewModel
-import it.reyboz.bustorino.viewmodels.StopsMapViewModel
-import org.osmdroid.config.Configuration
-import org.osmdroid.events.DelayedMapListener
-import org.osmdroid.events.MapListener
-import org.osmdroid.events.ScrollEvent
-import org.osmdroid.events.ZoomEvent
-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.Marker
-import org.osmdroid.views.overlay.infowindow.InfoWindow
-import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider
-
-class MapLibreFragment : ScreenBaseFragment() {
- protected var listenerMain: FragmentListenerMain? = null
- private var shownStops: HashSet? = null
- private lateinit var map: MapView
- var ctx: Context? = null
- private lateinit var mLocationOverlay: LocationOverlay
- private lateinit var stopsFolderOverlay: FolderOverlay
- private var savedMapState: Bundle? = null
- protected lateinit var btCenterMap: ImageButton
- protected lateinit var btFollowMe: ImageButton
- protected var coordLayout: CoordinatorLayout? = null
- private var hasMapStartFinished = false
- private var followingLocation = false
+import org.maplibre.android.MapLibre
+import org.maplibre.android.camera.CameraPosition
+import org.maplibre.android.maps.MapView
+import org.maplibre.android.geometry.LatLng
+import org.maplibre.android.maps.MapLibreMap
+import org.maplibre.android.maps.OnMapReadyCallback
+
+
+// TODO: Rename parameter arguments, choose names that match
+// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+private const val ARG_PARAM1 = "param1"
+private const val ARG_PARAM2 = "param2"
+
+/**
+ * A simple [Fragment] subclass.
+ * Use the [MapLibreFragment.newInstance] factory method to
+ * create an instance of this fragment.
+ */
+class MapLibreFragment : Fragment(), OnMapReadyCallback {
+ // TODO: Rename and change types of parameters
+ //private var param1: String? = null
+ //private var param2: String? = null
+ // Declare a variable for MapView
+ private lateinit var mapView: MapView
+ protected var map: MapLibreMap? = null
- //the ViewModel from which we get the stop to display in the map
- private var stopsViewModel: StopsMapViewModel? = null
- //private GtfsPositionsViewModel gtfsPosViewModel; //= new ViewModelProvider(this).get(MapViewModel.class);
- private var livePositionsViewModel: LivePositionsViewModel? = null
- private var useMQTTViewModel = true
- private val busPositionMarkersByTrip = HashMap()
- private var busPositionsOverlay: FolderOverlay? = null
- private val tripMarkersAnimators = HashMap()
- protected val responder = TouchResponder { stopID, stopName ->
- if (listenerMain != null) {
- Log.d(DEBUG_TAG, "Asked to show arrivals for stop ID: $stopID")
- listenerMain!!.requestArrivalsForStopID(stopID)
- }
- }
- protected val locationCallbacks: OverlayCallbacks = object : OverlayCallbacks {
- override fun onDisableFollowMyLocation() {
- updateGUIForLocationFollowing(false)
- followingLocation = false
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ /*arguments?.let {
+ param1 = it.getString(ARG_PARAM1)
+ param2 = it.getString(ARG_PARAM2)
}
- override fun onEnableFollowMyLocation() {
- updateGUIForLocationFollowing(true)
- followingLocation = true
- }
+ */
+ MapLibre.getInstance(requireContext())
}
- private val positionRequestLauncher =
- registerForActivityResult, Map>(
- ActivityResultContracts.RequestMultiplePermissions(),
- ActivityResultCallback { result ->
- if (result == null) {
- Log.w(DEBUG_TAG, "Got asked permission but request is null, doing nothing?")
- } else if (java.lang.Boolean.TRUE == result[Manifest.permission.ACCESS_COARSE_LOCATION] && java.lang.Boolean.TRUE == result[Manifest.permission.ACCESS_FINE_LOCATION]) {
- map.overlays.remove(mLocationOverlay)
- startLocationOverlay(true, map)
- if (context == null || requireContext().getSystemService(Context.LOCATION_SERVICE) == null)
- return@ActivityResultCallback ///@registerForActivityResult
- val locationManager =
- requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
- @SuppressLint("MissingPermission") val userLocation =
- locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
- if (userLocation != null) {
- map!!.controller.setZoom(POSITION_FOUND_ZOOM)
- val startPoint = GeoPoint(userLocation)
- setLocationFollowing(true)
- map!!.controller.setCenter(startPoint)
- }
- } else Log.w(DEBUG_TAG, "No location permission")
- })
- //public static MapFragment getInstance(@NonNull Stop stop){
- // return getInstance(stop.getLatitude(), stop.getLongitude(), stop.getStopDisplayName(), stop.ID);
- //}
override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
+ inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- //use the same layout as the activity
- val root = inflater.inflate(R.layout.fragment_map, container, false)
- val context = requireContext()
- ctx = context.applicationContext
- Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(context))
- map = root.findViewById(R.id.map)
- map.setTileSource(TileSourceFactory.MAPNIK)
- //map.setTilesScaledToDpi(true);
- map.setFlingEnabled(true)
-
- // add ability to zoom with 2 fingers
- map.setMultiTouchControls(true)
- btCenterMap = root.findViewById(R.id.icon_center_map)
- btFollowMe = root.findViewById(R.id.icon_follow)
- coordLayout = root.findViewById(R.id.coord_layout)
+ // Inflate the layout for this fragment
+ val rootView = inflater.inflate(R.layout.fragment_map_libre, container, false)
- //setup FolderOverlay
- stopsFolderOverlay = FolderOverlay()
- //setup Bus Markers Overlay
- busPositionsOverlay = FolderOverlay()
- //reset shown bus updates
- busPositionMarkersByTrip.clear()
- tripMarkersAnimators.clear()
- //set map not done
- hasMapStartFinished = false
- val keySourcePositions = getString(R.string.pref_positions_source)
- useMQTTViewModel = PreferenceManager.getDefaultSharedPreferences(requireContext())
- .getString(keySourcePositions, SettingsFragment.LIVE_POSITIONS_PREF_MQTT_VALUE)
- .contentEquals(SettingsFragment.LIVE_POSITIONS_PREF_MQTT_VALUE)
-
-
- //Start map from bundle
- if (savedInstanceState != null) startMap(arguments, savedInstanceState) else startMap(
- arguments, savedMapState
- )
- //set listeners
- map.addMapListener(DelayedMapListener(object : MapListener {
- override fun onScroll(paramScrollEvent: ScrollEvent): Boolean {
- requestStopsToShow()
- //Log.d(DEBUG_TAG, "Scrolling");
- //if (moveTriggeredByCode) moveTriggeredByCode =false;
- //else setLocationFollowing(false);
- return true
- }
- override fun onZoom(event: ZoomEvent): Boolean {
- requestStopsToShow()
- return true
- }
- }))
- btCenterMap.setOnClickListener(View.OnClickListener { v: View? ->
- //Log.i(TAG, "centerMap clicked ");
- if (Permissions.bothLocationPermissionsGranted(context)) {
- val myPosition = mLocationOverlay!!.myLocation
- map.getController().animateTo(myPosition)
- } else Toast.makeText(context, R.string.enable_position_message_map, Toast.LENGTH_SHORT)
- .show()
- })
- btFollowMe.setOnClickListener(View.OnClickListener { v: View? ->
- //Log.i(TAG, "btFollowMe clicked ");
- if (Permissions.bothLocationPermissionsGranted(context)) setLocationFollowing(!followingLocation) else Toast.makeText(
- context, R.string.enable_position_message_map, Toast.LENGTH_SHORT
- )
- .show()
- })
- return root
- }
- override fun onAttach(context: Context) {
- super.onAttach(context)
- val provider = ViewModelProvider(this)
- //gtfsPosViewModel = provider.get(GtfsPositionsViewModel.class);
- livePositionsViewModel = provider.get(LivePositionsViewModel::class.java)
- stopsViewModel = provider.get(StopsMapViewModel::class.java)
- listenerMain = if (context is FragmentListenerMain) {
- context
- } else {
- throw RuntimeException(
- context.toString()
- + " must implement FragmentListenerMain"
- )
- }
- }
+ // Init layout view
- override fun onDetach() {
- super.onDetach()
- listenerMain = null
- //stop animations
+ // Init the MapView
+ mapView = rootView.findViewById(R.id.libreMapView)
+ mapView.getMapAsync(this) //{ //map ->
+ //map.setStyle("https://demotiles.maplibre.org/style.json") }
- // setupOnAttached = true;
- Log.w(DEBUG_TAG, "Fragment detached")
+ return rootView
}
- override fun onPause() {
- super.onPause()
- Log.w(DEBUG_TAG, "On pause called mapfrag")
- saveMapState()
- for (animator in tripMarkersAnimators.values) {
- if (animator != null && animator.isRunning) {
- animator.cancel()
+ override fun onMapReady(mapReady: MapLibreMap) {
+ this.map = mapReady
+ mapReady.cameraPosition = CameraPosition.Builder().target(LatLng(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON)).zoom(9.0).build()
+ activity?.run {
+ //TODO: copy from TransportR
+ val mapStyle = makeStyleUrl("jawg-terrain")
+ /*if (mapStyle != null && mapReady.style?.uri != mapStyle) {
+ mapReady.setStyle(mapStyle, ::onMapStyleLoaded) //callback
}
+ */
+ mapReady.setStyle(mapStyle)
}
- tripMarkersAnimators.clear()
- if (useMQTTViewModel) livePositionsViewModel!!.stopMatoUpdates()
}
- /**
- * Save the map state inside the fragment
- * (calls saveMapState(bundle))
- */
- private fun saveMapState() {
- savedMapState = Bundle()
- saveMapState(savedMapState!!)
- }
-
- /**
- * Save the state of the map to restore it to a later time
- * @param bundle the bundle in which to save the data
- */
- private fun saveMapState(bundle: Bundle) {
- Log.d(DEBUG_TAG, "Saving state, location following: $followingLocation")
- bundle.putBoolean(FOLLOWING_LOCAT_KEY, followingLocation)
- if (map == null) {
- //The map is null, it can happen?
- Log.e(DEBUG_TAG, "Cannot save map center, map is null")
- return
- }
- val loc = map!!.mapCenter
- bundle.putDouble(MAP_CENTER_LAT_KEY, loc.latitude)
- bundle.putDouble(MAP_CENTER_LON_KEY, loc.longitude)
- bundle.putDouble(MAP_CURRENT_ZOOM_KEY, map!!.zoomLevelDouble)
+ override fun onStart() {
+ super.onStart()
+ mapView.onStart()
}
override fun onResume() {
super.onResume()
- //TODO: cleanup duplicate code (maybe merging the positions classes?)
- if (listenerMain != null) listenerMain!!.readyGUIfor(FragmentKind.MAP)
- /// choose which to use
- val keySourcePositions = getString(R.string.pref_positions_source)
- useMQTTViewModel = PreferenceManager.getDefaultSharedPreferences(requireContext())
- .getString(keySourcePositions, SettingsFragment.LIVE_POSITIONS_PREF_MQTT_VALUE)
- .contentEquals(
- SettingsFragment.LIVE_POSITIONS_PREF_MQTT_VALUE
- )
- if (livePositionsViewModel != null) {
- //gtfsPosViewModel.requestUpdates();
- if (useMQTTViewModel) livePositionsViewModel!!.requestMatoPosUpdates(MQTTMatoClient.LINES_ALL)
- else livePositionsViewModel!!.requestGTFSUpdates()
- //mapViewModel.testCascade();
- livePositionsViewModel!!.isLastWorkResultGood.observe(this) { d: Boolean ->
- Log.d(
- DEBUG_TAG, "Last trip download result is $d"
- )
- }
- livePositionsViewModel!!.tripsGtfsIDsToQuery.observe(this) { dat: List ->
- Log.i(DEBUG_TAG, "Have these trips IDs missing from the DB, to be queried: $dat")
- livePositionsViewModel!!.downloadTripsFromMato(dat)
- }
- } /*else if(gtfsPosViewModel!=null){
- gtfsPosViewModel.requestUpdates();
- gtfsPosViewModel.getTripsGtfsIDsToQuery().observe(this, dat -> {
- Log.i(DEBUG_TAG, "Have these trips IDs missing from the DB, to be queried: "+dat);
- //gtfsPosViewModel.downloadTripsFromMato(dat);
- MatoTripsDownloadWorker.Companion.downloadTripsFromMato(dat,getContext().getApplicationContext(),
- "BusTO-MatoTripDownload");
- });
- }
- */ else Log.e(DEBUG_TAG, "livePositionsViewModel is null at onResume")
-
- //rerequest stop
- stopsViewModel!!.requestStopsInBoundingBox(map!!.boundingBox)
- }
-
- private fun startRequestsPositions() {
- if (livePositionsViewModel != null) {
- //should always be the case
- livePositionsViewModel!!.updatesWithTripAndPatterns.observe(viewLifecycleOwner) { data: HashMap> ->
- Log.d(
- DEBUG_TAG,
- "Have " + data.size + " trip updates, has Map start finished: " + hasMapStartFinished
- )
- if (hasMapStartFinished) updateBusPositionsInMap(data)
- if (!isDetached && !useMQTTViewModel) livePositionsViewModel!!.requestDelayedGTFSUpdates(
- 3000
- )
- }
- } else {
- Log.e(DEBUG_TAG, "PositionsViewModel is null")
- }
- }
-
- override fun onSaveInstanceState(outState: Bundle) {
- saveMapState(outState)
- super.onSaveInstanceState(outState)
- }
- //own methods
- /**
- * Switch following the location on and off
- * @param value true if we want to follow location
- */
- fun setLocationFollowing(value: Boolean) {
- followingLocation = value
- if (mLocationOverlay == null || context == null || map == null) //nothing else to do
- return
- if (value) {
- mLocationOverlay!!.enableFollowLocation()
- } else {
- mLocationOverlay!!.disableFollowLocation()
- }
- }
-
- /**
- * Do all the stuff you need to do on the gui, when parameter is changed to value
- * @param following value
- */
- protected fun updateGUIForLocationFollowing(following: Boolean) {
- if (following) btFollowMe!!.setImageResource(R.drawable.ic_follow_me_on) else btFollowMe!!.setImageResource(
- R.drawable.ic_follow_me
- )
- }
-
- /**
- * Build the location overlay. Enable only when
- * a) we know we have the permission
- * b) the location map is set
- */
- private fun startLocationOverlay(enableLocation: Boolean, map: MapView?) {
- checkNotNull(activity) { "Cannot enable LocationOverlay now" }
- // Location Overlay
- // from OpenBikeSharing (THANK GOD)
- Log.d(DEBUG_TAG, "Starting position overlay")
- val imlp = GpsMyLocationProvider(requireActivity().baseContext)
- imlp.locationUpdateMinDistance = 5f
- imlp.locationUpdateMinTime = 2000
- val overlay = LocationOverlay(imlp, map, locationCallbacks)
- if (enableLocation) overlay.enableMyLocation()
- overlay.isOptionsMenuEnabled = true
-
- //map.getOverlays().add(this.mLocationOverlay);
- mLocationOverlay = overlay
- map!!.overlays.add(mLocationOverlay)
- }
-
- fun startMap(incoming: Bundle?, savedInstanceState: Bundle?) {
- //Check that we're attached
- val activity = if (activity is GeneralActivity) activity as GeneralActivity? else null
- if (context == null || activity == null) {
- //we are not attached
- Log.e(DEBUG_TAG, "Calling startMap when not attached")
- return
- } else {
- Log.d(DEBUG_TAG, "Starting map from scratch")
- }
- //clear previous overlays
- map!!.overlays.clear()
-
-
- //parse incoming bundle
- var marker: GeoPoint? = null
- var name: String? = null
- var ID: String? = null
- var routesStopping: String? = ""
- if (incoming != null) {
- val lat = incoming.getDouble(BUNDLE_LATIT)
- val lon = incoming.getDouble(BUNDLE_LONGIT)
- marker = GeoPoint(lat, lon)
- name = incoming.getString(BUNDLE_NAME)
- ID = incoming.getString(BUNDLE_ID)
- routesStopping = incoming.getString(BUNDLE_ROUTES_STOPPING, "")
- }
-
-
- //ask for location permission
- if (!Permissions.bothLocationPermissionsGranted(activity)) {
- if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
- //TODO: show dialog for permission rationale
- Toast.makeText(activity, R.string.enable_position_message_map, Toast.LENGTH_SHORT)
- .show()
- }
- positionRequestLauncher.launch(Permissions.LOCATION_PERMISSIONS)
- }
- shownStops = HashSet()
- // move the map on the marker position or on a default view point: Turin, Piazza Castello
- // and set the start zoom
- val mapController = map!!.controller
- var startPoint: GeoPoint? = null
- startLocationOverlay(
- Permissions.bothLocationPermissionsGranted(activity),
- map
- )
- // set the center point
- if (marker != null) {
- //startPoint = marker;
- mapController.setZoom(POSITION_FOUND_ZOOM)
- setLocationFollowing(false)
- // put the center a little bit off (animate later)
- startPoint = GeoPoint(marker)
- startPoint.latitude = marker.latitude + utils.angleRawDifferenceFromMeters(20.0)
- startPoint.longitude = marker.longitude - utils.angleRawDifferenceFromMeters(20.0)
- //don't need to do all the rest since we want to show a point
- } else if (savedInstanceState != null && savedInstanceState.containsKey(MAP_CURRENT_ZOOM_KEY)) {
- mapController.setZoom(savedInstanceState.getDouble(MAP_CURRENT_ZOOM_KEY))
- mapController.setCenter(
- GeoPoint(
- savedInstanceState.getDouble(MAP_CENTER_LAT_KEY),
- savedInstanceState.getDouble(MAP_CENTER_LON_KEY)
- )
- )
- Log.d(
- DEBUG_TAG,
- "Location following from savedInstanceState: " + savedInstanceState.getBoolean(
- FOLLOWING_LOCAT_KEY
- )
- )
- setLocationFollowing(savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY))
- } else {
- Log.d(DEBUG_TAG, "No position found from intent or saved state")
- var found = false
- val locationManager =
- requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
- //check for permission
- if (Permissions.bothLocationPermissionsGranted(activity)) {
- @SuppressLint("MissingPermission") val userLocation =
- locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
- if (userLocation != null) {
- val distan = utils.measuredistanceBetween(
- userLocation.latitude, userLocation.longitude,
- DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON
- )
- if (distan < 100000.0) {
- mapController.setZoom(POSITION_FOUND_ZOOM)
- startPoint = GeoPoint(userLocation)
- found = true
- setLocationFollowing(true)
- }
- }
- }
- if (!found) {
- startPoint = GeoPoint(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON)
- mapController.setZoom(NO_POSITION_ZOOM)
- setLocationFollowing(false)
- }
- }
-
- // set the minimum zoom level
- map!!.minZoomLevel = 15.0
- //add contingency check (shouldn't happen..., but)
- if (startPoint != null) {
- mapController.setCenter(startPoint)
- }
-
-
- //add stops overlay
- //map.getOverlays().add(mLocationOverlay);
- map!!.overlays.add(stopsFolderOverlay)
- Log.d(DEBUG_TAG, "Requesting stops load")
- // This is not necessary, by setting the center we already move
- // the map and we trigger a stop request
- //requestStopsToShow();
- if (marker != null) {
- // make a marker with the info window open for the searched marker
- //TODO: make Stop Bundle-able
- val stopMarker = makeMarker(marker, ID, name, routesStopping, true)
- map!!.controller.animateTo(marker)
- }
- //add the overlays with the bus stops
- if (busPositionsOverlay == null) {
- //Log.i(DEBUG_TAG, "Null bus positions overlay,redo");
- busPositionsOverlay = FolderOverlay()
- }
- startRequestsPositions()
- if (stopsViewModel != null) {
- stopsViewModel!!.stopsInBoundingBox.observe(viewLifecycleOwner) { stops: List? ->
- showStopsMarkers(
- stops
- )
- }
- } else Log.d(DEBUG_TAG, "Cannot observe new stops in map, stopsViewModel is null")
- map!!.overlays.add(busPositionsOverlay)
- //set map as started
- hasMapStartFinished = true
- }
-
- /**
- * Start a request to load the stops that are in the current view
- * from the database
- */
- private fun requestStopsToShow() {
- // get the top, bottom, left and right screen's coordinate
- val bb = map!!.boundingBox
- Log.d(
- DEBUG_TAG,
- "Requesting stops in bounding box, stopViewModel is null " + (stopsViewModel == null)
- )
- if (stopsViewModel != null) {
- stopsViewModel!!.requestStopsInBoundingBox(bb)
- }
-
+ mapView.onResume()
}
- private fun updateBusMarker(
- marker: Marker?,
- posUpdate: LivePositionUpdate,
- justCreated: Boolean
- ) {
- val position: GeoPoint
- val updateID = posUpdate.tripID
- if (!justCreated) {
- position = marker!!.position
- if (posUpdate.latitude != position.latitude || posUpdate.longitude != position.longitude) {
- val newpos = GeoPoint(posUpdate.latitude, posUpdate.longitude)
- val valueAnimator = MarkerUtils.makeMarkerAnimator(
- map, marker, newpos, MarkerUtils.LINEAR_ANIMATION, 1200
- )
- valueAnimator.setAutoCancel(true)
- tripMarkersAnimators[updateID] = valueAnimator
- valueAnimator.start()
- }
- //marker.setPosition(new GeoPoint(posUpdate.getLatitude(), posUpdate.getLongitude()));
- } else {
- position = GeoPoint(posUpdate.latitude, posUpdate.longitude)
- marker!!.position = position
- }
- if (posUpdate.bearing != null) marker.rotation = posUpdate.bearing * -1f
- }
-
- private fun updateBusPositionsInMap(tripsPatterns: HashMap>) {
- Log.d(DEBUG_TAG, "Updating positions of the buses")
- //if(busPositionsOverlay == null) busPositionsOverlay = new FolderOverlay();
- val noPatternsTrips = ArrayList()
- for (tripID in tripsPatterns.keys) {
- val (update, tripWithPatternStops) = tripsPatterns[tripID] ?: continue
-
-
- //check if Marker is already created
- if (busPositionMarkersByTrip.containsKey(tripID)) {
- //need to change the position of the marker
- val marker = busPositionMarkersByTrip[tripID]!!
- updateBusMarker(marker, update, false)
- if (marker.infoWindow != null && marker.infoWindow is BusInfoWindow) {
- val window = marker.infoWindow as BusInfoWindow
- if (tripWithPatternStops != null) {
- //Log.d(DEBUG_TAG, "Update pattern for trip: "+tripID);
- window.setPatternAndDraw(tripWithPatternStops.pattern)
- }
- }
- } else {
- //marker is not there, need to make it
- if (map == null) Log.e(
- DEBUG_TAG,
- "Creating marker with null map, things will explode"
- )
- val marker = Marker(map)
-
- /*final Drawable mDrawable = DrawableUtils.Companion.getScaledDrawableResources(
- getResources(),
- R.drawable.point_heading_icon,
- R.dimen.map_icons_size, R.dimen.map_icons_size);
-
- */
- //String route = GtfsUtils.getLineNameFromGtfsID(update.getRouteID());
- val mdraw =
- ResourcesCompat.getDrawable(resources, R.drawable.map_bus_position_icon, null)!!
- //mdraw.setBounds(0,0,28,28);
- marker.icon = mdraw
- if (tripWithPatternStops == null) {
- noPatternsTrips.add(tripID)
- }
- var markerPattern: MatoPattern? = null
- if (tripWithPatternStops != null && tripWithPatternStops.pattern != null) markerPattern =
- tripWithPatternStops.pattern
- marker.infoWindow =
- BusInfoWindow(map!!, update, markerPattern, false) { pattern: MatoPattern? -> }
- marker.setInfoWindowAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
- marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
- updateBusMarker(marker, update, true)
- // the overlay is null when it's not attached yet?5
- // cannot recreate it because it becomes null very soon
- // if(busPositionsOverlay == null) busPositionsOverlay = new FolderOverlay();
- //save the marker
- if (busPositionsOverlay != null) {
- busPositionsOverlay!!.add(marker)
- busPositionMarkersByTrip[tripID] = marker
- }
- }
- }
- if (noPatternsTrips.size > 0) {
- Log.i(DEBUG_TAG, "These trips have no matching pattern: $noPatternsTrips")
- }
+ override fun onPause() {
+ super.onPause()
+ mapView.onPause()
}
- /**
- * Add stops as Markers on the map
- * @param stops the list of stops that must be included
- */
- protected fun showStopsMarkers(stops: List?) {
- if (context == null || stops == null) {
- //we are not attached
- return
- }
- var good = true
- for (stop in stops) {
- if (shownStops!!.contains(stop.ID)) {
- continue
- }
- if (stop.longitude == null || stop.latitude == null) continue
- shownStops!!.add(stop.ID)
- if (!map!!.isShown) {
- if (good) Log.d(
- DEBUG_TAG,
- "Need to show stop but map is not shown, probably detached already"
- )
- good = false
- continue
- } else if (map!!.repository == null) {
- Log.e(DEBUG_TAG, "Map view repository is null")
- }
- val marker = GeoPoint(stop.latitude!!, stop.longitude!!)
- val stopMarker = makeMarker(marker, stop, false)
- stopsFolderOverlay!!.add(stopMarker)
- if (!map!!.overlays.contains(stopsFolderOverlay)) {
- Log.w(DEBUG_TAG, "Map doesn't have folder overlay")
- }
- good = true
- }
- //Log.d(DEBUG_TAG,"We have " +stopsFolderOverlay.getItems().size()+" stops in the folderOverlay");
- //force redraw of markers
- map!!.invalidate()
+ override fun onStop() {
+ super.onStop()
+ mapView.onStop()
}
- fun makeMarker(geoPoint: GeoPoint?, stop: Stop, isStartMarker: Boolean): Marker {
- return makeMarker(
- geoPoint, stop.ID,
- stop.stopDefaultName,
- stop.routesThatStopHereToString(), isStartMarker
- )
+ override fun onLowMemory() {
+ super.onLowMemory()
+ mapView.onLowMemory()
}
- fun makeMarker(
- geoPoint: GeoPoint?, stopID: String?, stopName: String?,
- routesStopping: String?, isStartMarker: Boolean
- ): Marker {
-
- // add a marker
- val marker = Marker(map)
-
- // set custom info window as info window
- val popup = CustomInfoWindow(
- map, stopID, stopName, routesStopping,
- responder, R.layout.linedetail_stop_infowindow, R.color.red_darker
- )
- marker.infoWindow = popup
-
- // make the marker clickable
- marker.setOnMarkerClickListener { thisMarker: Marker, mapView: MapView? ->
- if (thisMarker.isInfoWindowOpen) {
- // on second click
- Log.w(DEBUG_TAG, "Pressed on the click marker")
- } else {
- // on first click
-
- // hide all opened info window
- InfoWindow.closeAllInfoWindowsOn(map)
- // show this particular info window
- thisMarker.showInfoWindow()
- // move the map to its position
- map!!.controller.animateTo(thisMarker.position)
- }
- true
- }
-
- // set its position
- marker.position = geoPoint
- marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
- // add to it an icon
- //marker.setIcon(getResources().getDrawable(R.drawable.bus_marker));
- marker.icon = ResourcesCompat.getDrawable(resources, R.drawable.bus_stop, ctx!!.theme)
- // add to it a title
- marker.title = stopName
- // set the description as the ID
- marker.snippet = stopID
-
- // show popup info window of the searched marker
- if (isStartMarker) {
- marker.showInfoWindow()
- //map.getController().animateTo(marker.getPosition());
- }
- return marker
+ override fun onDestroy() {
+ super.onDestroy()
+ mapView.onDestroy()
}
- override fun getBaseViewForSnackBar(): View? {
- return coordLayout
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ mapView.onSaveInstanceState(outState)
}
companion object {
- //private static final String TAG = "Busto-MapActivity";
- private const val MAP_CURRENT_ZOOM_KEY = "map-current-zoom"
- private const val MAP_CENTER_LAT_KEY = "map-center-lat"
- private const val MAP_CENTER_LON_KEY = "map-center-lon"
- private const val FOLLOWING_LOCAT_KEY = "following"
- const val BUNDLE_LATIT = "lat"
- const val BUNDLE_LONGIT = "lon"
- const val BUNDLE_NAME = "name"
- const val BUNDLE_ID = "ID"
- const val BUNDLE_ROUTES_STOPPING = "routesStopping"
- const val FRAGMENT_TAG = "BusTOMapFragment"
private const val DEFAULT_CENTER_LAT = 45.0708
private const val DEFAULT_CENTER_LON = 7.6858
private const val POSITION_FOUND_ZOOM = 18.3
+ private const val ACCESS_TOKEN="KxO8lF4U3kiO63m0c7lzqDCDrMUVg1OA2JVzRXxxmYSyjugr1xpe4W4Db5rFNvbQ"
const val NO_POSITION_ZOOM = 17.1
- private const val DEBUG_TAG = FRAGMENT_TAG
- val instance: MapLibreFragment
- get() = MapLibreFragment()
-
- fun getInstance(stop: Stop): MapLibreFragment {
- val fragment = MapLibreFragment()
- val args = Bundle()
- args.putDouble(BUNDLE_LATIT, stop.latitude!!)
- args.putDouble(BUNDLE_LONGIT, stop.longitude!!)
- args.putString(BUNDLE_NAME, stop.stopDisplayName)
- args.putString(BUNDLE_ID, stop.ID)
- args.putString(BUNDLE_ROUTES_STOPPING, stop.routesThatStopHereToString())
- fragment.arguments = args
- return fragment
- }
+ private const val MAPLIBRE_URL = "https://api.jawg.io/styles/"
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment MapLibreFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ @JvmStatic
+ fun newInstance(param1: String, param2: String) =
+ MapLibreFragment().apply {
+ arguments = Bundle().apply {
+ putString(ARG_PARAM1, param1)
+ putString(ARG_PARAM2, param2)
+ }
+ }
+ private fun makeStyleUrl(style: String = "jawg-streets") =
+ "${MAPLIBRE_URL+ style}.json?access-token=${ACCESS_TOKEN}"
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_map_libre.xml b/app/src/main/res/layout/fragment_map_libre.xml
new file mode 100644
index 0000000..deb298e
--- /dev/null
+++ b/app/src/main/res/layout/fragment_map_libre.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file