diff --git a/Hyperrail/src/main/java/be/hyperrail/android/adapter/MultilangAutocompleteAdapter.java b/Hyperrail/src/main/java/be/hyperrail/android/adapter/MultilangAutocompleteAdapter.java new file mode 100644 index 00000000..a1ae3001 --- /dev/null +++ b/Hyperrail/src/main/java/be/hyperrail/android/adapter/MultilangAutocompleteAdapter.java @@ -0,0 +1,201 @@ +package be.hyperrail.android.adapter; + +import android.database.DataSetObserver; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.ListAdapter; +import android.widget.TextView; + +import androidx.collection.ArraySet; +import androidx.fragment.app.FragmentActivity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +import be.hyperrail.opentransportdata.common.models.StopLocation; + +public class MultilangAutocompleteAdapter implements Filterable, ListAdapter { + + private final FragmentActivity activity; + private final int layoutResourceId; + private final StopLocation[] stations; + + private List visibleStops = new ArrayList<>(); + private Set observers = new ArraySet<>(); + + public MultilangAutocompleteAdapter(FragmentActivity activity, int layoutResourceId, StopLocation[] stations) { + this.activity = activity; + this.layoutResourceId = layoutResourceId; + this.stations = stations; + } + + @Override + public Filter getFilter() { + return new Filter() { + class MultilangFilterResults extends FilterResults { + public MultilangFilterResults(List results) { + this.values = results; + this.count = results.size(); + } + } + + @Override + protected FilterResults performFiltering(CharSequence constraint) { + constraint = constraint.toString().toLowerCase(); + List list = new ArrayList<>(); + for (StopLocation s : stations) { + if (stationNameContains(constraint, s)) { + list.add(s); + } + } + Collections.sort(list, new AutocompleteSortComparator(constraint)); + return new MultilangFilterResults(list); + } + + private boolean stationNameContains(CharSequence constraint, StopLocation s) { + if (s.getName().toLowerCase().contains(constraint)) { + return true; // primary name is not always included in the translations + } + for (String name : s.getTranslations().values()) { + if (name.toLowerCase().contains(constraint)) { + return true; + } + } + return false; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + //noinspection unchecked + updateVisibleStops((List) results.values); + } + }; + } + + private void updateVisibleStops(List stops) { + this.visibleStops = stops; + for (DataSetObserver observer : observers) { + observer.onChanged(); + } + } + + @Override + public boolean areAllItemsEnabled() { + return true; // No separators or other similar elements in this adapter + } + + @Override + public boolean isEnabled(int position) { + return true; // No separators or other similar elements in this adapter + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + this.observers.add(observer); + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + this.observers.remove(observer); + } + + @Override + public int getCount() { + return visibleStops.size(); + } + + @Override + public StopLocation getItem(int position) { + return visibleStops.get(position); + } + + @Override + public long getItemId(int position) { + return getItem(position).getSemanticId().hashCode(); + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return createViewFromResource(activity.getLayoutInflater(), position, convertView, parent, layoutResourceId); + } + + @Override + public int getItemViewType(int position) { + return 0; + } + + @Override + public int getViewTypeCount() { + return 1; + } + + @Override + public boolean isEmpty() { + return visibleStops.isEmpty(); + } + + // From ArrayAdapter + private View createViewFromResource(LayoutInflater inflater, int position, View convertView, ViewGroup parent, int resource) { + final View view; + final TextView text; + + if (convertView == null) { + view = inflater.inflate(resource, parent, false); + } else { + view = convertView; + } + + // If no custom field is assigned, assume the whole resource is a TextView + text = (TextView) view; + + final StopLocation item = getItem(position); + text.setText(item.getLocalizedName()); + + return view; + } + + private static class AutocompleteSortComparator implements Comparator { + private final String lowerCaseConstraint; + + public AutocompleteSortComparator(CharSequence lowerCaseConstraint) { + this.lowerCaseConstraint = lowerCaseConstraint.toString(); + } + + @Override + public int compare(StopLocation o1, StopLocation o2) { + boolean o1nameAdvantage = nameStartsWith(o1, lowerCaseConstraint); + boolean o2nameAdvantage = nameStartsWith(o2, lowerCaseConstraint); + if (o1nameAdvantage && !o2nameAdvantage) { + return -1; + } + if (o2nameAdvantage && !o1nameAdvantage) { + return 1; + } + return Float.compare(o2.getAvgStopTimes(), o1.getAvgStopTimes()); + } + + private boolean nameStartsWith(StopLocation location, String prefix) { + if (location.getName().toLowerCase().startsWith(prefix)) { + return true; // Name is not always included in the translations + } + for (String name : location.getTranslations().values()) { + if (name.toLowerCase().startsWith(prefix)) { + return true; + } + } + return false; + } + } +} diff --git a/Hyperrail/src/main/java/be/hyperrail/android/fragments/RouteSearchFragment.java b/Hyperrail/src/main/java/be/hyperrail/android/fragments/RouteSearchFragment.java index a4ee3586..b1345dd1 100644 --- a/Hyperrail/src/main/java/be/hyperrail/android/fragments/RouteSearchFragment.java +++ b/Hyperrail/src/main/java/be/hyperrail/android/fragments/RouteSearchFragment.java @@ -52,6 +52,7 @@ import be.hyperrail.android.R; import be.hyperrail.android.activities.searchresult.RouteActivity; +import be.hyperrail.android.adapter.MultilangAutocompleteAdapter; import be.hyperrail.android.adapter.OnRecyclerItemClickListener; import be.hyperrail.android.adapter.OnRecyclerItemLongClickListener; import be.hyperrail.android.adapter.RouteSuggestionsCardAdapter; @@ -76,8 +77,6 @@ public class RouteSearchFragment extends Fragment implements OnRecyclerItemClick private AutoCompleteTextView vToText; private TextView vDatetime; private Spinner vArriveDepart; - private LinearLayout vArriveDepartContainer; - private DateTime searchDateTime = null; private PersistentQueryProvider persistentQueryProvider; @@ -123,8 +122,6 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { createKeyListeners(); createClickListeners(view); - vArriveDepartContainer = view.findViewById(R.id.container_arrivedepart); - if (this.getArguments() != null && (this.getArguments().containsKey("from") || this.getArguments().containsKey("to"))) { prefillFieldsFromArguments(); } else if (savedInstanceState != null) { @@ -433,7 +430,7 @@ protected void onPostExecute(List> suggestions) } } - private static class LoadAutoCompleteTask extends AsyncTask { + private static class LoadAutoCompleteTask extends AsyncTask { private WeakReference fragmentReference; @@ -443,15 +440,14 @@ private static class LoadAutoCompleteTask extends AsyncTask autocompleteAdapter = new ArrayAdapter<>(fragment.getActivity(), + MultilangAutocompleteAdapter autocompleteAdapter = new MultilangAutocompleteAdapter(fragment.getActivity(), android.R.layout.simple_dropdown_item_1line, stations); fragment.vFromText.setAdapter(autocompleteAdapter); diff --git a/build.gradle b/build.gradle index bdd347fe..394ddf88 100644 --- a/build.gradle +++ b/build.gradle @@ -8,8 +8,8 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:8.2.0' - classpath 'com.google.gms:google-services:4.3.15' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2' + classpath 'com.google.gms:google-services:4.4.0' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9' } } diff --git a/opentransport_be/src/main/java/be/hyperrail/opentransportdata/be/irail/NmbsToMlgDessinsAdapter.java b/opentransport_be/src/main/java/be/hyperrail/opentransportdata/be/irail/NmbsToMlgDessinsAdapter.java index c7ef4913..fc232fad 100644 --- a/opentransport_be/src/main/java/be/hyperrail/opentransportdata/be/irail/NmbsToMlgDessinsAdapter.java +++ b/opentransport_be/src/main/java/be/hyperrail/opentransportdata/be/irail/NmbsToMlgDessinsAdapter.java @@ -62,9 +62,29 @@ private static NmbsTrainType convertCarriage(String parentType, String subType, } break; case "M7": - // Fallback on M6 icons - newParentType = "M6"; - // Continue into M6 subtype handling + switch (subType) { + // Just handle all known M6 variants + case "BYU": + // BU + Y // With a little conductor room? + case "BU": + // 140/133 2nd class + newSubType = "B"; + break; + case "BUH": + // BU + H + case "BAU": + // Mixed 1st/2nd class + case "AU": + case "ABUH": + // 124/133 1st class + newSubType = "AB"; + break; + case "BDXH": + case "BMX": + newSubType = "BDX"; + break; + } + break; case "M6": switch (subType) { case "BXAA": diff --git a/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_ab_l.png b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_ab_l.png new file mode 100644 index 00000000..3f28c0eb Binary files /dev/null and b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_ab_l.png differ diff --git a/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_ab_r.png b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_ab_r.png new file mode 100644 index 00000000..6bb40afc Binary files /dev/null and b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_ab_r.png differ diff --git a/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_b_l.png b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_b_l.png new file mode 100644 index 00000000..87eb295e Binary files /dev/null and b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_b_l.png differ diff --git a/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_b_r.png b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_b_r.png new file mode 100644 index 00000000..2eab7a59 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_b_r.png differ diff --git a/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_bdx_l.png b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_bdx_l.png new file mode 100644 index 00000000..36411f74 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_bdx_l.png differ diff --git a/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_bdx_r.png b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_bdx_r.png new file mode 100644 index 00000000..ce7f80a2 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-hdpi/sncb_m7_bdx_r.png differ diff --git a/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_ab_l.png b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_ab_l.png new file mode 100644 index 00000000..d4c01c5b Binary files /dev/null and b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_ab_l.png differ diff --git a/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_ab_r.png b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_ab_r.png new file mode 100644 index 00000000..16c45d0f Binary files /dev/null and b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_ab_r.png differ diff --git a/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_b_l.png b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_b_l.png new file mode 100644 index 00000000..50b16eec Binary files /dev/null and b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_b_l.png differ diff --git a/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_b_r.png b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_b_r.png new file mode 100644 index 00000000..7708bf74 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_b_r.png differ diff --git a/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_bdx_l.png b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_bdx_l.png new file mode 100644 index 00000000..c4eeb2c2 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_bdx_l.png differ diff --git a/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_bdx_r.png b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_bdx_r.png new file mode 100644 index 00000000..fe15234b Binary files /dev/null and b/opentransport_be/src/main/res/drawable-mdpi/sncb_m7_bdx_r.png differ diff --git a/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_ab_l.png b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_ab_l.png new file mode 100644 index 00000000..06b7ed20 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_ab_l.png differ diff --git a/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_ab_r.png b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_ab_r.png new file mode 100644 index 00000000..6e88587a Binary files /dev/null and b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_ab_r.png differ diff --git a/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_b_l.png b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_b_l.png new file mode 100644 index 00000000..88517393 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_b_l.png differ diff --git a/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_b_r.png b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_b_r.png new file mode 100644 index 00000000..8486e25a Binary files /dev/null and b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_b_r.png differ diff --git a/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_bdx_l.png b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_bdx_l.png new file mode 100644 index 00000000..16654ea8 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_bdx_l.png differ diff --git a/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_bdx_r.png b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_bdx_r.png new file mode 100644 index 00000000..1adb0902 Binary files /dev/null and b/opentransport_be/src/main/res/drawable-xhdpi/sncb_m7_bdx_r.png differ