Page Menu
Home
GitPull.it
Search
Configure Global Search
Log In
Files
F13564982
D133.1784157991.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Authored By
Unknown
Size
24 KB
Referenced Files
None
Subscribers
None
D133.1784157991.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D133: Merge LiveData for positions, and make a switch in the settings
Attached
Detach File
Event Timeline