io.github.runassudo.ptoffline.adapters.TripAdapter.java Source code

Java tutorial

Introduction

Here is the source code for io.github.runassudo.ptoffline.adapters.TripAdapter.java

Source

/*    Transportr
 *    Copyright (C) 2013 - 2016 Torsten Grote
 *
 *    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 the Free Software Foundation, either version 3 of the
 *    License, or (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package io.github.runassudo.ptoffline.adapters;

import android.animation.LayoutTransition;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.v4.view.ViewCompat;
import android.support.v7.util.SortedList;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

import org.apmem.tools.layouts.FlowLayout;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import io.github.runassudo.ptoffline.ListTrip;
import io.github.runassudo.ptoffline.R;
import io.github.runassudo.ptoffline.ui.LegPopupMenu;
import io.github.runassudo.ptoffline.ui.SwipeDismissRecyclerViewTouchListener;
import io.github.runassudo.ptoffline.utils.DateUtils;
import io.github.runassudo.ptoffline.utils.TransportrUtils;
import io.github.runassudo.ptoffline.pte.dto.Stop;
import io.github.runassudo.ptoffline.pte.dto.Trip;

public class TripAdapter extends RecyclerView.Adapter<TripAdapter.TripHolder> {

    private SortedList<ListTrip> trips = new SortedList<>(ListTrip.class, new SortedList.Callback<ListTrip>() {
        @Override
        public void onInserted(int position, int count) {
            notifyItemRangeInserted(position, count);
        }

        @Override
        public void onChanged(int position, int count) {
            notifyItemRangeChanged(position, count);
        }

        @Override
        public void onMoved(int fromPosition, int toPosition) {
            notifyItemMoved(fromPosition, toPosition);
        }

        @Override
        public void onRemoved(int position, int count) {
            notifyItemRangeRemoved(position, count);
        }

        @Override
        public int compare(ListTrip t1, ListTrip t2) {
            return t1.trip.getFirstDepartureTime().compareTo(t2.trip.getFirstDepartureTime());
        }

        @Override
        public boolean areItemsTheSame(ListTrip t1, ListTrip t2) {
            return t1.trip.equals(t2.trip);
        }

        @Override
        public boolean areContentsTheSame(ListTrip t_old, ListTrip t_new) {
            // keep expanded state when trip is updated in case Provider returns same trips
            t_new.expanded = t_old.expanded;

            // return whether the trips' visual representations are the same or not
            return t_old.trip.equals(t_new.trip);
        }
    });
    private SwipeDismissRecyclerViewTouchListener touchListener;
    private Context context;
    private List<ListTrip> removed;
    private final boolean showLineName;

    public TripAdapter(List<ListTrip> trips, SwipeDismissRecyclerViewTouchListener touchListener, Context context,
            boolean showLineName) {
        this.touchListener = touchListener;
        this.context = context;
        this.removed = new ArrayList<>();
        this.showLineName = showLineName;

        addAll(trips);
    }

    @Override
    public int getItemViewType(int position) {
        return trips.get(position).trip.legs.size();
    }

    @Override
    public TripHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(context).inflate(R.layout.trip, viewGroup, false);

        return new TripHolder(v, i);
    }

    @Override
    public void onBindViewHolder(final TripHolder ui, final int position) {
        // get trip with position from View Holder as this one gets updated when trips are removed
        final ListTrip trip = trips.get(ui.getAdapterPosition());
        ViewCompat.setTransitionName(ui.card, trip.trip.getId());

        // listen to touches also in the card, because it does not work only in the RecyclerView
        ui.card.setOnTouchListener(touchListener);

        // re-apply current expansion saved in trip
        expandTrip(ui, !trip.expanded);

        // Clear Transport Icons to avoid accumulation when same trips are returned
        ui.lines.removeAllViews();

        int i = 0;
        for (final Trip.Leg leg : trip.trip.legs) {
            bindLeg(context, ui.legs.get(i), leg, false, ui.lines, showLineName);

            // show departure delay also on overview when trip is folded
            if (i == 0 && leg instanceof Trip.Public) {
                TransportrUtils.setDepartureTimes(context, ui.legs.get(i).departureTime, ui.departureDelay,
                        ((Trip.Public) leg).departureStop);
            }

            i += 1;
        }

        // hide last divider
        ui.legs.get(trip.trip.legs.size() - 1).divider.setVisibility(View.GONE);

        // Show Number of Changes for long trips
        if (trip.trip.numChanges != null && trip.trip.numChanges > 3) {
            ui.changes.setText(String.valueOf(trip.trip.numChanges));
            ui.changes.setVisibility(View.VISIBLE);
        } else {
            ui.changes.setVisibility(View.GONE);
        }

        // Show Trip Duration
        ui.duration.setText(DateUtils.getDuration(trip.trip.getDuration()));

        // Re-color arrow down
        ui.lineArrowDown
                .setImageDrawable(TransportrUtils.getTintedDrawable(context, ui.lineArrowDown.getDrawable()));

        // Show Trip on Map
        ui.map.setImageDrawable(TransportrUtils.getTintedDrawable(context, ui.map.getDrawable()));
        ui.map.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TransportrUtils.showTripOnMap(context, trip.trip);
            }
        });

        // Share Trip
        ui.share.setImageDrawable(TransportrUtils.getTintedDrawable(context, ui.share.getDrawable()));
        ui.share.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TransportrUtils.share(context, trip.trip);
            }
        });

        // Add Trip to Calendar
        ui.calendar.setImageDrawable(TransportrUtils.getTintedDrawable(context, ui.calendar.getDrawable()));
        ui.calendar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TransportrUtils.intoCalendar(context, trip.trip);
            }
        });

        // Expand Card
        if (trip.trip.legs.size() == 1) {
            ui.expand.setVisibility(View.GONE);
        } else {
            ui.expand.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    expandTrip(ui, trip.expanded);
                    trip.expanded = !trip.expanded;
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return trips == null ? 0 : trips.size();
    }

    public int getPosition(Trip trip) {
        return trips.indexOf(new ListTrip(trip));
    }

    private static void bindLeg(Context context, final LegHolder leg_holder, Trip.Leg leg, boolean detail,
            FlowLayout lines, boolean showLineName) {
        // Locations
        leg_holder.departureLocation.setText(TransportrUtils.getLocName(leg.departure));
        leg_holder.arrivalLocation.setText(TransportrUtils.getLocName(leg.arrival));

        if (detail) {
            final LegPopupMenu departurePopup = new LegPopupMenu(context, leg_holder.departureLocation, leg);
            leg_holder.departureLocation.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    departurePopup.show();
                }
            });
            final LegPopupMenu arrivalPopup = new LegPopupMenu(context, leg_holder.arrivalLocation, leg, true);
            leg_holder.arrivalLocation.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    arrivalPopup.show();
                }
            });
        } else {
            leg_holder.departureLocation.setBackgroundResource(android.R.color.transparent);
            leg_holder.arrivalLocation.setBackgroundResource(android.R.color.transparent);
        }

        // Re-color arrow down
        leg_holder.arrowDown
                .setImageDrawable(TransportrUtils.getTintedDrawable(context, leg_holder.arrowDown.getDrawable()));

        // Leg duration
        leg_holder.duration.setText(DateUtils.getDuration(leg.getDepartureTime(), leg.getArrivalTime()));

        if (leg instanceof Trip.Public) {
            Trip.Public public_leg = ((Trip.Public) leg);

            TransportrUtils.setArrivalTimes(context, leg_holder.arrivalTime, leg_holder.arrivalDelay,
                    public_leg.arrivalStop);
            TransportrUtils.setDepartureTimes(context, leg_holder.departureTime, leg_holder.departureDelay,
                    public_leg.departureStop);

            if (leg_holder.arrivalDelay.getText() == null || leg_holder.arrivalDelay.getText().equals("")) {
                // hide delay view if there's no delay
                leg_holder.arrivalDelay.setVisibility(View.GONE);
            }

            // Departure Platform
            if (detail && public_leg.getDeparturePosition() != null) {
                leg_holder.departurePlatform.setText(public_leg.getDeparturePosition().toString());
            } else {
                leg_holder.departurePlatform.setVisibility(View.GONE);
            }

            // Arrival Platform
            if (detail && public_leg.getArrivalPosition() != null) {
                leg_holder.arrivalPlatform.setText(public_leg.getArrivalPosition().toString());
            } else {
                leg_holder.arrivalPlatform.setVisibility(View.GONE);
            }

            leg_holder.line.removeViewAt(0);
            TransportrUtils.addLineBox(context, leg_holder.line, public_leg.line, 0);
            if (lines != null)
                TransportrUtils.addLineBox(context, lines, public_leg.line);

            if (showLineName && public_leg.line.name != null) {
                leg_holder.lineDestination.setText(public_leg.line.name);
                leg_holder.arrow.setVisibility(View.INVISIBLE);
            } else if (public_leg.destination != null) {
                leg_holder.lineDestination.setText(TransportrUtils.getLocName(public_leg.destination));
                leg_holder.arrow.setImageDrawable(
                        TransportrUtils.getTintedDrawable(context, leg_holder.arrow.getDrawable()));
            } else {
                // hide arrow because this line has no name and no destination
                leg_holder.arrow.setVisibility(View.GONE);
            }

            if (detail) {
                // show intermediate stops and leg duration
                bindStops(context, leg_holder, public_leg.intermediateStops);

                // optional trip message
                if (public_leg.message != null) {
                    leg_holder.message.setVisibility(View.VISIBLE);
                    leg_holder.message.setText(Html.fromHtml(public_leg.message).toString());
                }
                if (public_leg.line.message != null) {
                    leg_holder.message.setVisibility(View.VISIBLE);
                    leg_holder.message.setText(leg_holder.message.getText() + "\n"
                            + Html.fromHtml(public_leg.line.message).toString());
                }
            }
        } else if (leg instanceof Trip.Individual) {
            final Trip.Individual individual = (Trip.Individual) leg;

            leg_holder.arrivalTime.setText(DateUtils.getTime(context, individual.arrivalTime));
            leg_holder.departureTime.setText(DateUtils.getTime(context, individual.departureTime));

            // TODO carry over delay from last leg somehow?
            leg_holder.arrivalDelay.setVisibility(View.GONE);

            leg_holder.line.removeViewAt(0);
            TransportrUtils.addWalkingBox(context, leg_holder.line, 0);
            if (lines != null)
                TransportrUtils.addWalkingBox(context, lines);

            if (detail) {
                final LegPopupMenu walkPopup = new LegPopupMenu(context, leg_holder.line, leg);
                leg_holder.info.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        walkPopup.show();
                    }
                });
            } else {
                leg_holder.info.setBackgroundResource(android.R.color.transparent);
            }

            // hide arrow because this line has no destination
            leg_holder.arrow.setVisibility(View.GONE);

            // show distance
            if (individual.distance > 0) {
                leg_holder.lineDestination.setText(
                        "  " + Integer.toString(individual.distance) + " " + context.getString(R.string.meter));
            } else {
                leg_holder.lineDestination.setVisibility(View.GONE);
            }
        }
    }

    static public void bindLeg(Context context, LegHolder leg_holder, Trip.Leg leg, boolean detail,
            boolean showLineName) {
        bindLeg(context, leg_holder, leg, detail, null, showLineName);
    }

    private static void bindStops(Context context, final LegHolder leg_holder, List<Stop> stops) {
        leg_holder.stops.setVisibility(View.GONE);
        leg_holder.duration.setVisibility(View.GONE);

        leg_holder.info.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (leg_holder.stops.getVisibility() == View.GONE) {
                    leg_holder.stops.setVisibility(View.VISIBLE);
                    leg_holder.duration.setVisibility(View.VISIBLE);
                } else {
                    leg_holder.stops.setVisibility(View.GONE);
                    leg_holder.duration.setVisibility(View.GONE);

                }
            }
        });

        // highlight duration to set it apart from platforms/positions
        leg_holder.duration.setTextColor(leg_holder.departureLocation.getCurrentTextColor());

        // stop here, if there are no stops
        if (stops == null)
            return;

        // Remove previous stops in case we are refreshing the view.
        leg_holder.stops.removeAllViews();

        for (final Stop stop : stops) {
            TableRow stopView = (TableRow) LayoutInflater.from(context).inflate(R.layout.stop, leg_holder.stops,
                    false);

            StopHolder stopHolder = new StopHolder(stopView);

            Date arrivalTime = stop.getArrivalTime();
            Date departureTime = stop.getDepartureTime();

            if (arrivalTime != null) {
                TransportrUtils.setArrivalTimes(context, stopHolder.arrivalTime, stopHolder.arrivalDelay, stop);
            } else {
                stopHolder.arrivalTime.setVisibility(View.GONE);
                stopHolder.arrivalDelay.setVisibility(View.GONE);
            }

            if (departureTime != null) {
                TransportrUtils.setDepartureTimes(context, stopHolder.departureTime, stopHolder.departureDelay,
                        stop);
            } else {
                stopHolder.departureTime.setVisibility(View.GONE);
                stopHolder.departureDelay.setVisibility(View.GONE);
            }

            stopHolder.location.setText(TransportrUtils.getLocName(stop.location));

            if (stop.plannedArrivalPosition != null) {
                stopHolder.arrivalPlatform.setText(stop.plannedArrivalPosition.name);
            }
            if (stop.plannedDeparturePosition != null) {
                stopHolder.departurePlatform.setText(stop.plannedDeparturePosition.name);
            }

            SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
            if (settings.getBoolean("pref_key_hide_departure_time", false)) {
                stopHolder.departureTime.setVisibility(View.GONE);
                stopHolder.departureDelay.setVisibility(View.GONE);
                stopHolder.departurePlatform.setVisibility(View.GONE);
            }

            // Creating PopupMenu for stop
            final LegPopupMenu popup = new LegPopupMenu(context, stopView, stop);

            // show popup on click
            stopView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    popup.show();
                }
            });
            // show popup also on long click
            stopView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    popup.show();
                    return true;
                }
            });

            leg_holder.stops.addView(stopView);
        }
    }

    public ListTrip getItem(int position) {
        return trips.get(position);
    }

    public void addAll(final List<ListTrip> trips) {
        this.trips.addAll(trips);
    }

    public boolean remove(ListTrip trip) {
        removed.add(trip);

        return this.trips.remove(trip);
    }

    public ListTrip removeItemAt(int index) {
        ListTrip trip = this.trips.removeItemAt(index);
        removed.add(trip);

        return trip;
    }

    public void undo() {
        trips.add(removed.remove(removed.size() - 1));
    }

    private void expandTrip(final TripHolder ui, boolean expand) {
        Drawable icon;
        int state, ostate;

        if (expand) {
            //noinspection deprecation
            icon = TransportrUtils.getTintedDrawable(context, R.drawable.ic_action_navigation_unfold_more);
            state = View.GONE;
            ostate = View.VISIBLE;
        } else {
            //noinspection deprecation
            icon = TransportrUtils.getTintedDrawable(context, R.drawable.ic_action_navigation_unfold_less);
            state = View.VISIBLE;
            ostate = View.GONE;
        }
        ui.expand.setImageDrawable(icon);

        // show view with all trip lines if everything else is gone
        ui.linesView.setVisibility(ostate);

        if (ui.legs.size() <= 1) {
            // show/hide additional trip info
            ui.legs.get(0).info.setVisibility(state);

            return;
        }

        int i = 0;
        for (LegHolder leg : ui.legs) {
            if (i == 0) {
                // first leg
                leg.arrival.setVisibility(state);
                leg.info.setVisibility(state);
                leg.divider.setVisibility(state);
            } else if (i == ui.legs.size() - 1) {
                // last leg
                leg.departure.setVisibility(state);
                leg.info.setVisibility(state);
            } else {
                // all middle legs
                leg.arrival.setVisibility(state);
                leg.info.setVisibility(state);
                leg.departure.setVisibility(state);
                leg.divider.setVisibility(state);
            }
            i += 1;
        }
    }

    public static class BaseTripHolder extends RecyclerView.ViewHolder {
        public CardView card;
        ViewGroup legsView;
        public List<LegHolder> legs;

        public BaseTripHolder(View v, int size) {
            super(v);

            card = (CardView) v.findViewById(R.id.cardView);
            legsView = (ViewGroup) v.findViewById(R.id.legsView);

            legs = new ArrayList<>();

            // add more leg views for number of legs
            for (int i = 0; i < size; i++) {
                ViewGroup legView = (ViewGroup) LayoutInflater.from(v.getContext()).inflate(R.layout.leg, legsView,
                        false);
                legsView.addView(legView);

                LegHolder legHolder = new LegHolder(legView);
                legs.add(legHolder);
            }
        }
    }

    static class TripHolder extends BaseTripHolder {
        CardView card;
        TableLayout firstLeg;
        TableRow linesView;
        TextView departureDelay;
        ImageView lineArrowDown;
        public FlowLayout lines;
        TextView changes;
        private TextView duration;
        private ImageView map;
        private ImageView share;
        ImageView calendar;
        ImageView expand;

        TripHolder(View v, int size) {
            super(v, size - 1);

            card = (CardView) v.findViewById(R.id.cardView);
            firstLeg = (TableLayout) v.findViewById(R.id.firstLegView);
            map = (ImageView) v.findViewById(R.id.mapView);
            share = (ImageView) v.findViewById(R.id.shareView);
            calendar = (ImageView) v.findViewById(R.id.calendarView);
            expand = (ImageView) v.findViewById(R.id.expandView);

            LayoutTransition transition = new LayoutTransition();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                transition.enableTransitionType(LayoutTransition.CHANGING);
                transition.enableTransitionType(LayoutTransition.APPEARING);
                transition.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
                transition.enableTransitionType(LayoutTransition.DISAPPEARING);
                transition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
            }
            legsView.setLayoutTransition(transition);

            LegHolder firstLegHolder = new LegHolder(firstLeg);
            legs.add(0, firstLegHolder);

            // inflate special view that contains all lines on that trip
            linesView = (TableRow) LayoutInflater.from(v.getContext()).inflate(R.layout.lines, firstLeg, false);

            firstLeg.addView(linesView, 1);

            // remember where the lines are inserted and the trip duration
            departureDelay = (TextView) linesView.findViewById(R.id.departureDelayView);
            lineArrowDown = (ImageView) linesView.findViewById(R.id.lineArrowDown);
            lines = (FlowLayout) linesView.findViewById(R.id.lineLayout);
            changes = (TextView) linesView.findViewById(R.id.changesView);
            duration = (TextView) linesView.findViewById(R.id.durationView);
        }
    }

    public static class LegHolder extends RecyclerView.ViewHolder {
        public TableLayout layout;
        public ViewGroup departure;
        TextView departureTime;
        TextView departureDelay;
        TextView departureLocation;
        TextView departurePlatform;
        ViewGroup arrival;
        TextView arrivalTime;
        TextView arrivalDelay;
        TextView arrivalLocation;
        TextView arrivalPlatform;
        private ViewGroup info;
        private TextView message;
        ViewGroup stops;
        public ViewGroup line;
        ImageView arrow;
        ImageView arrowDown;
        TextView lineDestination;
        public TextView duration;
        public View divider;

        LegHolder(ViewGroup v) {
            super(v);

            layout = (TableLayout) v;
            departure = (ViewGroup) v.findViewById(R.id.departureView);
            departureTime = (TextView) v.findViewById(R.id.departureTimeView);
            departureDelay = (TextView) v.findViewById(R.id.departureDelayView);
            departureLocation = (TextView) v.findViewById(R.id.departureLocationView);
            departurePlatform = (TextView) v.findViewById(R.id.departurePlatformView);
            arrival = (ViewGroup) v.findViewById(R.id.arrivalView);
            arrivalTime = (TextView) v.findViewById(R.id.arrivalTimeView);
            arrivalDelay = (TextView) v.findViewById(R.id.arrivalDelayView);
            arrivalLocation = (TextView) v.findViewById(R.id.arrivalLocationView);
            arrivalPlatform = (TextView) v.findViewById(R.id.arrivalPlatformView);
            info = (ViewGroup) v.findViewById(R.id.infoView);
            message = (TextView) v.findViewById(R.id.messageView);
            stops = (ViewGroup) v.findViewById(R.id.stopsView);
            line = (ViewGroup) v.findViewById(R.id.lineView);
            arrow = (ImageView) v.findViewById(R.id.arrowView);
            arrowDown = (ImageView) v.findViewById(R.id.arrowDown);
            lineDestination = (TextView) v.findViewById(R.id.lineDestinationView);
            duration = (TextView) v.findViewById(R.id.durationView);
            divider = v.findViewById(R.id.dividerView);

            message.setVisibility(View.GONE);
        }
    }

    private static class StopHolder {
        public TableRow layout;
        TextView arrivalTime;
        TextView departureTime;
        TextView arrivalDelay;
        TextView departureDelay;

        public TextView location;

        ViewGroup platformView;
        TextView arrivalPlatform;
        TextView departurePlatform;

        StopHolder(TableRow v) {
            layout = v;
            arrivalTime = (TextView) v.findViewById(R.id.arrivalTimeView);
            departureTime = (TextView) v.findViewById(R.id.departureTimeView);
            arrivalDelay = (TextView) v.findViewById(R.id.arrivalDelayView);
            departureDelay = (TextView) v.findViewById(R.id.departureDelayView);

            location = (TextView) v.findViewById(R.id.locationView);

            platformView = (ViewGroup) v.findViewById(R.id.platformView);
            arrivalPlatform = (TextView) v.findViewById(R.id.arrivalPlatformView);
            departurePlatform = (TextView) v.findViewById(R.id.departurePlatformView);
        }
    }
}