Page MenuHomeGitPull.it

D222.1776864501.diff
No OneTemporary

Size
69 KB
Referenced Files
None
Subscribers
None

D222.1776864501.diff

diff --git a/app/build.gradle b/app/build.gradle
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -116,6 +116,8 @@
// Guava implementation for DBUpdateWorker
implementation 'com.google.guava:guava:33.5.0-android'
+
+ implementation 'com.google.android.flexbox:flexbox:3.0.0'
implementation "androidx.fragment:fragment-ktx:$fragment_version"
implementation "androidx.activity:activity-ktx:$activity_version"
diff --git a/app/src/main/java/it/reyboz/bustorino/adapters/PalinaAdapter.java b/app/src/main/java/it/reyboz/bustorino/adapters/PalinaAdapter.java
--- a/app/src/main/java/it/reyboz/bustorino/adapters/PalinaAdapter.java
+++ b/app/src/main/java/it/reyboz/bustorino/adapters/PalinaAdapter.java
@@ -25,11 +25,13 @@
import androidx.preference.PreferenceManager;
import android.content.SharedPreferences;
+import android.view.Gravity;
import android.os.Build;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.PopupMenu;
import android.widget.TextView;
import java.util.*;
@@ -88,6 +90,12 @@
vh.routeIDTextView.setText(route.getDisplayCode());
vh.routeCard.setOnClickListener(view -> mRouteListener.requestShowingRoute(route));
+
+ // Clicking anywhere on the row shows a popup menu
+ vh.itemView.setOnClickListener(view ->
+ openPopupMenuDetails(con,view, route)
+ ); //vh.rowRouteDestination.getVisibility() == View.VISIBLE ? vh.rowRouteDestination : vh.itemView
+
if(route.destinazione==null || route.destinazione.length() == 0) {
vh.rowRouteDestination.setVisibility(View.GONE);
// move around the route timetable
@@ -114,11 +122,6 @@
}
vh.rowRouteDestination.setText(dest);
-
- //set click listener
- vh.itemView.setOnClickListener(view -> {
- mRouteListener.showRouteFullDirection(route);
- });
}
switch (route.type) {
@@ -208,6 +211,26 @@
return Capitalize.DO_NOTHING;
}
+ private void openPopupMenuDetails(Context con, View view, Route route){
+ PopupMenu popup = new PopupMenu(con, view, Gravity.END);
+ popup.inflate(R.menu.menu_arrivals_line_item);
+ if (route.destinazione == null || route.destinazione.isEmpty()) {
+ popup.getMenu().findItem(R.id.action_show_direction).setVisible(false);
+ }
+ popup.setOnMenuItemClickListener(item -> {
+ int id = item.getItemId();
+ if (id == R.id.action_open_line) {
+ mRouteListener.requestShowingRoute(route);
+ return true;
+ } else if (id == R.id.action_show_direction) {
+ mRouteListener.showRouteFullDirection(route);
+ return true;
+ }
+ return false;
+ });
+ popup.show();
+ }
+
public PalinaAdapter(Context context, Palina p, PalinaClickListener listener, boolean hideEmptyRoutes) {
Comparator<Passaggio> sorter = null;
if (p.getPassaggiSourceIfAny()== Passaggio.Source.GTTJSON){
diff --git a/app/src/main/java/it/reyboz/bustorino/adapters/RouteAdapter.kt b/app/src/main/java/it/reyboz/bustorino/adapters/RouteAdapter.kt
--- a/app/src/main/java/it/reyboz/bustorino/adapters/RouteAdapter.kt
+++ b/app/src/main/java/it/reyboz/bustorino/adapters/RouteAdapter.kt
@@ -12,7 +12,7 @@
class RouteAdapter(val routes: List<GtfsRoute>,
click: ItemClicker,
- private val layoutId: Int = R.layout.entry_line_num_descr) :
+ private val layoutId: Int = R.layout.entry_line_name_description) :
RecyclerView.Adapter<RouteAdapter.ViewHolder>()
{
val clickreference: WeakReference<ItemClicker>
@@ -45,7 +45,7 @@
// Get element from your dataset at this position and replace the
// contents of the view with that element
val route = routes[position]
- holder.nameTextView.text = route.shortName
+ holder.nameTextView.text = route.getShortNameDisplay()
holder.descrptionTextView.text = route.longName
holder.itemView.setOnClickListener{
diff --git a/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt b/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt
--- a/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt
+++ b/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt
@@ -6,6 +6,7 @@
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import it.reyboz.bustorino.R
+import it.reyboz.bustorino.backend.FiveTNormalizer
import it.reyboz.bustorino.backend.Palina
import java.lang.ref.WeakReference
@@ -47,7 +48,8 @@
// Get element from your dataset at this position and replace the
// contents of the view with that element
- viewHolder.textView.text = routeNames[position]
+ // SHOW "STAR" as "ST"
+ viewHolder.textView.text = FiveTNormalizer.filterFullStarName(routeNames[position])
viewHolder.itemView.setOnClickListener{
clickreference?.get()?.onItemClick(position, routeNames[position])
}
diff --git a/app/src/main/java/it/reyboz/bustorino/backend/FiveTNormalizer.java b/app/src/main/java/it/reyboz/bustorino/backend/FiveTNormalizer.java
--- a/app/src/main/java/it/reyboz/bustorino/backend/FiveTNormalizer.java
+++ b/app/src/main/java/it/reyboz/bustorino/backend/FiveTNormalizer.java
@@ -182,6 +182,7 @@
if(routeID.length() == 3 && routeID.charAt(2) == 'B') {
return routeID.substring(0,2).concat("/");
}
+ //TODO: Decide what to do about the "+" lines (68+, 13+)
switch(routeID) {
case "1C":
@@ -380,4 +381,13 @@
return sb.toString();
}
+
+ public static String filterFullStarName(String name){
+ String outName = name;
+ if(name.contains("STAR ")){
+ //FIX FOR THE MaTO data
+ outName = outName.replace("STAR ","ST");
+ }
+ return outName;
+ }
}
diff --git a/app/src/main/java/it/reyboz/bustorino/backend/Palina.java b/app/src/main/java/it/reyboz/bustorino/backend/Palina.java
--- a/app/src/main/java/it/reyboz/bustorino/backend/Palina.java
+++ b/app/src/main/java/it/reyboz/bustorino/backend/Palina.java
@@ -1,6 +1,7 @@
/*
BusTO (backend components)
Copyright (C) 2016 Ludovico Pavesi
+ Copyright (c) 2026 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
@@ -416,7 +417,64 @@
return mList;
}
- //private void mergeRoute
+
+ private static String pick(String a, String b) {
+ return (a != null && !a.isEmpty()) ? a : b;
+ }
+
+ /**
+ * Merge two Palinas, including information from both
+ * @param p1 the first one, which has priority
+ * @param p2 the second one
+ * @return the merged Palina data
+ */
+ public static @Nullable Palina mergePaline(@Nullable Palina p1, @Nullable Palina p2) {
+ if (p1 == null) return p2;
+ if (p2 == null) return p1;
+
+ // --- Campi base (Stop) ---
+ String id = p1.ID; // assumiamo stesso ID
+
+ String name = pick(p1.getStopDefaultName(), p2.getStopDefaultName());
+ String userName = pick(p1.getStopUserName(), p2.getStopUserName());
+ String location = pick(p1.location, p2.location);
+
+ Double lat = p1.getLatitude() != null ? p1.getLatitude() : p2.getLatitude();
+ Double lon = p1.getLongitude() != null ? p1.getLongitude() : p2.getLongitude();
+
+ String gtfsID = pick(p1.gtfsID, p2.gtfsID);
+
+ Palina result = new Palina(id, name, userName, location, lat, lon, gtfsID);
+
+ // --- Routes ---
+ List<Route> mergedRoutes = new ArrayList<>();
+ boolean addFromSecond = false;
+
+ if (p1.queryAllRoutes() != null)
+ mergedRoutes.addAll(p1.routes);
+
+ else if (p2.queryAllRoutes() != null)
+ mergedRoutes.addAll(p2.routes);
+ else {
+ //assume the first one has more important imformation
+ mergedRoutes.addAll(p1.routes);
+ addFromSecond = true;
+
+ }
+
+ result.setRoutes(mergedRoutes);
+ if(addFromSecond){
+ result.addInfoFromRoutes(p2.routes);
+ }
+
+ // Unisci eventuali duplicati (stesso routeID)
+ result.mergeDuplicateRoutes(0);
+
+ // Aggiorna stringa routes
+ result.buildRoutesString();
+
+ return result;
+ }
/// ------- Parcelable stuff ---
protected Palina(Parcel in) {
diff --git a/app/src/main/java/it/reyboz/bustorino/backend/Route.java b/app/src/main/java/it/reyboz/bustorino/backend/Route.java
--- a/app/src/main/java/it/reyboz/bustorino/backend/Route.java
+++ b/app/src/main/java/it/reyboz/bustorino/backend/Route.java
@@ -432,6 +432,15 @@
return adjusted;
}
+ public String getRouteLongDisplayName() {
+
+ String routeName = FiveTNormalizer.routeInternalToDisplay(this.name);
+ if (routeName == null) {
+ routeName = this.displayCode;
+ }
+ return routeName;
+ }
+
// ---- Parcelable implem ---
protected Route(Parcel in) {
diff --git a/app/src/main/java/it/reyboz/bustorino/backend/Stop.java b/app/src/main/java/it/reyboz/bustorino/backend/Stop.java
--- a/app/src/main/java/it/reyboz/bustorino/backend/Stop.java
+++ b/app/src/main/java/it/reyboz/bustorino/backend/Stop.java
@@ -216,9 +216,7 @@
/**
* Returns stop name or username (if set).<br>
- * - empty string means "already searched everywhere, can't find it"<br>
- * - null means "didn't search, yet. Maybe you should try."<br>
- * - string means "here's the name.", obviously.<br>
+ * If null, we should try to look somewhere else.
*
* @return string if known, null if still unknown
*/
@@ -282,6 +280,13 @@
return String.format(Locale.US, "geo:%f,%f", this.lat, this.lon);
}
+ /**
+ * Check if the stop contains the coordinates
+ * @return true if both the latitude and the longitude are not null
+ */
+ public final boolean hasCoords(){
+ return (this.lat!=null)&&(this.lon!=null);
+ }
public final @Nullable String getGeoURLWithAddress() {
String url = getGeoURL();
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
@@ -18,6 +18,7 @@
package it.reyboz.bustorino.backend.gtfs;
import androidx.core.util.Pair;
+import it.reyboz.bustorino.backend.FiveTNormalizer;
import it.reyboz.bustorino.backend.ServiceType;
abstract public class GtfsUtils {
@@ -69,4 +70,13 @@
public static String getLineNameFromGtfsID(String routeID){
return getRouteInfoFromGTFS(routeID).second;
}
+
+ public static String lineNameDisplayFromGtfsID(String routeID){
+ String name = getRouteInfoFromGTFS(routeID).second;
+
+ String altName = FiveTNormalizer.routeInternalToDisplay(name);
+ if (altName==null) //WTF WHY DOES IT HAVE TO BE NULL
+ return name;
+ else return altName;
+ }
}
diff --git a/app/src/main/java/it/reyboz/bustorino/backend/mato/MatoAPIFetcher.kt b/app/src/main/java/it/reyboz/bustorino/backend/mato/MatoAPIFetcher.kt
--- a/app/src/main/java/it/reyboz/bustorino/backend/mato/MatoAPIFetcher.kt
+++ b/app/src/main/java/it/reyboz/bustorino/backend/mato/MatoAPIFetcher.kt
@@ -199,7 +199,7 @@
for (i in 0 until routesStoppingJSON.length()){
val routeBaseInfo = routesStoppingJSON.getJSONObject(i)
val r = Route(routeBaseInfo.getString("shortName"), Route.Type.UNKNOWN,"")
- r.setGtfsId(routeBaseInfo.getString("gtfsId").trim())
+ r.gtfsId = routeBaseInfo.getString("gtfsId").trim()
baseRoutes.add(r)
}
@@ -233,7 +233,7 @@
//val gtfsRoutes = mutableListOf<>()
return palina
}
- fun parseRouteStoptimesJSON(jsonPatternWithStops: JSONObject): Route{
+ private fun parseRouteStoptimesJSON(jsonPatternWithStops: JSONObject): Route{
val patternJSON = jsonPatternWithStops.getJSONObject("pattern")
val routeJSON = patternJSON.getJSONObject("route")
@@ -258,7 +258,7 @@
"TRAM" -> routeType = Route.Type.TRAM
}
val route = Route(
- routeJSON.getString("shortName"),
+ FiveTNormalizer.filterFullStarName(routeJSON.getString("shortName")),
patternJSON.getString("headsign"),
routeType,
passages,
diff --git a/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsRoute.kt b/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsRoute.kt
--- a/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsRoute.kt
+++ b/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsRoute.kt
@@ -20,6 +20,7 @@
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
+import it.reyboz.bustorino.backend.FiveTNormalizer
@Entity(tableName=GtfsRoute.DB_TABLE)
data class GtfsRoute(
@@ -80,4 +81,8 @@
override fun getColumns(): Array<String> {
return COLUMNS
}
+
+ fun getShortNameDisplay(): String {
+ return FiveTNormalizer.filterFullStarName(shortName)
+ }
}
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt
--- a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt
@@ -65,8 +65,10 @@
//Views
protected lateinit var addToFavorites: ImageButton
+ protected lateinit var openInMapButton: ImageButton
protected lateinit var timesSourceTextView: TextView
- protected lateinit var messageTextView: TextView
+ private lateinit var messageTextView: TextView
+ private lateinit var preMessageTextView: TextView // this hold the "Arrivals at: " text
protected lateinit var arrivalsRecyclerView: RecyclerView
private var mListAdapter: PalinaAdapter? = null
@@ -95,14 +97,8 @@
private val palinaClickListener: PalinaClickListener = object : PalinaClickListener {
override fun showRouteFullDirection(route: Route) {
- var routeName: String?
+ var routeName = route.routeLongDisplayName
Log.d(DEBUG_TAG, "Make toast for line " + route.name)
-
-
- routeName = FiveTNormalizer.routeInternalToDisplay(route.name)
- if (routeName == null) {
- routeName = route.displayCode
- }
if (context == null) Log.e(DEBUG_TAG, "Touched on a route but Context is null")
else if (route.destinazione == null || route.destinazione.length == 0) {
Toast.makeText(
@@ -168,7 +164,9 @@
): View? {
val root = inflater.inflate(R.layout.fragment_arrivals, container, false)
messageTextView = root.findViewById(R.id.messageTextView)
+ preMessageTextView = root.findViewById(R.id.arrivalsTextView)
addToFavorites = root.findViewById(R.id.addToFavorites)
+ openInMapButton = root.findViewById(R.id.openInMapButton)
// "How does it work part"
howDoesItWorkTextView = root.findViewById(R.id.howDoesItWorkTextView)
hideHintButton = root.findViewById(R.id.hideHintButton)
@@ -219,7 +217,7 @@
val displayName = requireArguments().getString(STOP_TITLE)
if (displayName != null) setTextViewMessage(
String.format(
- getString(R.string.passages), displayName
+ getString(R.string.passages_fill), displayName
)
)
@@ -261,6 +259,7 @@
arrivalsViewModel.palinaLiveData.observe(viewLifecycleOwner){
mListener.toggleSpinner(false)
+ Log.d(DEBUG_TAG, "New result palina observed, has coords: ${it.hasCoords()}")
if(arrivalsViewModel.resultLiveData.value==Fetcher.Result.OK){
//the result is true
changeUIFirstSearchActive(false)
@@ -456,21 +455,34 @@
if (p == null) Log.w(DEBUG_TAG, "Asked to update the data, but we're not attached and the data is null")
else needUpdateOnAttach = true
} else {
+ //set title
+ if(stopName==null && p?.stopDisplayName != null){
+ stopName = p.stopDisplayName
+ updateMessage()
+ }
+
val adapter = PalinaAdapter(context, lastUpdatedPalina, palinaClickListener, true)
showArrivalsSources(lastUpdatedPalina!!)
resetListAdapter(adapter)
+ lastUpdatedPalina?.let{ pal ->
+ openInMapButton.setOnClickListener {
+ if (pal.hasCoords())
+ mListener.showMapCenteredOnStop(pal)
+ }
+ }
+
val routesWithNoPassages = lastUpdatedPalina!!.routesNamesWithNoPassages
if (routesWithNoPassages.isEmpty()) {
//hide the views if there are no empty routes
- noArrivalsRecyclerView!!.visibility = View.GONE
+ noArrivalsRecyclerView.visibility = View.GONE
noArrivalsTitleView!!.visibility = View.GONE
} else {
Collections.sort(routesWithNoPassages, LinesNameSorter())
noArrivalsAdapter = RouteOnlyLineAdapter(routesWithNoPassages, null)
- noArrivalsRecyclerView!!.adapter = noArrivalsAdapter
+ noArrivalsRecyclerView.adapter = noArrivalsAdapter
- noArrivalsRecyclerView!!.visibility = View.VISIBLE
+ noArrivalsRecyclerView.visibility = View.VISIBLE
noArrivalsTitleView!!.visibility = View.VISIBLE
}
@@ -525,9 +537,7 @@
}
/**
- * Update the message in the fragment
- *
- * It may eventually change the "Add to Favorite" icon
+ * Update the stop title in the fragment
*/
private fun updateMessage() {
var message = ""
@@ -539,13 +549,21 @@
Log.e("ArrivalsFragm$tag", "NO ID FOR THIS FRAGMENT - something went horribly wrong")
}
if (message.isNotEmpty()) {
- setTextViewMessage(getString(R.string.passages, message))
+ //setTextViewMessage(getString(R.string.passages_fill, message))
+ setTextViewMessage(message)
}
+ }
- // whatever is the case, update the star icon
- //updateStarIconFromLastBusStop();
+ /**
+ * Set the message textView
+ * @param message the whole message to write in the textView
+ */
+ fun setTextViewMessage(message: String?) {
+ messageTextView.text = message
+ messageTextView.visibility = View.VISIBLE
}
+
override fun onCreateLoader(id: Int, p1: Bundle?): Loader<Cursor> {
val args = arguments
//if (args?.getString(KEY_STOP_ID) == null) throw
@@ -592,7 +610,7 @@
stopIsInFavorites = false
}
updateStarIcon()
-
+ /*
if (stopName == null) {
//stop is not inside the favorites and wasn't provided
Log.d("ArrivalsFragment$tag", "Stop wasn't in the favorites and has no name, looking in the DB")
@@ -601,8 +619,10 @@
arguments, this
)
}
+ 6
+ */
}
-
+ /*
loaderStopId -> if (data.count > 0) {
data.moveToFirst()
val index = data.getColumnIndex(
@@ -616,6 +636,8 @@
} else {
Log.w("ArrivalsFragment$tag", "Stop is not inside the database... CLOISTER BELL")
}
+
+ */
}
}
@@ -629,15 +651,6 @@
arrivalsRecyclerView.visibility = View.VISIBLE
}
- /**
- * Set the message textView
- * @param message the whole message to write in the textView
- */
- fun setTextViewMessage(message: String?) {
- messageTextView.text = message
- messageTextView.visibility = View.VISIBLE
- }
-
fun toggleLastStopToFavorites() {
val stop: Stop? = lastUpdatedPalina
if (stop != null) {
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
@@ -45,6 +45,7 @@
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.maplibre.android.MapLibre
+import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.location.LocationComponent
import org.maplibre.android.location.LocationComponentOptions
@@ -326,7 +327,7 @@
}
// Hide the bottom sheet and remove extra symbol
- protected fun hideStopOrBusBottomSheet(){
+ protected open fun hideStopOrBusBottomSheet(){
if (stopActiveSymbol!=null){
symbolManager?.delete(stopActiveSymbol)
stopActiveSymbol = null
@@ -534,7 +535,7 @@
*/
protected fun showVehicleTripInBottomSheet(
veh: String,
- onDirectionsClick: (patternCode: String) -> Unit
+ onDirectionsClick: (patternCode: String, veh: String) -> Unit
) {
val data = updatesByVehDict[veh] ?: run {
Log.w(DEBUG_TAG, "Asked to show vehicle $veh, but it's not present in the updates")
@@ -542,7 +543,7 @@
}
bottomLayout?.let {
val lineName = FiveTNormalizer.fixShortNameForDisplay(
- GtfsUtils.getLineNameFromGtfsID(data.posUpdate.routeID), true
+ GtfsUtils.getLineNameFromGtfsID(data.posUpdate.routeID), false
)
val pat = data.pattern
if (pat != null) {
@@ -554,7 +555,7 @@
stopNumberTextView.text = getString(R.string.line_fill, lineName)
}
directionsCard.setOnClickListener {
- onDirectionsClick(pat?.code ?: "")
+ onDirectionsClick(pat?.code ?: "", veh)
}
directionsCard.visibility = View.VISIBLE
bottomrightImage.setImageDrawable(
@@ -700,6 +701,7 @@
val string_show = if (stop.numRoutesStopping==0) ""
else requireContext().getString(R.string.lines_fill, stop.routesThatStopHereToString())
linesPassingTextView.text = string_show
+ linesPassingTextView.visibility = View.VISIBLE
//SET ON CLICK LISTENER
arrivalsCard.setOnClickListener{
@@ -911,6 +913,13 @@
updatePositionsIcons(forced = false)
}
+ protected fun setCameraPosition(latitude: Double, longitude: Double, zoom: Double) {
+ map?.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(latitude, longitude))
+ .zoom(zoom)
+ .build()
+ }
+
companion object{
private const val DEBUG_TAG="GeneralMapLibreFragment"
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
@@ -23,7 +23,6 @@
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
-import android.content.res.ColorStateList
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@@ -35,18 +34,15 @@
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
-import androidx.core.view.ViewCompat
import androidx.fragment.app.viewModels
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.gson.JsonObject
import it.reyboz.bustorino.R
import it.reyboz.bustorino.adapters.NameCapitalize
import it.reyboz.bustorino.adapters.StopAdapterListener
import it.reyboz.bustorino.adapters.StopRecyclerAdapter
-import it.reyboz.bustorino.backend.FiveTNormalizer
import it.reyboz.bustorino.backend.Stop
import it.reyboz.bustorino.backend.gtfs.GtfsUtils
import it.reyboz.bustorino.backend.gtfs.PolylineParser
@@ -101,7 +97,7 @@
private var patternShown: MatoPatternWithStops? = null
private val viewModel: LinesViewModel by viewModels()
- private var firstInit = true
+ //private var firstInit = true
private var pausedFragment = false
private lateinit var switchButton: ImageButton
@@ -263,8 +259,7 @@
}
val titleTextView = rootView.findViewById<TextView>(R.id.titleTextView)
- titleTextView.text = getString(R.string.line)+" "+FiveTNormalizer.fixShortNameForDisplay(
- GtfsUtils.getLineNameFromGtfsID(lineID), true)
+ titleTextView.text = getString(R.string.line)+" "+ GtfsUtils.lineNameDisplayFromGtfsID(lineID)
favoritesButton?.isClickable = true
favoritesButton?.setOnClickListener {
@@ -342,24 +337,27 @@
usingMQTTPositions = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getString(keySourcePositions, "mqtt").contentEquals("mqtt")
- viewModel.patternsWithStopsByRouteLiveData.observe(viewLifecycleOwner){
- patterns -> savePatternsToShow(patterns)
- }
+ viewModel.patternsWithStopsByRouteLiveData.observe(viewLifecycleOwner, this::savePatternsToShow)
/*
*/
viewModel.stopsForPatternLiveData.observe(viewLifecycleOwner) { stops ->
- if(mapView.visibility ==View.VISIBLE)
- patternShown?.let{
- // We have the pattern and the stops here, time to display them
- //TODO: Decide if we should follow the camera view given by the previous screen (probably the map fragment)
- // use !restoredCameraInMap to do so
- displayPatternWithStopsOnMap(it,stops, true)
- } ?:{
- Log.w(DEBUG_TAG, "The viewingPattern is null!")
- }
- else{
- if(stopsRecyclerView.visibility==View.VISIBLE)
+ val pattern = viewModel.selectedPatternLiveData.value
+ if (pattern == null) {
+ Log.w(DEBUG_TAG, "The selectedPattern is null!")
+ return@observe
+ }
+ if(mapView.visibility ==View.VISIBLE) {
+ // We have the pattern and the stops here, time to display them
+ //TODO: Decide if we should follow the camera view given by the previous screen (probably the map fragment)
+ // use !restoredCameraInMap to do so
+
+ // val shouldZoom = (shownStopInBottomSheet == null) //use this if we want to avoid zoom when we're keeping the stop open
+ displayPatternWithStopsOnMap(pattern, stops, true)
+ } else {
+ if(stopsRecyclerView.visibility==View.VISIBLE) {
+ patternShown = pattern
showStopsInRecyclerView(stops)
+ }
}
}
viewModel.gtfsRoute.observe(viewLifecycleOwner){route->
@@ -395,6 +393,20 @@
updatePositionsIcons(true)
livePositionsViewModel.retriggerPositionUpdate()
}
+ if (shownStopInBottomSheet!=null){
+ //check if the stop is inside the new pattern
+ /*val s = shownStopInBottomSheet!!
+ val newPatternStops = patternWithStops.stopsIndices
+ val filterPStops = newPatternStops.filter { ps -> ps.stopGtfsId == "gtt:${s.ID}" }
+ if (filterPStops.isEmpty()){
+ hideStopOrBusBottomSheet()
+ }
+ */
+ // do another thing, just close the stop when the pattern is changed
+ if (patt.code != patternWithStops.pattern.code){
+ hideStopOrBusBottomSheet()
+ }
+ }
}
}
livePositionsViewModel.setGtfsLineToFilterPos(lineID, patternWithStops.pattern)
@@ -576,16 +588,16 @@
mapReady.addOnMapClickListener { point ->
val screenPoint = mapReady.projection.toScreenLocation(point)
- val features = mapReady.queryRenderedFeatures(screenPoint, STOPS_LAYER_ID)
+ val stopsNearby = mapReady.queryRenderedFeatures(screenPoint, STOPS_LAYER_ID)
val busNearby = mapReady.queryRenderedFeatures(screenPoint, BUSES_LAYER_ID)
- if (features.isNotEmpty()) {
- val feature = features[0]
+ //Log.d(DEBUG_TAG, "onMapClick, stopsNearby: $stopsNearby \nstopShown: $shownStopInBottomSheet \nbusNearby: $busNearby,")
+
+ if (stopsNearby.isNotEmpty()) {
+ val feature = stopsNearby[0]
val id = feature.getStringProperty("id")
- val name = feature.getStringProperty("name")
- //Toast.makeText(requireContext(), "Clicked on $name ($id)", Toast.LENGTH_SHORT).show()
val stop = viewModel.getStopByID(id)
stop?.let {
- if (isBottomSheetShowing() || vehShowing.isNotEmpty()){
+ if (isBottomSheetShowing() || vehShowing.isNotEmpty()) {
hideStopOrBusBottomSheet()
}
openStopInBottomSheet(it)
@@ -597,21 +609,7 @@
return@addOnMapClickListener true
} else if (busNearby.isNotEmpty()){
val feature = busNearby[0]
- val vehid = feature.getStringProperty("veh")
- val route = feature.getStringProperty("line")
- if(isBottomSheetShowing())
- hideStopOrBusBottomSheet()
- //if(context!=null){
- // Toast.makeText(context, "Veh $vehid on route ${route.slice(0..route.length-2)}", Toast.LENGTH_SHORT).show()
- //}
- showVehicleTripInBottomSheet(vehid)
- updatesByVehDict[vehid]?.let {
- //if (it.posUpdate.latitude != null && it.longitude != null)
- mapReady.animateCamera(
- CameraUpdateFactory.newLatLng(LatLng(it.posUpdate.latitude, it.posUpdate.longitude)),
- 750
- )
- }
+ openBusFromMapClick(feature)
return@addOnMapClickListener true
}
@@ -626,7 +624,7 @@
val zoom = 12.0
val latlngTarget = LatLng(MapLibreFragment.DEFAULT_CENTER_LAT, MapLibreFragment.DEFAULT_CENTER_LON)
if(!setViewAlready)
- mapReady.cameraPosition = savedCameraPosition ?:CameraPosition.Builder().target(latlngTarget).zoom(zoom).build()
+ mapReady.cameraPosition = savedCameraPosition ?:CameraPosition.Builder().target(latlngTarget).zoom(zoom).build()
savedCameraPosition = null
@@ -637,9 +635,23 @@
return true
}
- private fun observeBusPositionUpdates(){
-
+ /**
+ * Separate function to find the vehicle associated with a feature and display it
+ */
+ private fun openBusFromMapClick(feature: Feature){
+ val vehid = feature.getStringProperty("veh")
+ if(isBottomSheetShowing())
+ hideStopOrBusBottomSheet()
+ showVehicleTripInBottomSheet(vehid)
+ updatesByVehDict[vehid]?.let {
+ map?.animateCamera(
+ CameraUpdateFactory.newLatLng(LatLng(it.posUpdate.latitude, it.posUpdate.longitude)),
+ 750
+ )
+ }
+ }
+ private fun observeBusPositionUpdates(){
//live bus positions
livePositionsViewModel.filteredLocationUpdates.observe(viewLifecycleOwner){ pair ->
//Log.d(DEBUG_TAG, "Received ${updates.size} updates for the positions")
@@ -672,12 +684,27 @@
}
private fun showVehicleTripInBottomSheet(veh: String) {
- super.showVehicleTripInBottomSheet(veh) { patternCode ->
+ super.showVehicleTripInBottomSheet(veh) { patternCode, veh ->
//this is checked in @GeneralMapLibreFragment
//val data = updatesByVehDict[veh] ?: return@showVehicleTripInBottomSheet
if (patternCode.isEmpty()) return@showVehicleTripInBottomSheet
if (patternShown?.pattern?.code == patternCode) {
- Toast.makeText(context, R.string.showing_same_direction, Toast.LENGTH_SHORT).show()
+ //center view on vehicle
+ updatesByVehDict[veh]?.let { up->
+ map?.let{
+ /*
+ val c = it.cameraPosition
+ it.moveCamera(CameraUpdateFactory.CameraPositionUpdate(c.bearing,
+ LatLng(up.posUpdate.latitude, up.posUpdate.longitude),
+ c.tilt,c.zoom, c.padding)
+ )
+ */
+ it.animateCamera(CameraUpdateFactory.newLatLng(LatLng(up.posUpdate.latitude, up.posUpdate.longitude)))
+ }
+ } ?: {
+ Toast.makeText(context, R.string.showing_same_direction, Toast.LENGTH_SHORT).show()
+ }
+
} else {
showPatternWithCode(patternCode)
}
@@ -749,7 +776,7 @@
var p: MatoPatternWithStops? = null
if (patternIdToShow.isNotEmpty()){
- for (patt in currentPatterns) {
+ for (patt in patterns) {
if (patt.pattern.code == patternIdToShow){
p = patt
}
@@ -763,7 +790,7 @@
else if(stopIDFromToShow.isNotEmpty()) {
val stopGtfsID = "gtt:$stopIDFromToShow"
var pLength = 0
- for (patt in currentPatterns) {
+ for (patt in patterns) {
for (pstop in patt.stopsIndices) {
if (pstop.stopGtfsId == stopGtfsID) {
//found
@@ -781,9 +808,9 @@
else
Log.d(DEBUG_TAG, "Requesting to show pattern from stop $stopIDFromToShow, found pattern ${p.pattern.code}")
}
-
- stopIDFromToShow = ""
+ // the flag of showing pattern is not necessary anymore, we have set the pattern
patternIdToShow = ""
+ // the flag of selecting from stop needs to be used again when displaying the pattern
return p
}
/**
@@ -798,7 +825,7 @@
it.addAll(currentPatterns.map { p->"${p.pattern.directionId} - ${p.pattern.headsign}" })
it.notifyDataSetChanged()
}
- val patternToShow = filterPatternFromArgs(patterns)
+ val patternToShow = filterPatternFromArgs(currentPatterns)
if(patternToShow!=null) {
//showPattern(patternToShow)
patternShown = patternToShow
@@ -816,7 +843,6 @@
Log.d(DEBUG_TAG, "Requesting stops for pattern ${patternWithStops.pattern.code}")
viewModel.selectedPatternLiveData.value = patternWithStops
viewModel.currentPatternStops.value = patternWithStops.stopsIndices.sortedBy { i-> i.order }
- patternShown = patternWithStops
viewModel.requestStopsForPatternWithStops(patternWithStops)
}
@@ -831,12 +857,11 @@
}
}
Log.d(DEBUG_TAG, "Requesting stops fro pattern $code in position: $pos")
+ // this triggers the showing on the map / recyclerview
if (pos !=-2)
patternsSpinner.setSelection(pos)
else
Log.e(DEBUG_TAG, "Pattern with code $code not found!!")
- //request pattern stops from DB
- //setPatternAndReqStops(patternWs)
}
/**
@@ -957,12 +982,28 @@
Log.e(DEBUG_TAG, "Stops layer is not started!!")
}
+ var reallyZoomToPattern = zoomToPattern
+ if(stopIDFromToShow.isNotEmpty()){
+ //open the stop
+ val stopfilt = stopsSorted.filter { s -> s.ID == stopIDFromToShow }
+ if (stopfilt.isEmpty()){
+ Log.e(DEBUG_TAG, "Tried to show stop but it's not in the selected pattern")
+ } else{
+ val stop = stopfilt[0]
+ openStopInBottomSheet(stop)
+
+ if(stop.hasCoords()) {
+ reallyZoomToPattern = false
+ setCameraPosition(stop.latitude!!, stop.longitude!!, 13.5)
+ }
+
+ }
+ // Reset this to avoid checking again when showing
+ stopIDFromToShow = ""
+ //camera set
+ }
+ if(reallyZoomToPattern) zoomToCurrentPattern()
- //POINTS LIST IS NOT IN ORDER ANY MORE
- //if(!map.overlayManager.contains(stopsOverlay)){
- // map.overlayManager.add(stopsOverlay)
- //}
- if(zoomToPattern) zoomToCurrentPattern()
}
private fun initializeRecyclerView(){
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/LinesGridShowingFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/LinesGridShowingFragment.kt
--- a/app/src/main/java/it/reyboz/bustorino/fragments/LinesGridShowingFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/LinesGridShowingFragment.kt
@@ -17,6 +17,9 @@
import androidx.recyclerview.widget.RecyclerView
import androidx.work.WorkInfo
import androidx.work.WorkManager
+import com.google.android.flexbox.FlexDirection
+import com.google.android.flexbox.FlexboxLayoutManager
+import com.google.android.flexbox.JustifyContent
import it.reyboz.bustorino.R
import it.reyboz.bustorino.adapters.RouteAdapter
import it.reyboz.bustorino.adapters.RouteOnlyLineAdapter
@@ -30,7 +33,6 @@
import it.reyboz.bustorino.util.ViewUtils
import it.reyboz.bustorino.viewmodels.LinesGridShowingViewModel
-
class LinesGridShowingFragment : ScreenBaseFragment() {
@@ -63,6 +65,13 @@
private val linesComparator = Comparator<GtfsRoute> { a,b ->
return@Comparator linesNameSorter.compare(a.shortName, b.shortName)
}
+ private val linesPriorityComparator = Comparator<Pair<GtfsRoute,Int>> { pa, pb ->
+ if (pa.second != pb.second){
+ return@Comparator pa.second - pb.second
+ } else{
+ return@Comparator linesNameSorter.compare(pa.first.shortName, pb.first.shortName)
+ }
+ }
private val routeClickListener = RouteAdapter.ItemClicker {
fragmentListener.openLineFromStop(it.gtfsId, null)
@@ -73,6 +82,13 @@
private val lastQueryEmptyForAgency = HashMap<String, Boolean>(3)
private var openRecyclerView = "AG_URBAN"
+ private fun getFlexLayoutManager(context: Context): FlexboxLayoutManager{
+ val layoutManager = FlexboxLayoutManager(context)
+ layoutManager.flexDirection = FlexDirection.ROW
+ layoutManager.justifyContent = JustifyContent.FLEX_START
+
+ return layoutManager
+ }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@@ -105,37 +121,36 @@
recyView.layoutManager = gridLayoutManager
}
//init favorites recyclerview
- val gridLayoutManager = AutoFitGridLayoutManager(
- requireContext().applicationContext,
- (utils.convertDipToPixels(context, 70f)).toInt()
- )
- favoritesRecyclerView.layoutManager = gridLayoutManager
+ favoritesRecyclerView.layoutManager = getFlexLayoutManager(requireContext())
+
+ viewModel.getLinesLiveData().observe(viewLifecycleOwner){ rL ->
- viewModel.getLinesLiveData().observe(viewLifecycleOwner){
- //routesList = ArrayList(it)
- //routesList.sortWith(linesComparator)
routesByAgency.clear()
for (k in AGENCIES){
routesByAgency[k] = ArrayList()
}
-
- for(route in it){
+ val routesPrioByAg = HashMap<String, ArrayList<Pair<GtfsRoute,Int>>>()
+ for (ag in AGENCIES){
+ routesPrioByAg[ag] = ArrayList()
+ }
+ for(p in rL){
+ val route = p.first
val agency = route.agencyID
if(agency !in routesByAgency.keys){
- Log.e(DEBUG_TAG, "The agency $agency is not present in the predefined agencies (${routesByAgency.keys})")
+ Log.e(DEBUG_TAG, "The agency $agency for route ${p.first.gtfsId} is not in the predefined agencies (${routesByAgency.keys})")
}
routesByAgency[agency]?.add(route)
+ routesPrioByAg[agency]?.add(p) // I would print a debug here, but it's the same as above
}
//zip agencies and recyclerviews
- Companion.AGENCIES.zip(recViews) { ag, recView ->
- routesByAgency[ag]?.let { routeList ->
- if (routeList.size > 0) {
- routeList.sortWith(linesComparator)
- //val adapter = RouteOnlyLineAdapter(it.map { rt -> rt.shortName })
- val adapter = RouteAdapter(routeList, routeClickListener)
+ AGENCIES.zip(recViews) { ag, recView ->
+ routesPrioByAg[ag]?.let { routePrioList ->
+ if (routePrioList.isNotEmpty()) {
+ routePrioList.sortWith(linesPriorityComparator)
+ val adapter = RouteAdapter(routePrioList.map { it.first }, routeClickListener)
val lastQueryEmpty = if(ag in lastQueryEmptyForAgency.keys) lastQueryEmptyForAgency[ag]!! else true
if (lastQueryEmpty)
recView.adapter = adapter
@@ -148,7 +163,7 @@
lastQueryEmptyForAgency[ag] = true
}
- durations[ag] = if(routeList.size < 20) ViewUtils.DEF_DURATION else 1000
+ durations[ag] = if(routePrioList.size < 20) ViewUtils.DEF_DURATION else 1000
}
}
@@ -390,7 +405,7 @@
companion object {
- private const val COLUMN_WIDTH_DP=200
+ private const val COLUMN_WIDTH_DP=250
private const val AG_FAV = "fav"
private const val AG_URBAN = "gtt:U"
private const val AG_EXTRAURB ="gtt:E"
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
@@ -161,6 +161,12 @@
super.onCreate(savedInstanceState)
arguments?.let {
initialStopToShow = Stop.fromBundle(arguments)
+ if (initialStopToShow==null){
+
+ } else if(!initialStopToShow!!.hasCoords()){
+ //null the stop if it doesn't have coordinates, we cannot find it
+ initialStopToShow = null
+ }
}
}
@@ -352,9 +358,11 @@
if (initialStopToShow!=null){
val s = initialStopToShow!!
- mapReady.cameraPosition = CameraPosition.Builder().target(
- LatLng(s.latitude!!, s.longitude!!)
- ).zoom(DEFAULT_ZOOM).build()
+ if(s.hasCoords()){
+ mapReady.cameraPosition = CameraPosition.Builder().target(
+ LatLng(s.latitude!!, s.longitude!!)
+ ).zoom(DEFAULT_ZOOM).build()
+ }
restoredMapCamera.set(true)
} else{
var boundsRestored = false
@@ -437,6 +445,12 @@
override fun showOpenStopWithSymbolLayer(): Boolean {
return false
}
+ override fun hideStopOrBusBottomSheet(){
+ if (shownStopInBottomSheet?.ID == initialStopToShow?.ID){
+ initialStopToShow = null
+ }
+ super.hideStopOrBusBottomSheet()
+ }
override fun onAttach(context: Context) {
super.onAttach(context)
@@ -536,7 +550,7 @@
private fun showVehicleTripInBottomSheet(veh: String) {
val data = updatesByVehDict[veh] ?: return
- super.showVehicleTripInBottomSheet(veh) { patternCode ->
+ super.showVehicleTripInBottomSheet(veh) { patternCode, _ ->
map?.let { mapStateViewModel.saveMapState(it) }
fragmentListener?.openLineFromVehicle(
data.posUpdate.getLineGTFSFormat(),
@@ -553,7 +567,8 @@
initialStopToShow?.let{ s->
//show the stop in the bottom sheet
if(!initialStopShown && (s.ID in stopsShowing.map { it.ID })) {
- openStopInBottomSheet(s)
+ val stopToShow = stopsShowing.first { it.ID == s.ID }
+ openStopInBottomSheet(stopToShow)
initialStopShown = true
}
}
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ResultListFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/ResultListFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/ResultListFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/ResultListFragment.java
@@ -34,7 +34,6 @@
import android.view.ViewGroup;
import android.widget.*;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
import it.reyboz.bustorino.R;
import it.reyboz.bustorino.backend.FiveTNormalizer;
@@ -167,7 +166,7 @@
});
String displayName = getArguments().getString(ArrivalsFragment.STOP_TITLE);
setTextViewMessage(String.format(
- getString(R.string.passages), displayName));
+ getString(R.string.passages_fill), displayName));
break;
default:
throw new IllegalStateException("Argument passed was not of a supported type");
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
@@ -3,8 +3,6 @@
import android.Manifest;
import android.content.Context;
import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.view.Gravity;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/ArrivalsViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/ArrivalsViewModel.kt
--- a/app/src/main/java/it/reyboz/bustorino/viewmodels/ArrivalsViewModel.kt
+++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/ArrivalsViewModel.kt
@@ -5,22 +5,22 @@
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MediatorLiveData
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import it.reyboz.bustorino.backend.*
import it.reyboz.bustorino.backend.mato.MatoAPIFetcher
import it.reyboz.bustorino.data.NextGenDB
+import it.reyboz.bustorino.data.OldDataRepository
import it.reyboz.bustorino.middleware.RecursionHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicReference
class ArrivalsViewModel(application: Application): AndroidViewModel(application) {
// Arrivals of palina
val appContext: Context
- init {
- appContext = application.applicationContext
- }
val palinaLiveData = MediatorLiveData<Palina>()
val sourcesLiveData = MediatorLiveData<Passaggio.Source>()
@@ -29,9 +29,47 @@
val currentFetchers = MediatorLiveData<List<ArrivalsFetcher>>()
+ /// OLD REPO for stops instance
+ private val executor = Executors.newFixedThreadPool(2)
+ private val oldRepo = OldDataRepository(executor, NextGenDB.getInstance(application))
+
+ private var stopIdRequested = ""
+ private val stopFromDB = MutableLiveData<Stop>()
+ private val oldRepoStopCallback = OldDataRepository.Callback<List<Stop>>{ stopListRes ->
+ if(stopIdRequested.isEmpty()) return@Callback
+
+ if(stopListRes.isSuccess) {
+ val stopF = stopListRes.result!!.filter { s -> s.ID == stopIdRequested }
+ if (stopF.isEmpty()) {
+ Log.w(DEBUG_TAG, "Requested stop $stopIdRequested but is not in the list from database: ${stopListRes.result}")
+ } else{
+ stopFromDB.postValue(stopF[0])
+ Log.d(DEBUG_TAG, "Setting new stop ${stopF[0]} from database")
+ }
+ } else{
+ Log.e(DEBUG_TAG, "Requested stop ${stopIdRequested} from database but error occured: ${stopListRes.exception}")
+ }
+ }
+
+ init {
+ appContext = application.applicationContext
+ palinaLiveData.addSource(stopFromDB){
+ s ->
+ val hasSource = palinaLiveData.value?.passaggiSourceIfAny
+ Log.d(DEBUG_TAG, "Have current palina ${palinaLiveData.value!=null}, source passaggi $hasSource, new incoming stop $s from database")
+ val newp = Palina.mergePaline(palinaLiveData.value, Palina(s))
+ newp?.let { palinaLiveData.value = it }
+ }
+ }
+
+
fun requestArrivalsForStop(stopId: String, fetchers: List<ArrivalsFetcher>){
val context = appContext //application.applicationContext
currentFetchers.value = fetchers
+ //request stop from the DB
+ stopIdRequested = stopId
+ oldRepo.requestStopsWithGtfsIDs(listOf("gtt:$stopId"), oldRepoStopCallback)
+
viewModelScope.launch(Dispatchers.IO){
runArrivalsFetching(stopId, fetchers, context)
}
@@ -127,9 +165,7 @@
// Se abbiamo un risultato OK, restituiamo la palina
if (resultRef.get() == Fetcher.Result.OK) {
- //set data
- resultLiveData.postValue(Fetcher.Result.OK)
- palinaLiveData.postValue(palina)
+ setResultAndPalinaFromFetchers(palina, Fetcher.Result.OK)
//TODO: Rotate the fetchers appropriately
return
}
@@ -140,13 +176,18 @@
//failedAll = true
// Se abbiamo comunque una palina, la restituiamo
- if (resultPalina != null) {
- resultLiveData.postValue(resultRef.get())
- palinaLiveData.postValue(resultPalina)
+ resultPalina?.let {
+ setResultAndPalinaFromFetchers(it, resultRef.get())
}
}
+ private fun setResultAndPalinaFromFetchers(palina: Palina, fetcherResult: Fetcher.Result) {
+ resultLiveData.postValue(fetcherResult)
+ Log.d(DEBUG_TAG, "Have new result palina for stop ${palina.ID}, source ${palina.passaggiSourceIfAny} has coords: ${palina.hasCoords()}")
+ Log.d(DEBUG_TAG, "Old palina liveData is: ${palinaLiveData.value?.stopDisplayName}, has Coords ${palinaLiveData.value?.hasCoords()}")
+ palinaLiveData.postValue(Palina.mergePaline(palina, palinaLiveData.value))
+ }
companion object{
const val DEBUG_TAG="BusTO-ArrivalsViMo"
diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesGridShowingViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesGridShowingViewModel.kt
--- a/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesGridShowingViewModel.kt
+++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesGridShowingViewModel.kt
@@ -39,15 +39,27 @@
fun getLineQueryValue():String{
return queryLiveData.value ?: ""
}
- private val filteredLinesLiveData = MediatorLiveData<List<GtfsRoute>>()
- fun getLinesLiveData(): LiveData<List<GtfsRoute>> {
- return filteredLinesLiveData
- }
+ private val filteredLinesLiveData = MediatorLiveData<List<Pair<GtfsRoute,Int >>>()
+ fun getLinesLiveData() = filteredLinesLiveData
- private fun filterLinesForQuery(lines: List<GtfsRoute>, query: String): List<GtfsRoute>{
- val result= lines.filter { r-> query.lowercase() in r.shortName.lowercase() }
+ private fun filterLinesForQuery(lines: List<GtfsRoute>, query: String): ArrayList<Pair<GtfsRoute,Int>>{
+ var result= lines.filter { r-> query.lowercase() in r.shortName.lowercase() }
+ //EXCLUDE gtt:F - ferrovie (luckily, gtt does not run rail service anymore)
+ result = result.filter { r -> r.agencyID != "gtt:F" }
- return result
+ val out = ArrayList<Pair<GtfsRoute,Int>>()
+ for (r in result){
+ out.add(Pair(r,1))
+ }
+ // add those matching the query in the description
+ for (r: GtfsRoute in lines) {
+ if (query.lowercase() in r.description.lowercase()) {
+ if (r !in result){
+ out.add(Pair(r,2))
+ }
+ }
+ }
+ return out
}
init {
diff --git a/app/src/main/res/drawable/ic_star_filled.xml b/app/src/main/res/drawable/ic_star_filled.xml
--- a/app/src/main/res/drawable/ic_star_filled.xml
+++ b/app/src/main/res/drawable/ic_star_filled.xml
@@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="28dp"
- android:height="28dp"
+ android:width="30dp"
+ android:height="30dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
diff --git a/app/src/main/res/drawable/ic_star_outline.xml b/app/src/main/res/drawable/ic_star_outline.xml
--- a/app/src/main/res/drawable/ic_star_outline.xml
+++ b/app/src/main/res/drawable/ic_star_outline.xml
@@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="28dp"
- android:height="28dp"
+ android:width="30dp"
+ android:height="30dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
diff --git a/app/src/main/res/drawable/road_map_line.xml b/app/src/main/res/drawable/road_map_line.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/drawable/road_map_line.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="30dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24"
+ android:width="30dp">
+
+ <path android:fillColor="?colorPrimary" android:pathData="M4,6.143V18.967L9.065,16.796L15.065,19.796L20,17.681V4.857L21.303,4.299C21.557,4.19 21.851,4.307 21.96,4.561C21.986,4.624 22,4.691 22,4.758V19L15,22L9,19L2.697,21.701C2.443,21.81 2.149,21.692 2.04,21.439C2.014,21.376 2,21.309 2,21.242V7L4,6.143ZM16.243,11.243L12,15.485L7.757,11.243C5.414,8.899 5.414,5.101 7.757,2.757C10.101,0.414 13.899,0.414 16.243,2.757C18.586,5.101 18.586,8.899 16.243,11.243ZM12,12.657L14.828,9.828C16.39,8.266 16.39,5.734 14.828,4.172C13.266,2.609 10.734,2.609 9.172,4.172C7.609,5.734 7.609,8.266 9.172,9.828L12,12.657Z"/>
+
+</vector>
diff --git a/app/src/main/res/layout/entry_bus_line_passage.xml b/app/src/main/res/layout/entry_bus_line_passage.xml
--- a/app/src/main/res/layout/entry_bus_line_passage.xml
+++ b/app/src/main/res/layout/entry_bus_line_passage.xml
@@ -7,6 +7,9 @@
android:paddingBottom="8dp"
android:paddingStart="10dp"
android:paddingEnd="16dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true"
+ android:focusable="true"
>
diff --git a/app/src/main/res/layout/entry_line_num_descr.xml b/app/src/main/res/layout/entry_line_name_description.xml
rename from app/src/main/res/layout/entry_line_num_descr.xml
rename to app/src/main/res/layout/entry_line_name_description.xml
--- a/app/src/main/res/layout/entry_line_num_descr.xml
+++ b/app/src/main/res/layout/entry_line_name_description.xml
@@ -4,7 +4,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="5dp"
- android:layout_margin="4dp"
+ android:layout_margin="8dp"
>
<RelativeLayout
android:layout_width="match_parent"
@@ -19,7 +19,7 @@
app:cardElevation="0sp"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
- android:padding="3dp"
+ android:padding="6dp"
app:cardBackgroundColor="@color/orange_500"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
@@ -48,18 +48,23 @@
</TextView>
</RelativeLayout>
</androidx.cardview.widget.CardView>
- <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:id="@+id/lineDirectionTextView"
- android:layout_weight="8"
android:textSize="20sp"
- android:text="@string/route_towards_destination"
+ android:text="@string/hello_blank_fragment"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
- android:layout_marginEnd="10dp"
- android:layout_alignParentTop="true"
+ android:layout_marginEnd="2dp"
android:layout_toEndOf="@id/innerCardView"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="5dp"
+ android:layout_marginStart="13dp"
+ android:layout_marginBottom="10dp"
+ android:minHeight="52sp"
/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_arrivals.xml b/app/src/main/res/layout/fragment_arrivals.xml
--- a/app/src/main/res/layout/fragment_arrivals.xml
+++ b/app/src/main/res/layout/fragment_arrivals.xml
@@ -13,37 +13,78 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="5dp"
- app:cardElevation="4dp"
+ app:cardElevation="5dp"
android:layout_alignParentTop="true"
android:layout_marginStart="8sp"
android:layout_marginEnd="8sp"
android:layout_marginTop="5sp"
- android:padding="5sp"
+ android:padding="8sp"
>
-
- <TextView
- android:id="@+id/messageTextView"
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_toStartOf="@+id/addToFavorites"
- android:layout_toLeftOf="@+id/addToFavorites"
-
- android:foreground="?attr/selectableItemBackground"
- android:gravity="center_vertical"
- android:minHeight="40dp"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
-
- <ImageButton
- android:id="@+id/addToFavorites"
- android:layout_width="45dp"
- android:layout_height="match_parent"
- android:layout_gravity="end"
- android:background="@android:color/transparent"
- android:foreground="?attr/selectableItemBackground"
- app:srcCompat="@drawable/ic_star_outline"
- tools:ignore="OnClick"/>
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/arrivalsTextView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_margin="8dp"
+ android:gravity="center_vertical"
+ android:text="@string/passages"
+ android:minHeight="35dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ app:layout_constraintHorizontal_bias="0.0"
+ android:visibility="visible"/>
+ <TextView
+ android:id="@+id/messageTextView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:layout_marginStart="12dp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/addToFavorites"
+ app:layout_constraintStart_toEndOf="@id/arrivalsTextView"
+ android:foreground="?attr/selectableItemBackground"
+
+ android:gravity="center_vertical"
+ android:minHeight="35dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textSize="19sp"/>
+ <ImageButton
+ android:id="@+id/addToFavorites"
+ android:layout_width="35dp"
+ android:layout_height="35dp"
+ android:layout_gravity="end"
+ android:layout_margin="5dp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/openInMapButton"
+ app:layout_constraintStart_toEndOf="@id/messageTextView"
+ android:background="@android:color/transparent"
+ android:foreground="?attr/selectableItemBackground"
+ app:srcCompat="@drawable/ic_star_outline"
+ tools:ignore="OnClick"
+ />
+ <ImageButton
+ android:id="@+id/openInMapButton"
+ android:layout_width="35dp"
+ android:layout_height="35dp"
+ android:layout_gravity="end"
+ android:layout_margin="5dp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/addToFavorites"
+ android:background="@android:color/transparent"
+ android:foreground="?attr/selectableItemBackground"
+ app:srcCompat="@drawable/road_map_line"
+ app:tint="?colorPrimary"
+ tools:ignore="OnClick"
+ android:layout_marginEnd="12dp"
+ />
+ </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
diff --git a/app/src/main/res/menu/menu_arrivals_line_item.xml b/app/src/main/res/menu/menu_arrivals_line_item.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/menu/menu_arrivals_line_item.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/action_open_line"
+ android:title="@string/action_open_line"/>
+ <item
+ android:id="@+id/action_show_direction"
+ android:title="@string/action_show_direction"/>
+</menu>
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -41,7 +41,7 @@
<string name="message_check_at_least_one">Vérifiez cocher au moins un élément à importer !</string>
<string name="load_file_favorites">Importer les favoris depuis une sauvegarde</string>
<string name="load_preferences">Importer les préférences depuis une sauvegarde</string>
- <string name="passages">Arrivées à: %1$s</string>
+ <string name="passages_fill">Arrivées à: %1$s</string>
<string name="action_about_more">En savoir plus</string>
<string name="action_author">Rencontrer l\'auteur</string>
<string name="action_help">Aide</string>
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
@@ -18,7 +18,8 @@
<string name="no_arrivals_stop">Nessun passaggio trovato alla fermata</string>
<string name="searching_arrivals_fmt">Ricerca arrivi da %1$s</string>
<string name="parsing_error">Errore di lettura del sito 5T/GTT (dannato sito!)</string>
- <string name="passages">Fermata: %1$s</string>
+ <string name="passages_fill">Fermata: %1$s</string>
+ <string name="passages">Fermata:</string>
<string name="line">Linea</string>
<string name="lines">Linee</string>
<string name="urban_lines">Linee urbane</string>
@@ -45,6 +46,8 @@
<string name="action_source">Codice sorgente</string>
<string name="action_licence">Licenza</string>
<string name="action_author">Incontra l\'autore</string>
+ <string name="action_open_line">Mostra linea</string>
+ <string name="action_show_direction">Vedi direzione</string>
<string name="added_in_favorites">Fermata aggiunta ai preferiti</string>
<string name="cant_add_to_favorites">Impossibile aggiungere ai preferiti (memoria piena o database corrotto?)!</string>
<string name="title_activity_favorites">Preferiti</string>
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -140,7 +140,7 @@
<string name="insert_bus_stop_number_error">Voer bushalte nummer in</string>
<string name="network_error">Check je internetverbinding!</string>
<string name="query_too_short">Te korte naam, typ meer karakters en probeer opnieuw</string>
- <string name="passages">Aankomsten om: %1$s</string>
+ <string name="passages_fill">Aankomsten om: %1$s</string>
<string name="lines_fill">Lijnen: %1$s</string>
<string name="action_about_more">Meer over</string>
<string name="title_activity_favorites">Favorieten</string>
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
@@ -31,7 +31,8 @@
<string name="parsing_error">Error parsing the 5T/GTT website (damn site!)</string>
<string name="query_too_short">Name too short, type more characters and retry
</string> <!-- TODO: carry out experiments to determine the best wording for this message and publish a paper with the findings -->
- <string name="passages">Arrivals at: %1$s</string>
+ <string name="passages_fill">Arrivals at: %1$s</string>
+ <string name="passages">Arrivals at:</string>
<string name="results">Choose the bus stop…</string>
<string name="line">Line</string>
<string name="lines">Lines</string>
@@ -142,6 +143,8 @@
<string name="cant_add_to_favorites">Cannot add to favorites (storage full or corrupted database?)!</string>
<string name="action_view_on_map">View on a map</string>
+ <string name="action_open_line">Show line details</string>
+ <string name="action_show_direction">Show full direction</string>
<string name="cannot_show_on_map_no_activity">Cannot find any application to show it in</string>
<string name="cannot_show_on_map_no_position">Cannot find the position of the stop</string>

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 22, 15:28 (21 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1864826
Default Alt Text
D222.1776864501.diff (69 KB)

Event Timeline