diff --git a/app/build.gradle b/app/build.gradle --- a/app/build.gradle +++ b/app/build.gradle @@ -4,14 +4,14 @@ android { - compileSdk 34 + compileSdk 35 namespace "it.reyboz.bustorino" defaultConfig { applicationId "it.reyboz.bustorino" minSdkVersion 21 - targetSdkVersion 34 - buildToolsVersion = '34.0.0' + targetSdkVersion 35 + buildToolsVersion = '35.0.1' versionCode 62 versionName "2.3.1" vectorDrawables.useSupportLibrary = true @@ -65,6 +65,10 @@ androidResources { generateLocaleConfig true } + + buildFeatures{ + buildConfig = true + } } dependencies { @@ -114,8 +118,7 @@ implementation 'com.google.protobuf:protobuf-java:3.19.6' // mqtt library implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5' - implementation 'com.github.fabmazz:paho.mqtt.android:v1.0.0' - + implementation 'com.github.hannesa2:paho.mqtt.android:4.4' // ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" // LiveData diff --git a/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java b/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java --- a/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java +++ b/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java @@ -24,6 +24,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.Gravity; @@ -39,6 +40,7 @@ import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.view.GravityCompat; +import androidx.core.view.ViewCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -84,6 +86,10 @@ super.onCreate(savedInstanceState); Log.d(DEBUG_TAG, "onCreate, savedInstanceState is: "+savedInstanceState); setContentView(R.layout.activity_principal); + /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + getWindow().setNavigationBarContrastEnforced(false); + } + */ boolean showingArrivalsFromIntent = false; Toolbar mToolbar = findViewById(R.id.default_toolbar); @@ -94,7 +100,6 @@ mToolbar.setOnMenuItemClickListener(new ToolbarItemClickListener(this)); - mDrawer = findViewById(R.id.drawer_layout); drawerToggle = setupDrawerToggle(mToolbar); diff --git a/app/src/main/java/it/reyboz/bustorino/ActivitySettings.java b/app/src/main/java/it/reyboz/bustorino/ActivitySettings.java --- a/app/src/main/java/it/reyboz/bustorino/ActivitySettings.java +++ b/app/src/main/java/it/reyboz/bustorino/ActivitySettings.java @@ -1,6 +1,7 @@ package it.reyboz.bustorino; import android.os.Bundle; +import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.appcompat.app.ActionBar; @@ -14,10 +15,11 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); - + Toolbar mToolbar = findViewById(R.id.default_toolbar); + setSupportActionBar(mToolbar); ActionBar ab = getSupportActionBar(); if(ab!=null) { - ab.setIcon(R.drawable.ic_launcher); + //ab.setIcon(R.drawable.ic_launcher); ab.setDisplayHomeAsUpEnabled(true); } else { Log.e("SETTINGS_ACTIV","ACTION BAR IS NULL"); diff --git a/app/src/main/java/it/reyboz/bustorino/backend/mato/MQTTMatoClient.kt b/app/src/main/java/it/reyboz/bustorino/backend/mato/MQTTMatoClient.kt --- a/app/src/main/java/it/reyboz/bustorino/backend/mato/MQTTMatoClient.kt +++ b/app/src/main/java/it/reyboz/bustorino/backend/mato/MQTTMatoClient.kt @@ -143,23 +143,27 @@ fun stopMatoRequests(responder: MQTTMatoListener){ var removed = false - for ((line,v)in respondersMap.entries){ + for ((linekey,responderList)in respondersMap.entries){ var done = false - for (el in v){ + for (el in responderList){ if (el.get()==null){ - v.remove(el) + responderList.remove(el) } else if(el.get() == responder){ - v.remove(el) + responderList.remove(el) done = true } if (done) break } - if(done) Log.d(DEBUG_TAG, "Removed one listener for line $line, listeners: $v") + if(done) Log.d(DEBUG_TAG, "Removed one listener for line $linekey, listeners: $responderList") //if (done) break - if (v.isEmpty()){ + if (responderList.isEmpty()){ //actually unsubscribe - client?.unsubscribe( mapTopic(line)) + try { + client?.unsubscribe(mapTopic(linekey)) + } catch (e: Exception){ + Log.e(DEBUG_TAG, "Tried unsubscribing but there was an error in the client library:\n$e") + } } removed = done || removed } diff --git a/app/src/main/java/it/reyboz/bustorino/data/MatoPatternsDownloadWorker.kt b/app/src/main/java/it/reyboz/bustorino/data/MatoPatternsDownloadWorker.kt --- a/app/src/main/java/it/reyboz/bustorino/data/MatoPatternsDownloadWorker.kt +++ b/app/src/main/java/it/reyboz/bustorino/data/MatoPatternsDownloadWorker.kt @@ -86,7 +86,7 @@ Log.d(DEBUG_TAG, "Request to download and insert patterns for ${routesIds.size} routes, proceed: $runNewWork, workstate: $addDat") if(runNewWork){ - val routeIdsArray = routesIds.toTypedArray() + val routeIdsArray: Array = routesIds.toTypedArray() val dataBuilder = Data.Builder().putStringArray(ROUTES_KEYS,routeIdsArray) val requ = OneTimeWorkRequest.Builder(MatoPatternsDownloadWorker::class.java) diff --git a/app/src/main/java/it/reyboz/bustorino/data/MatoTripsDownloadWorker.kt b/app/src/main/java/it/reyboz/bustorino/data/MatoTripsDownloadWorker.kt --- a/app/src/main/java/it/reyboz/bustorino/data/MatoTripsDownloadWorker.kt +++ b/app/src/main/java/it/reyboz/bustorino/data/MatoTripsDownloadWorker.kt @@ -125,7 +125,7 @@ null else info[0].state Log.d(debugTag, "Request to download and insert ${trips.size} trips, proceed: $runNewWork, workstate: $addDat") if(runNewWork) { - val tripsArr = trips.toTypedArray() + val tripsArr: Array = trips.toTypedArray() val dataBuilder = Data.Builder().putStringArray(TRIPS_KEYS, tripsArr) //build() val requ = OneTimeWorkRequest.Builder(MatoTripsDownloadWorker::class.java) diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt @@ -6,7 +6,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.preference.PreferenceManager import com.google.gson.JsonObject import it.reyboz.bustorino.backend.Stop import it.reyboz.bustorino.data.PreferencesHolder @@ -76,6 +75,7 @@ } } + @Deprecated("Deprecated in Java") override fun onLowMemory() { super.onLowMemory() mapView.onLowMemory() @@ -104,25 +104,32 @@ //For extra stuff to do when the map is destroyed abstract fun onMapDestroy() - protected fun restoreMapStateFromBundle(bundle: Bundle){ + protected fun restoreMapStateFromBundle(bundle: Bundle): Boolean{ val nullDouble = -10_000.0 - val latCenter = bundle.getDouble("center_map_lat", -10.0) - val lonCenter = bundle.getDouble("center_map_lon",-10.0) - val zoom = bundle.getDouble("map_zoom", -10.0) + var boundsRestored =false + val latCenter = bundle.getDouble("center_map_lat", nullDouble) + val lonCenter = bundle.getDouble("center_map_lon",nullDouble) + val zoom = bundle.getDouble("map_zoom", nullDouble) val bearing = bundle.getDouble("map_bearing", nullDouble) val tilt = bundle.getDouble("map_tilt", nullDouble) - if(lonCenter>=0 &&latCenter>=0) map?.let { - val newPos = CameraPosition.Builder().target(LatLng(latCenter,lonCenter)) + if(lonCenter!=nullDouble &&latCenter!=nullDouble) map?.let { + val center = LatLng(latCenter, lonCenter) + val newPos = CameraPosition.Builder().target(center) if(zoom>0) newPos.zoom(zoom) if(bearing!=nullDouble) newPos.bearing(bearing) if(tilt != nullDouble) newPos.tilt(tilt) it.cameraPosition=newPos.build() + Log.d(DEBUG_TAG, "Restored map state from Bundle, center: $center, zoom: $zoom, bearing $bearing, tilt $tilt") + boundsRestored =true + } else{ + Log.d(DEBUG_TAG, "Not restoring map state, center: $latCenter,$lonCenter; zoom: $zoom, bearing: $bearing, tilt $tilt") } val mStop = bundle.getBundle("shown_stop")?.let { Stop.fromBundle(it) } mStop?.let { openStopInBottomSheet(it) } + return boundsRestored } protected fun saveMapStateBeforePause(bundle: Bundle){ @@ -136,6 +143,10 @@ it.cameraPosition.zoom.let { z-> bundle.putDouble("map_zoom",z) } bundle.putDouble("map_bearing",cp.bearing) bundle.putDouble("map_tilt", cp.tilt) + + val locationComponent = it.locationComponent + bundle.putBoolean(KEY_LOCATION_ENABLED,locationComponent.isLocationComponentEnabled) + bundle.putParcelable("last_location", locationComponent.lastKnownLocation) } shownStopInBottomSheet?.let { bundle.putBundle("shown_stop", it.toBundle()) @@ -167,5 +178,7 @@ const val SEL_STOP_SOURCE="selected-stop-source" const val SEL_STOP_LAYER = "selected-stop-layer" + + const val KEY_LOCATION_ENABLED="location_enabled" } } \ 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 --- a/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt @@ -95,7 +95,7 @@ // Sources for stops and buses are in GeneralMapLibreFragment - + private var isUserMovingCamera = false private var stopsLayerStarted = false private var lastStopsSizeShown = 0 private var lastBBox = LatLngBounds.from(2.0, 2.0, 1.0,1.0) @@ -122,25 +122,32 @@ private var pendingLocationActivation = false private var ignoreCameraMovementForFollowing = true private var enablingPositionFromClick = false - private val positionRequestLauncher = - registerForActivityResult, Map>( - ActivityResultContracts.RequestMultiplePermissions(), - ActivityResultCallback { result -> + 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(!pendingLocationActivation){ + /// SHOULD DO NOTHING HERE + Log.d(DEBUG_TAG, "Requested location but now there is no pendingLocationActivation") } else if (java.lang.Boolean.TRUE == result[Manifest.permission.ACCESS_COARSE_LOCATION] && java.lang.Boolean.TRUE == result[Manifest.permission.ACCESS_FINE_LOCATION]) { // We can use the position, restart location overlay Log.d(DEBUG_TAG, "HAVE THE PERMISSIONS") 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) { - if(LatLng(userLocation.latitude, userLocation.longitude).distanceTo(DEFAULT_LATLNG) >= MAX_DIST_KM*1000){ + val locationManager = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager + var lastLoc = stopsViewModel.lastUserLocation + @SuppressLint("MissingPermission") + if(lastLoc==null) lastLoc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) + else Log.d(DEBUG_TAG, "Got last location from cache") + + if (lastLoc != null) { + if(LatLng(lastLoc.latitude, lastLoc.longitude).distanceTo(DEFAULT_LATLNG) <= MAX_DIST_KM*1000){ + Log.d(DEBUG_TAG, "Showing the user position") setMapLocationEnabled(true, true, false) + } else{ + setMapLocationEnabled(false, false,false) + context?.let{Toast.makeText(it,R.string.too_far_not_showing_location, Toast.LENGTH_SHORT).show()} } } else requestInitialUserLocation() @@ -268,7 +275,6 @@ Toast.makeText(activity, R.string.enable_position_message_map, Toast.LENGTH_SHORT) .show() } - positionRequestLauncher.launch(Permissions.LOCATION_PERMISSIONS) } @@ -292,82 +298,94 @@ val mjson = Styles.getJsonStyleFromAsset(context, PreferencesHolder.getMapLibreStyleFile(context)) //ViewUtils.loadJsonFromAsset(requireContext(),"map_style_good.json") - activity?.run { - val builder = Style.Builder().fromJson(mjson!!) - mapReady.setStyle(builder) { style -> + val builder = Style.Builder().fromJson(mjson!!) - mapStyle = style - //setupLayers(style) + mapReady.setStyle(builder) { style -> - // Start observing data - observeStops() - initMapLocation(style, mapReady, requireContext()) - //init stop layer with this - val stopsInCache = stopsViewModel.getAllStopsLoaded() - if(stopsInCache.isEmpty()) - initStopsLayer(style, FeatureCollection.fromFeatures(ArrayList())) - else - displayStops(stopsInCache) - if(showBusLayer) setupBusLayer(style) + mapStyle = style + //setupLayers(style) + // Start observing data + observeStops() + initMapLocation(style, mapReady, requireContext()) + //init stop layer with this + val stopsInCache = stopsViewModel.getAllStopsLoaded() + if(stopsInCache.isEmpty()) + initStopsLayer(style, FeatureCollection.fromFeatures(ArrayList())) + else + displayStops(stopsInCache) + if(showBusLayer) setupBusLayer(style) - /*symbolManager = SymbolManager(mapView,mapReady,style, null, "symbol-transit-airfield") - symbolManager.iconAllowOverlap = true - symbolManager.textAllowOverlap = false - symbolManager.textIgnorePlacement =true + /*symbolManager = SymbolManager(mapView,mapReady,style, null, "symbol-transit-airfield") + symbolManager.iconAllowOverlap = true + symbolManager.textAllowOverlap = false + symbolManager.textIgnorePlacement =true - */ - /*symbolManager.addClickListener{ _ -> - if (stopActiveSymbol!=null){ - hideStopBottomSheet() - - return@addClickListener true - } else - return@addClickListener false - } - */ + */ + /*symbolManager.addClickListener{ _ -> + if (stopActiveSymbol!=null){ + hideStopBottomSheet() + return@addClickListener true + } else + return@addClickListener false } - mapReady.addOnCameraIdleListener { - map?.let { - val newBbox = it.projection.visibleRegion.latLngBounds - if ((newBbox.center==lastBBox.center) && (newBbox.latitudeSpan==lastBBox.latitudeSpan) && (newBbox.longitudeSpan==lastBBox.latitudeSpan)){ - //do nothing - } else { - stopsViewModel.loadStopsInLatLngBounds(newBbox) - lastBBox = newBbox + */ - } + } - } - } - mapReady.addOnCameraMoveStartedListener { + mapReady.addOnCameraIdleListener { + isUserMovingCamera = false + map?.let { + val newBbox = it.projection.visibleRegion.latLngBounds + if ((newBbox.center==lastBBox.center) && (newBbox.latitudeSpan==lastBBox.latitudeSpan) && (newBbox.longitudeSpan==lastBBox.latitudeSpan)){ + //do nothing + } else { + stopsViewModel.loadStopsInLatLngBounds(newBbox) + lastBBox = newBbox - map?.let { setFollowingUser(it.locationComponent.cameraMode == CameraMode.TRACKING) } - //setFollowingUser() + } } - mapReady.addOnMapClickListener { point -> - onMapClickReact(point) + } + mapReady.addOnCameraMoveStartedListener { v-> + if(v== MapLibreMap.OnCameraMoveStartedListener.REASON_API_GESTURE){ + //the user is moving the map + isUserMovingCamera = true } + map?.let { setFollowingUser(it.locationComponent.cameraMode == CameraMode.TRACKING) } + //setFollowingUser() - mapInitCompleted = true - // we start requesting the bus positions now - startRequestingPositions() } - savedMapStateOnPause?.let{ - restoreMapStateFromBundle(it) - pendingLocationActivation = false - Log.d(DEBUG_TAG, "Restored map state from the saved bundle") + + mapReady.addOnMapClickListener { point -> + onMapClickReact(point) } + + mapInitCompleted = true + // we start requesting the bus positions now + startRequestingPositions() + + //Restoring data + var boundsRestored = false + pendingLocationActivation = true + stopsViewModel.savedState?.let{ + boundsRestored = restoreMapStateFromBundle(it) + //why are we disabling it? + pendingLocationActivation = it.getBoolean(KEY_LOCATION_ENABLED,true) + Log.d(DEBUG_TAG, "Restored map state from the saved bundle: ") + } + if(pendingLocationActivation) + positionRequestLauncher.launch(Permissions.LOCATION_PERMISSIONS) + //reset saved State at the end - if( savedMapStateOnPause == null) { + if((!boundsRestored)) { //set initial position val zoom = 15.0 //center position @@ -377,7 +395,7 @@ mapReady.cameraPosition = CameraPosition.Builder().target(latlngTarget).zoom(zoom).build() } //reset saved state - savedMapStateOnPause = null + stopsViewModel.savedState = null } private fun onMapClickReact(point: LatLng): Boolean{ @@ -584,6 +602,13 @@ override fun onStart() { super.onStart() mapView.onStart() + + //restore state from viewModel + stopsViewModel.savedState?.let { + restoreMapStateFromBundle(it) + //reset state + stopsViewModel.savedState = null + } } override fun onResume() { @@ -611,6 +636,8 @@ } fragmentListener?.readyGUIfor(FragmentKind.MAP) + //restore saved state + savedMapStateOnPause?.let { restoreMapStateFromBundle(it) } } override fun onPause() { @@ -631,6 +658,11 @@ mapView.onSaveInstanceState(it) it } + //save last location + map?.locationComponent?.lastKnownLocation?.let{ + stopsViewModel.lastUserLocation = it + } + } @@ -816,8 +848,8 @@ val samePosition = oldPos?.let { (oldPos.latitude==pos.latitude)&&(oldPos.longitude == pos.longitude) }?:false if(!samePosition) { val isPositionInBounds = isInsideVisibleRegion( - pos.latitude, pos.longitude, true - ) || (oldPos?.let { isInsideVisibleRegion(it.latitude,it.longitude,true) } ?: false) + pos.latitude, pos.longitude, false + ) || (oldPos?.let { isInsideVisibleRegion(it.latitude,it.longitude, false) } ?: false) if (isPositionInBounds) { //animate = true //this moves both the icon and the label @@ -940,7 +972,9 @@ private fun updatePositionsIcons(){ //avoid frequent updates val currentTime = System.currentTimeMillis() - if(currentTime - lastUpdateTime < 60){ + //throttle updates when user is moving camera + val interval = if(isUserMovingCamera) 150 else 60 + if(currentTime - lastUpdateTime < interval){ //DO NOT UPDATE THE MAP return } @@ -984,7 +1018,6 @@ //provider.let { setLocationIconEnabled(true) Toast.makeText(requireContext(), R.string.position_searching_message, Toast.LENGTH_SHORT).show() - pendingLocationActivation = true locationManager.requestSingleUpdate(provider, object : LocationListener { override fun onLocationChanged(location: Location) { val userLatLng = LatLng(location.latitude, location.longitude) @@ -997,7 +1030,8 @@ setMapLocationEnabled(true, true, false) } } else { - Toast.makeText(context, "You are too far, not showing the position", Toast.LENGTH_SHORT).show() + Toast.makeText(context, R.string.too_far_not_showing_location, Toast.LENGTH_SHORT).show() + setMapLocationEnabled(false,false, false) } } @@ -1042,7 +1076,7 @@ val permissionOk = assumePermissions || Permissions.bothLocationPermissionsGranted(requireContext()) if (permissionOk) { - Log.d(DEBUG_TAG, "Permission OK, starting location component, assumed: $assumePermissions") + Log.d(DEBUG_TAG, "Permission OK, starting location component, assumed: $assumePermissions, fromClick: $fromClick") locationComponent.isLocationComponentEnabled = true if (initialStopToShow==null) { locationComponent.cameraMode = CameraMode.TRACKING //CameraMode.TRACKING @@ -1050,6 +1084,7 @@ } setLocationIconEnabled(true) if (fromClick) Toast.makeText(context, R.string.location_enabled, Toast.LENGTH_SHORT).show() + pendingLocationActivation =false } else { if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) { //TODO: show dialog for permission rationale @@ -1102,8 +1137,10 @@ private fun switchUserLocationStatus(view: View?){ if(pendingLocationActivation || locationComponent.isLocationComponentEnabled) setMapLocationEnabled(false, false, true) else{ + pendingLocationActivation = true Log.d(DEBUG_TAG, "Request enable location") setMapLocationEnabled(true, false, true) + } } diff --git a/app/src/main/java/it/reyboz/bustorino/middleware/AppLocationManager.kt b/app/src/main/java/it/reyboz/bustorino/middleware/AppLocationManager.kt --- a/app/src/main/java/it/reyboz/bustorino/middleware/AppLocationManager.kt +++ b/app/src/main/java/it/reyboz/bustorino/middleware/AppLocationManager.kt @@ -178,6 +178,7 @@ } } + @Deprecated("Deprecated in Java") override fun onStatusChanged(provider: String, status: Int, extras: Bundle) { //IF ANOTHER LOCATION SOURCE IS READY, USE IT //OTHERWISE, SIGNAL THAT WE HAVE NO LOCATION diff --git a/app/src/main/java/it/reyboz/bustorino/middleware/GeneralActivity.java b/app/src/main/java/it/reyboz/bustorino/middleware/GeneralActivity.java --- a/app/src/main/java/it/reyboz/bustorino/middleware/GeneralActivity.java +++ b/app/src/main/java/it/reyboz/bustorino/middleware/GeneralActivity.java @@ -22,10 +22,8 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.graphics.Rect; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; +import android.os.Build; import com.google.android.material.snackbar.Snackbar; import androidx.annotation.Nullable; @@ -169,4 +167,25 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); } + + protected void setSystemBarAppearance(boolean isSystemInDarkTheme) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (isSystemInDarkTheme) { + if (getWindow() != null && getWindow().getInsetsController() != null) { + getWindow().getInsetsController().setSystemBarsAppearance( + 0, + android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS + ); + } + } else { + if (getWindow() != null && getWindow().getInsetsController() != null) { + getWindow().getInsetsController().setSystemBarsAppearance( + android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, + android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS + ); + } + } + } + } + } diff --git a/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt b/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt --- a/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt +++ b/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt @@ -13,18 +13,41 @@ import android.view.animation.Animation import android.view.animation.Transformation import android.widget.Toast +import androidx.core.view.OnApplyWindowInsetsListener +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import androidx.core.widget.NestedScrollView import it.reyboz.bustorino.R import it.reyboz.bustorino.backend.Stop -import it.reyboz.bustorino.fragments.LinesDetailFragment -import it.reyboz.bustorino.fragments.LinesDetailFragment.Companion import java.io.IOException class ViewUtils { companion object{ + const val DEBUG_TAG="BusTO:ViewUtils" + + /** + * This should help in setting the padding of the last component down + */ + @JvmStatic + fun doOnApplyWindowInsetsForNavigationBars(view: View, listener: OnNavigationBarInsetsAppliedListener) { + ViewCompat.setOnApplyWindowInsetsListener( + view, + OnApplyWindowInsetsListener { v: View?, insets: WindowInsetsCompat? -> + val navigationBarsInsetsBottom = insets!!.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom + listener.onInsetsApplied(v, navigationBarsInsetsBottom) + insets + }) + view.requestApplyInsets() + } + + + interface OnNavigationBarInsetsAppliedListener { + fun onInsetsApplied(view: View?, navigationBarHeight: Int) + } + fun isViewFullyVisibleInScroll(view: View, scrollView: NestedScrollView): Boolean { val scrollBounds = Rect() scrollView.getDrawingRect(scrollBounds) diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/StopsMapViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/StopsMapViewModel.kt --- a/app/src/main/java/it/reyboz/bustorino/viewmodels/StopsMapViewModel.kt +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/StopsMapViewModel.kt @@ -1,6 +1,7 @@ package it.reyboz.bustorino.viewmodels import android.app.Application +import android.location.Location import android.os.Bundle import android.util.Log import androidx.lifecycle.AndroidViewModel @@ -81,8 +82,9 @@ } var savedState: Bundle? = null + var lastUserLocation: Location? = null companion object{ private const val DEBUG_TAG = "BusTOStopMapViewModel" } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_principal.xml b/app/src/main/res/layout/activity_principal.xml --- a/app/src/main/res/layout/activity_principal.xml +++ b/app/src/main/res/layout/activity_principal.xml @@ -4,7 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_height="match_parent"> - @@ -13,16 +13,24 @@ + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_alignParentStart="true" + android:layout_alignParentEnd="true"/> + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_alignParentStart="true" + android:layout_alignParentEnd="true" + /> - + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -14,8 +14,19 @@ android:layout_gravity="start"> --> + + \ No newline at end of file diff --git a/app/src/main/res/layout/default_toobar.xml b/app/src/main/res/layout/default_toobar.xml --- a/app/src/main/res/layout/default_toobar.xml +++ b/app/src/main/res/layout/default_toobar.xml @@ -3,15 +3,13 @@ xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:id="@+id/default_toolbar" + android:layout_height="?attr/actionBarSize" + android:id="@+id/default_toolbar" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:background="?attr/colorPrimary" android:fitsSystemWindows="true" - android:minHeight="?attr/actionBarSize" - android:elevation="4dp" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"> \ No newline at end of file diff --git a/app/src/main/res/values-v35/styles.xml b/app/src/main/res/values-v35/styles.xml new file mode 100644 --- /dev/null +++ b/app/src/main/res/values-v35/styles.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -290,8 +290,7 @@ @string/positions_source_mato_descr @string/positions_source_gtfsrt_descr - MaTO (updated more frequently, might be offline) - GTFS RT (more stable, less frequently updated) + "You are too far, not showing your position Style of the map Versatiles (vector) OSM legacy (raster, lighter) diff --git a/build.gradle b/build.gradle --- a/build.gradle +++ b/build.gradle @@ -9,12 +9,13 @@ } + //TODO: Migrate tfrom kapt to KSP //kotlin - ext.kotlin_version = '1.9.21' - ext.coroutines_version = "1.8.0" + ext.kotlin_version = '2.1.10' + ext.coroutines_version = "1.10.2" dependencies { - classpath 'com.android.tools.build:gradle:8.5.2' + classpath 'com.android.tools.build:gradle:8.6.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -27,7 +28,7 @@ //libraries versions fragment_version = "1.6.1" activity_version = "1.7.2" - appcompat_version = "1.6.1" + appcompat_version = "1.7.0" preference_version = "1.2.1" work_version = "2.9.0"