commit 0969b01f80a18bb9f43fae964c50cc054047b9d8 Author: Fabio Mazza Date: Tue Oct 13 18:33:58 2026 +0200 Refactor mapReady to bring it inside the GeneralMapLibreFragment diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt index 32737b9..4139886 100644 --- a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt @@ -646,7 +646,7 @@ class ArrivalsFragment : ResultBaseFragment(), LoaderManager.LoaderCallbacks { val args = arguments //if (args?.getString(KEY_STOP_ID) == null) throw diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt index f6c0542..6870aeb 100644 --- a/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt @@ -65,6 +65,7 @@ import it.reyboz.bustorino.backend.utils import it.reyboz.bustorino.data.PreferencesHolder import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops import it.reyboz.bustorino.map.MapLibreLocationEngine +import it.reyboz.bustorino.map.MapLibreStyles import it.reyboz.bustorino.map.MapLibreUtils import it.reyboz.bustorino.middleware.FusedNativeLocationProvider import it.reyboz.bustorino.util.PermissionsHelper @@ -366,22 +367,52 @@ abstract class GeneralMapLibreFragment: ScreenBaseFragment(), OnMapReadyCallback } } - protected fun reloadMap(){ - /*map?.let { - Log.d("GeneralMapFragment", "RELOADING MAP") - //save map state - savedMapStateOnPause = saveMapStateInBundle() - - onMapDestroy() - //Destroy and recreate MAP - mapView.onDestroy() - mapView.onCreate(null) - mapView.getMapAsync(this) + override fun onMapReady(mapReady: MapLibreMap) { + this.map = mapReady + val context = requireContext() + + // 1. Caricamento Stile (Comune) + val mjson = MapLibreStyles.getJsonStyleFromAsset(context, PreferencesHolder.getMapLibreStyleFile(context)) + val builder = Style.Builder().fromJson(mjson!!) + + mapReady.setStyle(builder) { style -> + mapStyle = style + addImagesStyle(style) + + // Gancio per layer e configurazioni specifiche dello stile + onStyleLoaded(mapReady, style) + + checkInitMapLocation(mapReady, style, context) } - */ + // 2. Setup Listeners (Comune + Specifici) + setupMapListenersOnInit(mapReady) + + // 4. Ripristino Camera / observe Buses + + mapInitialized = true + mapStateViewModel.mapInitOnce.set(true) + + onMapLibreInitialized(mapReady) + } + // --- Methods to implement in subclasses --- + /** + * Called when the map is loaded and the style is ready + */ + abstract fun onStyleLoaded(mapReady: MapLibreMap,style: Style) + + /** + * Called during the init setup of the map, separate method to add listeners to the map + */ + abstract fun setupMapListenersOnInit(mapReady: MapLibreMap) + + /** + * All things to do on the map different from listeners: listen to bus stops, bus positions updates... + */ + abstract fun onMapLibreInitialized(mapReady: MapLibreMap) + //For extra stuff to do when the map is destroyed abstract fun onMapDestroy() diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt index a97d5b8..6133419 100644 --- a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt @@ -161,11 +161,7 @@ class LinesDetailFragment() : GeneralMapLibreFragment() { //style and sources are in GeneralMapLibreFragment private lateinit var polylineSource: GeoJsonSource private lateinit var polyArrowSource: GeoJsonSource - - private var savedCameraPosition: CameraPosition? = null - private var lastStopsSizeShown = 0 - //BUS POSITIONS private var polyline: LineString? = null @@ -517,116 +513,93 @@ class LinesDetailFragment() : GeneralMapLibreFragment() { } // ------------- Map Code ------------------------- - /** - * This method sets up the map and the layers - */ - override fun onMapReady(mapReady: MapLibreMap) { - this.map = mapReady - - val context = requireContext() - val mjson = MapLibreStyles.getJsonStyleFromAsset(context, PreferencesHolder.getMapLibreStyleFile(context)) //ViewUtils.loadJsonFromAsset(requireContext(),"map_style_good.json") - var restoredMapState = false - activity?.run { - val builder = Style.Builder().fromJson(mjson!!) - mapReady.setStyle(builder) { style -> - addImagesStyle(style) + override fun onStyleLoaded(mapReady: MapLibreMap, style: Style) { - mapStyle = style - //setupLayers(style) + initPolylineStopsLayers(style, null) - //checkInitMapLocation(mapReady, style,requireContext()) + setupBusLayer(style) - //if(!stopsLayerStarted) - initPolylineStopsLayers(style, null) - - setupBusLayer(style) - - initSymbolManager(mapReady, style) - toRunWhenMapReady?.run() - toRunWhenMapReady = null - mapInitialized = true - - if(patternShown!=null){ - viewModel.stopsForPatternLiveData.value?.let { - Log.d(DEBUG_TAG, "Show stops from the cache") - displayPatternWithStopsOnMap(patternShown!!, it, true) - //Show stop from cache - mapStateViewModel.lastOpenStopID.value?.let{ sID-> - val s= it.filter { stop -> stop.ID==sID } - if (s.isEmpty()) { - if(sID.isNotEmpty()) - Log.w(DEBUG_TAG,"Wanted to open stop $sID in map but it was not loaded!") - } - else openStopInBottomSheet(s[0]) + initSymbolManager(mapReady, style) + if(!mapStateViewModel.mapInitOnce.get() || mapStateViewModel.locationUserActive.value == true) + checkInitMapLocation(mapReady, style, requireContext()) + } - } + override fun setupMapListenersOnInit(mapReady: MapLibreMap) { + mapReady.addOnMapClickListener { point -> + val screenPoint = mapReady.projection.toScreenLocation(point) + val stopsNearby = mapReady.queryRenderedFeatures(screenPoint, STOPS_LAYER_ID) + val busNearby = mapReady.queryRenderedFeatures(screenPoint, BUSES_LAYER_ID) + //Log.d(DEBUG_TAG, "onMapClick, stopsNearby: $stopsNearby \nstopShown: $shownStopInBottomSheet \nbusNearby: $busNearby,") + + if (stopsNearby.isNotEmpty()) { + val feature = stopsNearby[0] + val id = feature.getStringProperty("id") + val stop = viewModel.getStopByID(id) + stop?.let { + if (isBottomSheetShowing()) { + hideStopOrBusBottomSheet() } + openStopInBottomSheet(it) - + //move camera + if(it.latitude!=null && it.longitude!=null) + mapReady.animateCamera(CameraUpdateFactory.newLatLng(LatLng(it.latitude!!,it.longitude!!)),750) } - restoredMapState = mapStateViewModel.restoreMapState(mapReady) - arguments?.let { args -> - // if there is a Camera State in the arguments, set it for the new camera (doesn't work yet!) - if (!restoredMapState && MapCameraState.checkInBundle(args)) { - val initCamState = MapCameraState.fromBundle(args) - //map?.let{ - MapStateViewModel.restoreMapState(mapReady, initCamState) - restoredMapState = true + return@addOnMapClickListener true + } else if (busNearby.isNotEmpty()){ + val feature = busNearby[0] + openBusFromMapClick(feature) - } - } - restoredCameraInMap = restoredMapState - Log.d(DEBUG_TAG, "Restored map state: $restoredMapState") - if(!mapStateViewModel.mapInitOnce.get() || mapStateViewModel.locationUserActive.value == true) - checkInitMapLocation(mapReady, style, context) + return@addOnMapClickListener true } + false + } + } - mapReady.addOnMapClickListener { point -> - val screenPoint = mapReady.projection.toScreenLocation(point) - val stopsNearby = mapReady.queryRenderedFeatures(screenPoint, STOPS_LAYER_ID) - val busNearby = mapReady.queryRenderedFeatures(screenPoint, BUSES_LAYER_ID) - //Log.d(DEBUG_TAG, "onMapClick, stopsNearby: $stopsNearby \nstopShown: $shownStopInBottomSheet \nbusNearby: $busNearby,") - - if (stopsNearby.isNotEmpty()) { - val feature = stopsNearby[0] - val id = feature.getStringProperty("id") - val stop = viewModel.getStopByID(id) - stop?.let { - if (isBottomSheetShowing()) { - hideStopOrBusBottomSheet() - } - openStopInBottomSheet(it) + override fun onMapLibreInitialized(mapReady: MapLibreMap) { + toRunWhenMapReady?.run() + toRunWhenMapReady = null - //move camera - if(it.latitude!=null && it.longitude!=null) - mapReady.animateCamera(CameraUpdateFactory.newLatLng(LatLng(it.latitude!!,it.longitude!!)),750) - } - return@addOnMapClickListener true - } else if (busNearby.isNotEmpty()){ - val feature = busNearby[0] - openBusFromMapClick(feature) + observeBusPositionUpdates() + + if(patternShown!=null){ + viewModel.stopsForPatternLiveData.value?.let { + Log.d(DEBUG_TAG, "Show stops from the cache") + displayPatternWithStopsOnMap(patternShown!!, it, true) + //Show stop from cache + mapStateViewModel.lastOpenStopID.value?.let { sID -> + val s = it.filter { stop -> stop.ID == sID } + if (s.isEmpty()) { + if (sID.isNotEmpty()) + Log.w(DEBUG_TAG, "Wanted to open stop $sID in map but it was not loaded!") + } else openStopInBottomSheet(s[0]) - return@addOnMapClickListener true } - false } - - // we start requesting the bus positions now - observeBusPositionUpdates() - } - val zoom = 12.0 - val latlngTarget = LatLng(MapLibreFragment.DEFAULT_CENTER_LAT, MapLibreFragment.DEFAULT_CENTER_LON) - if(!restoredMapState) - mapReady.cameraPosition = savedCameraPosition ?:CameraPosition.Builder().target(latlngTarget).zoom(zoom).build() + var restoredMapState = false - savedCameraPosition = null + restoredMapState = mapStateViewModel.restoreMapState(mapReady) + arguments?.let { args -> + // if there is a Camera State in the arguments, set it for the new camera (doesn't work yet!) + if (!restoredMapState && MapCameraState.checkInBundle(args)) { + val initCamState = MapCameraState.fromBundle(args) + //map?.let{ + MapStateViewModel.restoreMapState(mapReady, initCamState) + restoredMapState = true - //if(mapStateViewModel.locationUserActive.value == true) - // mapReady.style?.let{ checkInitMapLocation(mapReady,it, context)} - mapStateViewModel.mapInitOnce.set(true) + } + } + restoredCameraInMap = restoredMapState + Log.d(DEBUG_TAG, "Restored map state: $restoredMapState") + + if(!restoredMapState) { + val zoom = 12.0 + val latlngTarget = LatLng(MapLibreFragment.DEFAULT_CENTER_LAT, MapLibreFragment.DEFAULT_CENTER_LON) + mapReady.cameraPosition = CameraPosition.Builder().target(latlngTarget).zoom(zoom).build() + } } override fun showOpenStopWithSymbolLayer(): Boolean { 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 cd15477..74fee9d 100644 --- a/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt @@ -38,10 +38,8 @@ 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.data.PreferencesHolder import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops import it.reyboz.bustorino.map.MapLibreLocationEngine -import it.reyboz.bustorino.map.MapLibreStyles import it.reyboz.bustorino.viewmodels.StopsMapViewModel import org.maplibre.android.camera.CameraPosition import org.maplibre.android.camera.CameraUpdateFactory @@ -175,21 +173,6 @@ class MapLibreFragment : GeneralMapLibreFragment() { setFollowUserLocation(!followingUserLocation) } } - //locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager - /* - if (Permissions.bothLocationPermissionsGranted(requireContext()) && deviceHasGpsProvider()) { - - requestInitialUserLocation() - } else{ - 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() - } - // PERMISSIONS REQUESTED AFTER MAP SETUP - } - - */ // Setup close button rootView.findViewById(R.id.btnClose).setOnClickListener { hideStopOrBusBottomSheet() @@ -243,35 +226,18 @@ class MapLibreFragment : GeneralMapLibreFragment() { } - /** - * This method sets up the map and the layers - */ - override fun onMapReady(mapReady: MapLibreMap) { - this.map = mapReady - val context = requireContext() - val mjson = MapLibreStyles.getJsonStyleFromAsset(context, PreferencesHolder.getMapLibreStyleFile(context)) - - val builder = Style.Builder().fromJson(mjson!!) - - mapReady.setStyle(builder) { style -> - mapStyle = style - //setupLayers(style) - addImagesStyle(style) - - //init stop layer with this - val stopsInCache = stopsViewModel.stopsToShow.value - if(stopsInCache.isNullOrEmpty()) initStopsLayer(style, null) - else displayStops(stopsInCache) - - if(showBusLayer) setupBusLayer(style, withLabels = true, busIconsScale = 1.2f) + override fun onStyleLoaded(mapReady: MapLibreMap,style: Style) { + //init stop layer with this + val stopsInCache = stopsViewModel.stopsToShow.value + if(stopsInCache.isNullOrEmpty()) initStopsLayer(style, null) + else displayStops(stopsInCache) - // Start observing data now that everything is set up - observeStops() - - checkInitMapLocation(mapReady,style, context) - } + if(showBusLayer) setupBusLayer(style, withLabels = true, busIconsScale = 1.2f) + checkInitMapLocation(mapReady,style, requireContext()) + } + override fun setupMapListenersOnInit(mapReady: MapLibreMap) { mapReady.addOnCameraIdleListener { map?.let { val newBbox = it.projection.visibleRegion.latLngBounds @@ -289,12 +255,14 @@ class MapLibreFragment : GeneralMapLibreFragment() { } mapReady.addOnMapClickListener { point -> - onMapClickReact(point) + onMapClickReact(point) } - // we start requesting the bus positions now - observeBusPositionUpdates() + } - //Restoring data + override fun onMapLibreInitialized(mapReady: MapLibreMap) { + // Start observing data now that everything is set up + observeStops() + observeBusPositionUpdates() if (initialStopToShow!=null && initialStopToShow?.hasCoords() == true){ val s = initialStopToShow!! @@ -309,15 +277,15 @@ class MapLibreFragment : GeneralMapLibreFragment() { //restore the map state here map?.let{ boundsRestored = mapStateViewModel.restoreMapState(it) - mapStateViewModel.lastOpenStopID.value?.let{ sID-> - val s= stopsViewModel.getStopByID(sID) - if (s==null) { - if(sID.isNotEmpty()) - Log.w(DEBUG_TAG,"Wanted to open stop $sID in map but it was not loaded!") - } - else{ - openStopInBottomSheet(s) } - } + mapStateViewModel.lastOpenStopID.value?.let{ sID-> + val s= stopsViewModel.getStopByID(sID) + if (s==null) { + if(sID.isNotEmpty()) + Log.w(DEBUG_TAG,"Wanted to open stop $sID in map but it was not loaded!") + } + else{ + openStopInBottomSheet(s) } + } } if(!boundsRestored){ @@ -326,20 +294,14 @@ class MapLibreFragment : GeneralMapLibreFragment() { val defaultLoc = LatLng(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON) val proposedLoc = lastLoc?.let{ LatLng(lastLoc.latitude, lastLoc.longitude)} val targetLoc = if(proposedLoc == null || proposedLoc.distanceTo(defaultLoc) > MAX_DIST_KM*1000) - defaultLoc - else proposedLoc + defaultLoc + else proposedLoc mapReady.cameraPosition = CameraPosition.Builder().target(targetLoc).zoom(DEFAULT_ZOOM).build() } restoredMapCamera.set(boundsRestored) - - } - mapInitialized = true - - //pendingLocationActivation = true - //positionRequestLauncher.launch(Permissions.LOCATION_PERMISSIONS) }