diff --git a/app/src/main/java/it/reyboz/bustorino/adapters/AdapterClickListener.java b/app/src/main/java/it/reyboz/bustorino/adapters/AdapterClickListener.java new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/adapters/AdapterClickListener.java @@ -0,0 +1,6 @@ +package it.reyboz.bustorino.adapters; + +public interface AdapterClickListener { + + void onAdapterClickListener(T element); +} 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 @@ -27,14 +27,11 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.TextView; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; +import java.util.*; +import androidx.recyclerview.widget.RecyclerView; import it.reyboz.bustorino.R; import it.reyboz.bustorino.backend.Palina; import it.reyboz.bustorino.backend.Passaggio; @@ -42,6 +39,7 @@ import it.reyboz.bustorino.backend.utils; import it.reyboz.bustorino.util.PassaggiSorter; import it.reyboz.bustorino.util.RouteSorterByArrivalTime; +import org.jetbrains.annotations.NotNull; /** * This once was a ListView Adapter for BusLine[]. @@ -52,9 +50,9 @@ * @author Valerio Bozzolan * @author Ludovico Pavesi */ -public class PalinaAdapter extends ArrayAdapter implements SharedPreferences.OnSharedPreferenceChangeListener { - private LayoutInflater li; - private static int row_layout = R.layout.entry_bus_line_passage; +public class PalinaAdapter extends RecyclerView.Adapter implements SharedPreferences.OnSharedPreferenceChangeListener { + + private static final int ROW_LAYOUT = R.layout.entry_bus_line_passage; private static final int metroBg = R.drawable.route_background_metro; private static final int busBg = R.drawable.route_background_bus; private static final int extraurbanoBg = R.drawable.route_background_bus_long_distance; @@ -65,98 +63,22 @@ private final String KEY_CAPITALIZE; private Capitalize capit; - //private static final int cityIcon = R.drawable.city; - - // hey look, a pattern! - private static class ViewHolder { - TextView rowStopIcon; - TextView rowRouteDestination; - TextView rowRouteTimetable; - } - private static Capitalize getCapitalize(SharedPreferences shPr, String key){ - String capitalize = shPr.getString(key, ""); - - switch (capitalize.trim()){ - case "KEEP": - return Capitalize.DO_NOTHING; - case "CAPITALIZE_ALL": - return Capitalize.ALL; - - case "CAPITALIZE_FIRST": - return Capitalize.FIRST; - } - return Capitalize.DO_NOTHING; - } - - public PalinaAdapter(Context context, Palina p) { - super(context, row_layout, p.queryAllRoutes()); - li = LayoutInflater.from(context); - Comparator sorter = null; - if (p.getPassaggiSourceIfAny()== Passaggio.Source.GTTJSON){ - sorter = new PassaggiSorter(); - } - for(Route r: p.queryAllRoutes()){ - if (sorter==null) Collections.sort(r.passaggi); - else Collections.sort(r.passaggi, sorter); - } - sort(new RouteSorterByArrivalTime()); - /* - sort(new Comparator() { - - @Override - public int compare(Route route, Route t1) { - LinesNameSorter sorter = new LinesNameSorter(); - if(route.getNameForDisplay()!= null){ - if(t1.getNameForDisplay()!=null){ - return sorter.compare(route.getNameForDisplay(), t1.getNameForDisplay()); - } - else return -1; - } else if(t1.getNameForDisplay()!=null){ - return +1; - } - else return 0; - } - }); - - */ - KEY_CAPITALIZE = context.getString(R.string.pref_arrival_times_capit); - SharedPreferences defSharPref = PreferenceManager.getDefaultSharedPreferences(context); - defSharPref.registerOnSharedPreferenceChangeListener(this); - this.capit = getCapitalize(defSharPref, KEY_CAPITALIZE); - } + private final List mRoutes; + private final AdapterClickListener mRouteListener; - /** - * Some parts taken from the AdapterBusLines class.
- * Some parts inspired by these enlightening tutorials:
- * http://www.simplesoft.it/android/guida-agli-adapter-e-le-listview-in-android.html
- * https://www.codeofaninja.com/2013/09/android-viewholder-pattern-example.html
- * And some other bits and bobs TIRATI FUORI DAL NULLA CON L'INTUIZIONE INTELLETTUALE PERCHÉ - * SEMBRA CHE NESSUNO ABBIA LA MINIMA IDEA DI COME FUNZIONA UN ADAPTER SU ANDROID. - */ @NonNull + @NotNull @Override - public View getView(int position, View convertView, @NonNull ViewGroup parent) { - ViewHolder vh; - - if(convertView == null) { - // INFLATE! - // setting a parent here is not supported and causes a fatal exception, apparently. - convertView = li.inflate(row_layout, null); - - // STORE TEXTVIEWS! - vh = new ViewHolder(); - vh.rowStopIcon = (TextView) convertView.findViewById(R.id.routeID); - vh.rowRouteDestination = (TextView) convertView.findViewById(R.id.routeDestination); - vh.rowRouteTimetable = (TextView) convertView.findViewById(R.id.routesThatStopHere); + public PalinaViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(ROW_LAYOUT, parent, false); + return new PalinaViewHolder(view); + } - // STORE VIEWHOLDER IN\ON\OVER\UNDER\ABOVE\BESIDE THE VIEW! - convertView.setTag(vh); - } else { - // RECOVER THIS STUFF! - vh = (ViewHolder) convertView.getTag(); - } + @Override + public void onBindViewHolder(@NonNull @NotNull PalinaViewHolder vh, int position) { + final Route route = mRoutes.get(position); - Route route = getItem(position); vh.rowStopIcon.setText(route.getNameForDisplay()); if(route.destinazione==null || route.destinazione.length() == 0) { vh.rowRouteDestination.setVisibility(View.GONE); @@ -184,6 +106,11 @@ } vh.rowRouteDestination.setText(dest); + + //set click listener + vh.itemView.setOnClickListener(view -> { + mRouteListener.onAdapterClickListener(route); + }); } switch (route.type) { @@ -223,9 +150,82 @@ vh.rowRouteTimetable.setText(route.getPassaggiToString()); } - return convertView; } + @Override + public int getItemCount() { + return mRoutes.size(); + } + + //private static final int cityIcon = R.drawable.city; + + // hey look, a pattern! + public static class PalinaViewHolder extends RecyclerView.ViewHolder { + final TextView rowStopIcon; + final TextView rowRouteDestination; + final TextView rowRouteTimetable; + + public PalinaViewHolder(@NonNull @NotNull View view) { + super(view); + /* + convertView.findViewById(R.id.routeID); + vh.rowRouteDestination = (TextView) convertView.findViewById(R.id.routeDestination); + vh.rowRouteTimetable = (TextView) convertView.findViewById(R.id.routesThatStopHere); + */ + rowStopIcon = view.findViewById(R.id.routeID); + rowRouteDestination = view.findViewById(R.id.routeDestination); + rowRouteTimetable = view.findViewById(R.id.routesThatStopHere); + } + } + private static Capitalize getCapitalize(SharedPreferences shPr, String key){ + String capitalize = shPr.getString(key, ""); + + switch (capitalize.trim()){ + case "KEEP": + return Capitalize.DO_NOTHING; + case "CAPITALIZE_ALL": + return Capitalize.ALL; + + case "CAPITALIZE_FIRST": + return Capitalize.FIRST; + } + return Capitalize.DO_NOTHING; + } + + public PalinaAdapter(Context context, Palina p, AdapterClickListener listener, boolean hideEmptyRoutes) { + Comparator sorter = null; + if (p.getPassaggiSourceIfAny()== Passaggio.Source.GTTJSON){ + sorter = new PassaggiSorter(); + } + final List routes; + if (hideEmptyRoutes){ + // build the routes by filtering them + routes = new ArrayList<>(); + for(Route r: p.queryAllRoutes()){ + //add only if there is at least one passage + if (r.numPassaggi()>0){ + routes.add(r); + } + } + } else + routes = p.queryAllRoutes(); + for(Route r: routes){ + if (sorter==null) Collections.sort(r.passaggi); + else Collections.sort(r.passaggi, sorter); + } + + Collections.sort(routes,new RouteSorterByArrivalTime()); + + mRoutes = routes; + KEY_CAPITALIZE = context.getString(R.string.pref_arrival_times_capit); + SharedPreferences defSharPref = PreferenceManager.getDefaultSharedPreferences(context); + defSharPref.registerOnSharedPreferenceChangeListener(this); + this.capit = getCapitalize(defSharPref, KEY_CAPITALIZE); + + this.mRouteListener = listener; + } + + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { diff --git a/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt b/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt @@ -0,0 +1,48 @@ +package it.reyboz.bustorino.adapters + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import it.reyboz.bustorino.R +import it.reyboz.bustorino.backend.Palina + +class RouteOnlyLineAdapter (val routeNames: List) : + RecyclerView.Adapter() { + + /** + * Provide a reference to the type of views that you are using + * (custom ViewHolder) + */ + class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { + val textView: TextView + + init { + // Define click listener for the ViewHolder's View + textView = view.findViewById(R.id.routeBallID) + } + } + constructor(palina: Palina, showOnlyEmpty: Boolean): this(palina.routesNamesWithNoPassages) + + // Create new views (invoked by the layout manager) + override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { + // Create a new view, which defines the UI of the list item + val view = LayoutInflater.from(viewGroup.context) + .inflate(R.layout.round_line_header, viewGroup, false) + + return ViewHolder(view) + } + + // Replace the contents of a view (invoked by the layout manager) + override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { + + // Get element from your dataset at this position and replace the + // contents of the view with that element + viewHolder.textView.text = routeNames[position] + } + + // Return the size of your dataset (invoked by the layout manager) + override fun getItemCount() = routeNames.size + +} 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 @@ -400,5 +400,18 @@ if (min == Integer.MAX_VALUE) return 0; else return min; } + + public ArrayList getRoutesNamesWithNoPassages(){ + ArrayList mList = new ArrayList<>(); + if(routes==null || routes.size() == 0){ + return mList; + } + for(Route r: routes){ + if(r.numPassaggi()==0) + mList.add(r.getNameForDisplay()); + } + + return mList; + } //private void mergeRoute } \ No newline at end of file diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.java @@ -18,13 +18,16 @@ package it.reyboz.bustorino.fragments; +import android.annotation.SuppressLint; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.widget.*; import androidx.annotation.Nullable; import androidx.annotation.NonNull; +import androidx.core.widget.NestedScrollView; import androidx.loader.app.LoaderManager; import androidx.loader.content.CursorLoader; import androidx.loader.content.Loader; @@ -33,17 +36,19 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.ListAdapter; -import android.widget.TextView; -import android.widget.Toast; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import it.reyboz.bustorino.R; +import it.reyboz.bustorino.adapters.AdapterClickListener; import it.reyboz.bustorino.adapters.PalinaAdapter; +import it.reyboz.bustorino.adapters.RouteOnlyLineAdapter; import it.reyboz.bustorino.backend.ArrivalsFetcher; import it.reyboz.bustorino.backend.DBStatusManager; import it.reyboz.bustorino.backend.Fetcher; @@ -57,8 +62,10 @@ import it.reyboz.bustorino.data.NextGenDB; import it.reyboz.bustorino.data.UserDB; import it.reyboz.bustorino.middleware.AsyncStopFavoriteAction; +import it.reyboz.bustorino.util.LinesNameSorter; +import it.reyboz.bustorino.util.ViewUtils; -public class ArrivalsFragment extends ResultListFragment implements LoaderManager.LoaderCallbacks { +public class ArrivalsFragment extends ResultBaseFragment implements LoaderManager.LoaderCallbacks { private final static String KEY_STOP_ID = "stopid"; private final static String KEY_STOP_NAME = "stopname"; @@ -81,11 +88,41 @@ //Views protected ImageButton addToFavorites; protected TextView timesSourceTextView; + protected TextView messageTextView; + protected RecyclerView arrivalsRecyclerView; + private PalinaAdapter mListAdapter = null; + + //private NestedScrollView theScrollView; + protected RecyclerView noArrivalsRecyclerView; + private RouteOnlyLineAdapter noArrivalsAdapter; + private TextView noArrivalsTitleView; + private GridLayoutManager layoutManager; + + //private View canaryEndView; private List fetchers = null; //new ArrayList<>(Arrays.asList(utils.getDefaultArrivalsFetchers())); private boolean reloadOnResume = true; + private final AdapterClickListener mRouteClickListener = route -> { + String routeName; + + routeName = FiveTNormalizer.routeInternalToDisplay(route.getNameForDisplay()); + if (routeName == null) { + routeName = route.getNameForDisplay(); + } + if(getContext()==null) + Log.e(DEBUG_TAG, "Touched on a route but Context is null"); + else if (route.destinazione == null || route.destinazione.length() == 0) { + Toast.makeText(getContext(), + getString(R.string.route_towards_unknown, routeName), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(getContext(), + getString(R.string.route_towards_destination, routeName, route.destinazione), Toast.LENGTH_SHORT).show(); + } + + }; + public static ArrivalsFragment newInstance(String stopID){ return newInstance(stopID, null); } @@ -95,7 +132,7 @@ Bundle args = new Bundle(); args.putString(KEY_STOP_ID,stopID); //parameter for ResultListFragmentrequestArrivalsForStopID - args.putSerializable(LIST_TYPE,FragmentKind.ARRIVALS); + //args.putSerializable(LIST_TYPE,FragmentKind.ARRIVALS); if (stopName != null){ args.putString(KEY_STOP_NAME,stopName); } @@ -103,6 +140,10 @@ return fragment; } + public static String getFragmentTag(Palina p) { + return "palina_"+p.ID; + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -140,7 +181,14 @@ View root = inflater.inflate(R.layout.fragment_arrivals, container, false); messageTextView = root.findViewById(R.id.messageTextView); addToFavorites = root.findViewById(R.id.addToFavorites); - resultsListView = root.findViewById(R.id.resultsListView); + //theScrollView = root.findViewById(R.id.arrivalsScrollView); + // recyclerview holding the arrival times + arrivalsRecyclerView = root.findViewById(R.id.arrivalsRecyclerView); + final LinearLayoutManager manager = new LinearLayoutManager(getContext()); + arrivalsRecyclerView.setLayoutManager(manager); + final DividerItemDecoration mDividerItemDecoration = new DividerItemDecoration(arrivalsRecyclerView.getContext(), + manager.getOrientation()); + arrivalsRecyclerView.addItemDecoration(mDividerItemDecoration); timesSourceTextView = root.findViewById(R.id.timesSourceTextView); timesSourceTextView.setOnLongClickListener(view -> { if(!fetchersChangeRequestPending){ @@ -165,25 +213,9 @@ toggleLastStopToFavorites(); }); - resultsListView.setOnItemClickListener((parent, view, position, id) -> { - String routeName; - - Route r = (Route) parent.getItemAtPosition(position); - routeName = FiveTNormalizer.routeInternalToDisplay(r.getNameForDisplay()); - if (routeName == null) { - routeName = r.getNameForDisplay(); - } - if (r.destinazione == null || r.destinazione.length() == 0) { - Toast.makeText(getContext(), - getString(R.string.route_towards_unknown, routeName), Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(getContext(), - getString(R.string.route_towards_destination, routeName, r.destinazione), Toast.LENGTH_SHORT).show(); - } - }); String displayName = getArguments().getString(STOP_TITLE); if(displayName!=null) - setTextViewMessage(String.format( + setTextViewMessage(String.format( getString(R.string.passages), displayName)); @@ -193,6 +225,19 @@ messageTextView.setText(probablemessage); messageTextView.setVisibility(View.VISIBLE); } + //no arrivals stuff + noArrivalsRecyclerView = root.findViewById(R.id.noArrivalsRecyclerView); + layoutManager = new GridLayoutManager(getContext(),60); + layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + return 12; + } + }); + noArrivalsRecyclerView.setLayoutManager(layoutManager); + noArrivalsTitleView = root.findViewById(R.id.noArrivalsMessageTextView); + + //canaryEndView = root.findViewById(R.id.canaryEndView); /*String sourcesTextViewData = getArguments().getString(SOURCES_TEXT); if (sourcesTextViewData!=null){ @@ -208,13 +253,23 @@ public void onResume() { super.onResume(); LoaderManager loaderManager = getLoaderManager(); - Log.d(DEBUG_TAG, "OnResume, justCreated "+justCreated); + Log.d(DEBUG_TAG, "OnResume, justCreated "+justCreated+", lastUpdatedPalina is: "+lastUpdatedPalina); /*if(needUpdateOnAttach){ updateFragmentData(null); needUpdateOnAttach=false; }*/ + /*if(lastUpdatedPalina!=null){ + updateFragmentData(null); + showArrivalsSources(lastUpdatedPalina); + }*/ + if (mListAdapter!=null) + resetListAdapter(mListAdapter); + if(noArrivalsAdapter!=null){ + noArrivalsRecyclerView.setAdapter(noArrivalsAdapter); + + } + if(stopID!=null){ - //refresh the arrivals if(!justCreated){ fetchers = utils.getDefaultArrivalsFetchers(getContext()); adjustFetchersToSource(); @@ -314,12 +369,35 @@ else needUpdateOnAttach = true; } else { - final PalinaAdapter adapter = new PalinaAdapter(getContext(), lastUpdatedPalina); + final PalinaAdapter adapter = new PalinaAdapter(getContext(), lastUpdatedPalina, mRouteClickListener, true); showArrivalsSources(lastUpdatedPalina); - super.resetListAdapter(adapter); + resetListAdapter(adapter); + + final ArrayList routesWithNoPassages = lastUpdatedPalina.getRoutesNamesWithNoPassages(); + Collections.sort(routesWithNoPassages, new LinesNameSorter()); + noArrivalsAdapter = new RouteOnlyLineAdapter(routesWithNoPassages); + if(noArrivalsRecyclerView!=null){ + noArrivalsRecyclerView.setAdapter(noArrivalsAdapter); + //hide the views if there are no empty routes + if(routesWithNoPassages.isEmpty()){ + noArrivalsRecyclerView.setVisibility(View.GONE); + noArrivalsTitleView.setVisibility(View.GONE); + } else { + noArrivalsRecyclerView.setVisibility(View.VISIBLE); + noArrivalsTitleView.setVisibility(View.VISIBLE); + } + } + + //canaryEndView.setVisibility(View.VISIBLE); + //check if canaryEndView is visible + //boolean isCanaryVisibile = ViewUtils.Companion.isViewPartiallyVisibleInScroll(canaryEndView, theScrollView); + //Log.d(DEBUG_TAG, "Canary view fully visibile: "+isCanaryVisibile); + } } + + /** * Set the message of the arrival times source * @param p Palina with the arrival times @@ -357,6 +435,8 @@ Log.w(DEBUG_TAG, "Tried to update the source fetcher but it didn't work"); final String base_message = getString(R.string.times_source_fmt, source_txt); timesSourceTextView.setText(base_message); + timesSourceTextView.setVisibility(View.VISIBLE); + if (p.getTotalNumberOfPassages() > 0) { timesSourceTextView.setVisibility(View.VISIBLE); } else { @@ -383,11 +463,6 @@ return adjustFetchersToSource(source); } - @Override - public void setNewListAdapter(ListAdapter adapter) { - throw new UnsupportedOperationException(); - } - /** * Update the message in the fragment * @@ -484,7 +559,22 @@ public void onLoaderReset(Loader loader) { //NOTHING TO DO } + protected void resetListAdapter(PalinaAdapter adapter) { + mListAdapter = adapter; + if (arrivalsRecyclerView != null) { + arrivalsRecyclerView.setAdapter(adapter); + arrivalsRecyclerView.setVisibility(View.VISIBLE); + } + } + /** + * Set the message textView + * @param message the whole message to write in the textView + */ + public void setTextViewMessage(String message) { + messageTextView.setText(message); + messageTextView.setVisibility(View.VISIBLE); + } public void toggleLastStopToFavorites() { @@ -553,7 +643,17 @@ @Override public void onDestroyView() { - getArguments().putString(SOURCES_TEXT, timesSourceTextView.getText().toString()); + arrivalsRecyclerView = null; + if(getArguments()!=null) { + getArguments().putString(SOURCES_TEXT, timesSourceTextView.getText().toString()); + getArguments().putString(MESSAGE_TEXT_VIEW, messageTextView.getText().toString()); + } super.onDestroyView(); } + + public boolean isFragmentForTheSameStop(Palina p) { + if (getTag() != null) + return getTag().equals(getFragmentTag(p)); + else return false; + } } diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/FragmentHelper.java b/app/src/main/java/it/reyboz/bustorino/fragments/FragmentHelper.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/FragmentHelper.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/FragmentHelper.java @@ -126,7 +126,7 @@ } else { arrivalsFragment = ArrivalsFragment.newInstance(p.ID); } - String probableTag = ResultListFragment.getFragmentTag(p); + String probableTag = ArrivalsFragment.getFragmentTag(p); attachFragmentToContainer(fm,arrivalsFragment,new AttachParameters(probableTag, true, addToBackStack)); } // DO NOT CALL `setListAdapter` ever on arrivals fragment diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java @@ -137,7 +137,7 @@ uri = Uri.parse(result.getContents()); // this apparently prevents NullPointerException. Somehow. } catch (NullPointerException e) { if (getContext()!=null) - Toast.makeText(getContext().getApplicationContext(), + Toast.makeText(getContext().getApplicationContext(), R.string.no_qrcode, Toast.LENGTH_SHORT).show(); return; } diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ResultBaseFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/ResultBaseFragment.java new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ResultBaseFragment.java @@ -0,0 +1,33 @@ +package it.reyboz.bustorino.fragments; + +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; + +public abstract class ResultBaseFragment extends Fragment { + + protected FragmentListenerMain mListener; + protected static final String MESSAGE_TEXT_VIEW = "message_text_view"; + + + public ResultBaseFragment() { + } + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + if (context instanceof FragmentListenerMain) { + mListener = (FragmentListenerMain) context; + } else { + throw new RuntimeException(context.toString() + + " must implement FragmentListenerMain"); + } + + } + + @Override + public void onDetach() { + mListener.showFloatingActionButton(false); + mListener = null; + super.onDetach(); + } +} 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 @@ -285,9 +285,6 @@ resultsListView.setVisibility(View.VISIBLE); } } - public void setNewListAdapter(ListAdapter adapter){ - resetListAdapter(adapter); - } /** * Set the message textView diff --git a/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt b/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt @@ -0,0 +1,33 @@ +package it.reyboz.bustorino.util + +import android.graphics.Rect +import android.util.Log + +import android.view.View +import androidx.core.widget.NestedScrollView + + +class ViewUtils { + + companion object{ + const val DEBUG_TAG="BusTO:ViewUtils" + fun isViewFullyVisibleInScroll(view: View, scrollView: NestedScrollView): Boolean { + val scrollBounds = Rect() + scrollView.getDrawingRect(scrollBounds) + val top = view.y + val bottom = top + view.height + Log.d(DEBUG_TAG, "Scroll bounds are $scrollBounds, top:${view.y}, bottom $bottom") + return (scrollBounds.top < top && scrollBounds.bottom > bottom) + } + fun isViewPartiallyVisibleInScroll(view: View, scrollView: NestedScrollView): Boolean{ + val scrollBounds = Rect() + scrollView.getHitRect(scrollBounds) + Log.d(DEBUG_TAG, "Scroll bounds are $scrollBounds") + if (view.getLocalVisibleRect(scrollBounds)) { + return true + } else { + return false + } + } + } +} \ No newline at end of file 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,7 @@ android:paddingLeft="16dip" android:paddingRight="16dip"> + + + android:id="@+id/messageCardView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:cardCornerRadius="5dp" + app:cardElevation="2dp" + > + android:id="@+id/messageTextView" + 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"/> + 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_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/messageCardView" + android:orientation="vertical"> + + + + + + + + - android:layout_marginTop="5dp" + + + + + + + - android:layout_marginBottom="5dp" - android:orientation="horizontal"> - + android:id="@+id/timesSourceTextView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:text="" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="20sp" + + android:gravity="center_vertical" + android:paddingBottom="5dp" + android:layout_marginStart="10dp" + android:layout_marginTop="5dp" + /> + - \ No newline at end of file diff --git a/app/src/main/res/layout/round_line_header.xml b/app/src/main/res/layout/round_line_header.xml new file mode 100644 --- /dev/null +++ b/app/src/main/res/layout/round_line_header.xml @@ -0,0 +1,37 @@ + + + + + + + \ 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 @@ -155,6 +155,8 @@ Cambiamento sorgente orari… Premi a lungo per cambiare la sorgente degli orari + Nessun passaggio per le linee: + Canale unico delle notifiche diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -18,6 +18,7 @@ #4DB6AC #80cbc4 #F5F5F5 + #dddddd #f8f8f8 #757575