Page MenuHomeGitPull.it

D133.1784157991.diff
No OneTemporary

Authored By
Unknown
Size
24 KB
Referenced Files
None
Subscribers
None

D133.1784157991.diff

diff --git a/app/src/main/java/it/reyboz/bustorino/backend/gtfs/GtfsUtils.java b/app/src/main/java/it/reyboz/bustorino/backend/gtfs/GtfsUtils.java
--- a/app/src/main/java/it/reyboz/bustorino/backend/gtfs/GtfsUtils.java
+++ b/app/src/main/java/it/reyboz/bustorino/backend/gtfs/GtfsUtils.java
@@ -21,6 +21,16 @@
import it.reyboz.bustorino.backend.ServiceType;
abstract public class GtfsUtils {
+
+ public static String stripGtfsPrefix(String routeID){
+ String[] explo = routeID.split(":");
+ //default is
+ String toParse = routeID;
+ if(explo.length>1) {
+ toParse = explo[1];
+ }
+ return toParse;
+ }
public static Pair<ServiceType, String> getRouteInfoFromGTFS(String routeID){
String[] explo = routeID.split(":");
//default is
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
@@ -164,8 +164,10 @@
val topic = mapTopic(line)
if(elms.isEmpty())
respondersMap.remove(line)
- else
+ else {
client.subscribe(topic, QoS.AtMostOnce.value, null, null)
+ Log.d(DEBUG_TAG, "Resubscribed with topic $topic")
+ }
}
Log.d(DEBUG_TAG, "Reconnected to MQTT Mato Client")
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt
--- a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt
@@ -48,14 +48,10 @@
import it.reyboz.bustorino.data.gtfs.MatoPattern
import it.reyboz.bustorino.data.gtfs.MatoPatternWithStops
import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops
-import it.reyboz.bustorino.map.BusInfoWindow
-import it.reyboz.bustorino.map.BusPositionUtils
+import it.reyboz.bustorino.map.*
import it.reyboz.bustorino.map.CustomInfoWindow.TouchResponder
-import it.reyboz.bustorino.map.LocationOverlay
-import it.reyboz.bustorino.map.MapViewModel
-import it.reyboz.bustorino.map.MarkerUtils
import it.reyboz.bustorino.viewmodels.LinesViewModel
-import it.reyboz.bustorino.viewmodels.MQTTPositionsViewModel
+import it.reyboz.bustorino.viewmodels.LivePositionsViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.osmdroid.config.Configuration
@@ -129,13 +125,15 @@
private var showOnTopOfLine = true
private var recyclerInitDone = false
+ private var useMQTTPositions = true
+
//position of live markers
private val busPositionMarkersByTrip = HashMap<String,Marker>()
private var busPositionsOverlay = FolderOverlay()
private val tripMarkersAnimators = HashMap<String, ObjectAnimator>()
- private val liveBusViewModel: MQTTPositionsViewModel by viewModels()
+ private val liveBusViewModel: LivePositionsViewModel by viewModels()
@SuppressLint("SetTextI18n")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@@ -164,18 +162,25 @@
stopsRecyclerView.visibility = View.VISIBLE
viewModel.setMapShowing(false)
- liveBusViewModel.stopPositionsListening()
+ liveBusViewModel.stopMatoUpdates()
switchButton.setImageDrawable(AppCompatResources.getDrawable(requireContext(), R.drawable.ic_map_white_30))
} else{
stopsRecyclerView.visibility = View.GONE
map.visibility = View.VISIBLE
viewModel.setMapShowing(true)
- liveBusViewModel.requestPosUpdates(lineID)
+ if(useMQTTPositions)
+ liveBusViewModel.requestMatoPosUpdates(lineID)
+ else
+ liveBusViewModel.requestGTFSUpdates()
switchButton.setImageDrawable(AppCompatResources.getDrawable(requireContext(), R.drawable.ic_list_30))
}
}
viewModel.setRouteIDQuery(lineID)
+ val keySourcePositions = getString(R.string.pref_positions_source)
+ useMQTTPositions = PreferenceManager.getDefaultSharedPreferences(requireContext())
+ .getString(keySourcePositions, "mqtt").contentEquals("mqtt")
+
viewModel.patternsWithStopsByRouteLiveData.observe(viewLifecycleOwner){
patterns -> savePatternsToShow(patterns)
}
@@ -229,6 +234,7 @@
//DO NOTHING
return@observe
}
+ val filtdLineID = GtfsUtils.stripGtfsPrefix(lineID)
//filter buses with direction, show those only with the same direction
val outmap = HashMap<String, Pair<LivePositionUpdate, TripAndPatternWithStops?>>()
val currentPattern = viewingPattern!!.pattern
@@ -236,21 +242,28 @@
Log.d(DEBUG_TAG, "Got $numUpds updates, current pattern is: ${currentPattern.name}, directionID: ${currentPattern.directionId}")
val patternsDirections = HashMap<String,Int>()
for((tripId, pair) in it.entries){
+ //remove trips with wrong line ideas
+ if(pair.first.routeID!=filtdLineID)
+ continue
if(pair.second!=null && pair.second?.pattern !=null){
val dir = pair.second?.pattern?.directionId
if(dir !=null && dir == currentPattern.directionId){
- outmap.set(tripId, pair)
+ outmap[tripId] = pair
}
patternsDirections.set(tripId,if (dir!=null) dir else -10)
} else{
outmap[tripId] = pair
//Log.d(DEBUG_TAG, "No pattern for tripID: $tripId")
- patternsDirections.set(tripId, -10)
+ patternsDirections[tripId] = -10
}
}
Log.d(DEBUG_TAG, " Filtered updates are ${outmap.keys.size}") // Original updates directs: $patternsDirections\n
updateBusPositionsInMap(outmap)
+ //if not using MQTT positions
+ if(!useMQTTPositions){
+ liveBusViewModel.requestDelayedGTFSUpdates(2000)
+ }
}
//download missing tripIDs
@@ -653,7 +666,16 @@
Log.d(DEBUG_TAG, "Resetting paused from onResume")
pausedFragment = false
- liveBusViewModel.requestPosUpdates(GtfsUtils.getLineNameFromGtfsID(lineID))
+ val keySourcePositions = getString(R.string.pref_positions_source)
+ useMQTTPositions = PreferenceManager.getDefaultSharedPreferences(requireContext())
+ .getString(keySourcePositions, "mqtt").contentEquals("mqtt")
+
+ //separate paths
+ if(useMQTTPositions)
+ liveBusViewModel.requestMatoPosUpdates(GtfsUtils.getLineNameFromGtfsID(lineID))
+ else
+ liveBusViewModel.requestGTFSUpdates()
+
if(mapViewModel.currentLat.value!=MapViewModel.INVALID) {
Log.d(DEBUG_TAG, "mapViewModel posi: ${mapViewModel.currentLat.value}, ${mapViewModel.currentLong.value}"+
@@ -677,7 +699,7 @@
override fun onPause() {
super.onPause()
- liveBusViewModel.stopPositionsListening()
+ liveBusViewModel.stopMatoUpdates()
pausedFragment = true
//save map
val center = map.mapCenter
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MapFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/MapFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/MapFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/MapFragment.java
@@ -50,7 +50,8 @@
import it.reyboz.bustorino.data.gtfs.MatoPattern;
import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops;
import it.reyboz.bustorino.map.*;
-import it.reyboz.bustorino.viewmodels.MQTTPositionsViewModel;
+import it.reyboz.bustorino.viewmodels.GtfsPositionsViewModel;
+import it.reyboz.bustorino.viewmodels.LivePositionsViewModel;
import it.reyboz.bustorino.viewmodels.StopsMapViewModel;
import org.osmdroid.api.IGeoPoint;
import org.osmdroid.api.IMapController;
@@ -120,8 +121,9 @@
//the ViewModel from which we get the stop to display in the map
private StopsMapViewModel stopsViewModel;
- //private GTFSPositionsViewModel gtfsPosViewModel; //= new ViewModelProvider(this).get(MapViewModel.class);
- private MQTTPositionsViewModel positionsViewModel;
+ //private GtfsPositionsViewModel gtfsPosViewModel; //= new ViewModelProvider(this).get(MapViewModel.class);
+ private LivePositionsViewModel livePositionsViewModel;
+ private Boolean useMQTTViewModel = true;
private final HashMap<String,Marker> busPositionMarkersByTrip = new HashMap<>();
private FolderOverlay busPositionsOverlay = null;
@@ -230,6 +232,11 @@
//set map not done
hasMapStartFinished = false;
+ String keySourcePositions=getString(R.string.pref_positions_source);
+ useMQTTViewModel = (
+ PreferenceManager.getDefaultSharedPreferences(requireContext())
+ .getString(keySourcePositions,"mqtt").contentEquals("mqtt"));
+
//Start map from bundle
if (savedInstanceState !=null)
@@ -283,11 +290,12 @@
public void onAttach(@NonNull Context context) {
super.onAttach(context);
- //gtfsPosViewModel = new ViewModelProvider(this).get(GTFSPositionsViewModel.class);
- //viewModel
ViewModelProvider provider = new ViewModelProvider(this);
- positionsViewModel = provider.get(MQTTPositionsViewModel.class);
+ //gtfsPosViewModel = provider.get(GtfsPositionsViewModel.class);
+ livePositionsViewModel = provider.get(LivePositionsViewModel.class);
stopsViewModel = provider.get(StopsMapViewModel.class);
+
+
if (context instanceof FragmentListenerMain) {
listenerMain = (FragmentListenerMain) context;
} else {
@@ -316,7 +324,7 @@
}
}
tripMarkersAnimators.clear();
- positionsViewModel.stopPositionsListening();
+ if(useMQTTViewModel) livePositionsViewModel.stopMatoUpdates();
}
@@ -347,21 +355,58 @@
bundle.putDouble(MAP_CURRENT_ZOOM_KEY, map.getZoomLevelDouble());
}
+
@Override
public void onResume() {
super.onResume();
+ //TODO: cleanup duplicate code (maybe merging the positions classes?)
if(listenerMain!=null) listenerMain.readyGUIfor(FragmentKind.MAP);
- if(positionsViewModel !=null) {
+ /// choose which to use
+ String keySourcePositions=getString(R.string.pref_positions_source);
+ useMQTTViewModel = PreferenceManager.getDefaultSharedPreferences(requireContext())
+ .getString(keySourcePositions,"mqtt").contentEquals("mqtt");
+ if(livePositionsViewModel !=null) {
//gtfsPosViewModel.requestUpdates();
- positionsViewModel.requestPosUpdates(MQTTMatoClient.LINES_ALL);
+ if(useMQTTViewModel)
+ livePositionsViewModel.requestMatoPosUpdates(MQTTMatoClient.LINES_ALL);
+ else
+ livePositionsViewModel.requestGTFSUpdates();
//mapViewModel.testCascade();
- positionsViewModel.getTripsGtfsIDsToQuery().observe(this, dat -> {
+ livePositionsViewModel.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,
+ requireContext().getApplicationContext(),
+ "BusTO-MatoTripDownload");
+ });
+ } /*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");
+ }
+
+ private void startRequestsPositions(){
+ if (livePositionsViewModel != null) {
+ //should always be the case
+ livePositionsViewModel.getUpdatesWithTripAndPatterns().observe(getViewLifecycleOwner(), data -> {
+ 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
@@ -543,19 +588,7 @@
//Log.i(DEBUG_TAG, "Null bus positions overlay,redo");
busPositionsOverlay = new FolderOverlay();
}
-
-
- if(positionsViewModel !=null){
- //should always be the case
- positionsViewModel.getUpdatesWithTripAndPatterns().observe(getViewLifecycleOwner(), data->{
- Log.d(DEBUG_TAG, "Have "+data.size()+" trip updates, has Map start finished: "+hasMapStartFinished);
- if (hasMapStartFinished) updateBusPositionsInMap(data);
- //if(!isDetached())
- // gtfsPosViewModel.requestDelayedUpdates(4000);
- });
- } else {
- Log.e(DEBUG_TAG, "PositionsViewModel is null");
- }
+ startRequestsPositions();
if(stopsViewModel !=null){
stopsViewModel.getStopsInBoundingBox().observe(getViewLifecycleOwner(),
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/TestRealtimeGtfsFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/TestRealtimeGtfsFragment.kt
--- a/app/src/main/java/it/reyboz/bustorino/fragments/TestRealtimeGtfsFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/TestRealtimeGtfsFragment.kt
@@ -12,7 +12,7 @@
import androidx.fragment.app.viewModels
import it.reyboz.bustorino.R
import it.reyboz.bustorino.backend.mato.MQTTMatoClient
-import it.reyboz.bustorino.viewmodels.MQTTPositionsViewModel
+import it.reyboz.bustorino.viewmodels.LivePositionsViewModel
/**
@@ -30,7 +30,7 @@
private lateinit var lineEditText: EditText
- private val mqttViewModel: MQTTPositionsViewModel by viewModels()
+ private val mqttViewModel: LivePositionsViewModel by viewModels()
/*private val requestListener = object: GtfsRtPositionsRequest.Companion.RequestListener{
override fun onResponse(response: ArrayList<GtfsPositionUpdate>?) {
@@ -91,12 +91,12 @@
*/
subscribed = if(subscribed){
//mqttMatoClient.desubscribe(listener)
- mqttViewModel.stopPositionsListening()
+ mqttViewModel.stopMatoUpdates()
buttonLaunch.text="Start"
false
} else{
//mqttMatoClient.startAndSubscribe(lineEditText.text.trim().toString(), listener)
- mqttViewModel.requestPosUpdates(lineEditText.text.trim().toString())
+ mqttViewModel.requestMatoPosUpdates(lineEditText.text.trim().toString())
buttonLaunch.text="Stop"
true
}
diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/GTFSPositionsViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/GtfsPositionsViewModel.kt
rename from app/src/main/java/it/reyboz/bustorino/viewmodels/GTFSPositionsViewModel.kt
rename to app/src/main/java/it/reyboz/bustorino/viewmodels/GtfsPositionsViewModel.kt
--- a/app/src/main/java/it/reyboz/bustorino/viewmodels/GTFSPositionsViewModel.kt
+++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/GtfsPositionsViewModel.kt
@@ -32,7 +32,7 @@
/**
* View Model for the map. For containing the stops, the trips and whatever
*/
-class GTFSPositionsViewModel(application: Application): AndroidViewModel(application) {
+class GtfsPositionsViewModel(application: Application): AndroidViewModel(application) {
private val gtfsRepo = GtfsRepository(application)
private val netVolleyManager = NetworkVolleyManager.getInstance(application)
@@ -62,11 +62,7 @@
}
private val positionRequestErrorListener = Response.ErrorListener {
- //error listener, it->VolleyError
Log.e(DEBUG_TI, "Could not download the update, error:\n"+it.stackTrace)
-
- //TODO: launch again if needed
-
}
fun requestUpdates(){
diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/MQTTPositionsViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/LivePositionsViewModel.kt
rename from app/src/main/java/it/reyboz/bustorino/viewmodels/MQTTPositionsViewModel.kt
rename to app/src/main/java/it/reyboz/bustorino/viewmodels/LivePositionsViewModel.kt
--- a/app/src/main/java/it/reyboz/bustorino/viewmodels/MQTTPositionsViewModel.kt
+++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/LivePositionsViewModel.kt
@@ -20,29 +20,38 @@
import android.app.Application
import android.util.Log
import androidx.lifecycle.*
+import com.android.volley.Response
+import it.reyboz.bustorino.backend.NetworkVolleyManager
+import it.reyboz.bustorino.backend.gtfs.GtfsRtPositionsRequest
import it.reyboz.bustorino.backend.gtfs.LivePositionUpdate
import it.reyboz.bustorino.backend.mato.MQTTMatoClient
import it.reyboz.bustorino.data.GtfsRepository
import it.reyboz.bustorino.data.MatoPatternsDownloadWorker
import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-typealias UpdatesMap = HashMap<String, LivePositionUpdate>
-
-class MQTTPositionsViewModel(application: Application): AndroidViewModel(application) {
+class LivePositionsViewModel(application: Application): AndroidViewModel(application) {
private val gtfsRepo = GtfsRepository(application)
//private val updates = UpdatesMap()
private val updatesLiveData = MutableLiveData<ArrayList<LivePositionUpdate>>()
+ private val netVolleyManager = NetworkVolleyManager.getInstance(application)
+
private var mqttClient = MQTTMatoClient.getInstance()
private var lineListening = ""
private var lastTimeReceived: Long = 0
- private val positionListener = MQTTMatoClient.Companion.MQTTMatoListener{
+ private val gtfsRtRequestRunning = MutableLiveData<Boolean>(false)
+
+ /**
+ * Responder to the MQTT Client
+ */
+ private val matoPositionListener = MQTTMatoClient.Companion.MQTTMatoListener{
val mupds = ArrayList<LivePositionUpdate>()
if(lineListening==MQTTMatoClient.LINES_ALL){
@@ -132,20 +141,20 @@
}
- fun requestPosUpdates(line: String){
+ fun requestMatoPosUpdates(line: String){
lineListening = line
viewModelScope.launch {
- mqttClient.startAndSubscribe(line,positionListener, getApplication())
+ mqttClient.startAndSubscribe(line,matoPositionListener, getApplication())
}
//updatePositions(1000)
}
- fun stopPositionsListening(){
+ fun stopMatoUpdates(){
viewModelScope.launch {
val tt = System.currentTimeMillis()
- mqttClient.desubscribe(positionListener)
+ mqttClient.desubscribe(matoPositionListener)
val time = System.currentTimeMillis() -tt
Log.d(DEBUG_TI, "Took $time ms to unsubscribe")
}
@@ -157,8 +166,51 @@
updatesLiveData.postValue(updatesLiveData.value)
}
}
+ //Gtfs Real time
+
+
+ private val gtfsPositionsReqListener = object: GtfsRtPositionsRequest.Companion.RequestListener{
+ override fun onResponse(response: ArrayList<LivePositionUpdate>?) {
+ Log.i(DEBUG_TI,"Got response from the GTFS RT server")
+ response?.let {it:ArrayList<LivePositionUpdate> ->
+ if (it.size == 0) {
+ Log.w(DEBUG_TI,"No position updates from the GTFS RT server")
+ return
+ }
+ else {
+ //Log.i(DEBUG_TI, "Posting value to positionsLiveData")
+ viewModelScope.launch { updatesLiveData.postValue(it) }
+
+ }
+ }
+ gtfsRtRequestRunning.postValue(false)
+
+ }
+
+ }
+ private val positionRequestErrorListener = Response.ErrorListener {
+ Log.e(DEBUG_TI, "Could not download the update, error:\n"+it.stackTrace)
+ gtfsRtRequestRunning.postValue(false)
+ }
+
+ fun requestGTFSUpdates(){
+ if(gtfsRtRequestRunning.value == null || !gtfsRtRequestRunning.value!!) {
+ val request = GtfsRtPositionsRequest(positionRequestErrorListener, gtfsPositionsReqListener)
+ netVolleyManager.requestQueue.add(request)
+ Log.i(DEBUG_TI, "Requested GTFS realtime position updates")
+ gtfsRtRequestRunning.value = true
+ }
+
+ }
+
+ fun requestDelayedGTFSUpdates(timems: Long){
+ viewModelScope.launch {
+ delay(timems)
+ requestGTFSUpdates()
+ }
+ }
companion object{
private const val DEBUG_TI = "BusTO-MQTTLiveData"
}
}
\ No newline at end of file
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -206,7 +206,12 @@
<string name="pref_shown_startup">Schermata da mostrare all\'avvio</string>
<string name="pref_shown_startup_def_desc">Tocca per cambiare</string>
+ <string name="positions_source_pref_title">Fonte posizioni in tempo reale di bus e tram</string>
+ <array name="positions_source_sel">
+ <item>MaTO (aggiornate più spesso, può non funzionare)</item>
+ <item>GTFS RT (più stabile)</item>
+ </array>
<!-- lines -->
<string name="long_press_stop_4_options">Tocca a lungo la fermata per le opzioni</string>
diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml
--- a/app/src/main/res/values/keys.xml
+++ b/app/src/main/res/values/keys.xml
@@ -23,4 +23,11 @@
<item>gttjsonfetcher</item>
<item>fivetscraper</item>
</array>
+
+ <string name="pref_positions_source">pref_positions_source</string>
+ <array name="positions_source_values">
+ <item>mqtt</item>
+ <item>gtfsrt</item>
+ </array>
+
</resources>
\ 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
@@ -243,6 +243,12 @@
<item>@string/lines</item>
</array>
+ <string name="positions_source_pref_title">Source of real time positions for buses and trams</string>
+ <array name="positions_source_sel">
+ <item>MaTO (updated more frequently, might be offline)</item>
+ <item>GTFS RT (more stable, less frequently updated)</item>
+ </array>
+
<string name="remove_all_trips">Remove all GTFS trips info</string>
<string name="all_trips_removed">All GTFS trips have been removed from the database</string>
</resources>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -10,6 +10,13 @@
android:title="@string/pref_shown_startup"
android:summary="%s"
/>
+
+ <androidx.preference.ListPreference
+ android:key="@string/pref_positions_source"
+ android:entries="@array/positions_source_sel"
+ android:entryValues="@array/positions_source_values"
+ android:title="@string/positions_source_pref_title"
+ />
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory

File Metadata

Mime Type
text/plain
Expires
Thu, Jul 16, 01:26 (22 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2001914
Default Alt Text
D133.1784157991.diff (24 KB)

Event Timeline