fr.cph.chicago.core.activity.StationActivity.java Source code

Java tutorial

Introduction

Here is the source code for fr.cph.chicago.core.activity.StationActivity.java

Source

/**
 * Copyright 2016 Carl-Philipp Harmant
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fr.cph.chicago.core.activity;

import android.content.res.ColorStateList;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils.TruncateAt;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.annimon.stream.Optional;
import com.annimon.stream.Stream;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import butterknife.BindColor;
import butterknife.BindDimen;
import butterknife.BindDrawable;
import butterknife.BindString;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.cph.chicago.R;
import fr.cph.chicago.core.App;
import fr.cph.chicago.core.listener.GoogleMapDirectionOnClickListener;
import fr.cph.chicago.core.listener.GoogleMapOnClickListener;
import fr.cph.chicago.core.listener.GoogleStreetOnClickListener;
import fr.cph.chicago.data.DataHolder;
import fr.cph.chicago.data.Preferences;
import fr.cph.chicago.data.TrainData;
import fr.cph.chicago.entity.Eta;
import fr.cph.chicago.entity.Position;
import fr.cph.chicago.entity.Station;
import fr.cph.chicago.entity.Stop;
import fr.cph.chicago.entity.TrainArrival;
import fr.cph.chicago.entity.enumeration.TrainDirection;
import fr.cph.chicago.entity.enumeration.TrainLine;
import fr.cph.chicago.rx.subscriber.SubscriberTrainArrival;
import fr.cph.chicago.service.TrainService;
import fr.cph.chicago.service.impl.TrainServiceImpl;
import fr.cph.chicago.util.Util;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * Activity that represents the train station
 *
 * @author Carl-Philipp Harmant
 * @version 1
 */
public class StationActivity extends AbstractStationActivity {

    @BindView(android.R.id.content)
    ViewGroup viewGroup;
    @BindView(R.id.activity_train_station_streetview_image)
    ImageView streetViewImage;
    @BindView(R.id.scrollViewTrainStation)
    ScrollView scrollView;
    @BindView(R.id.activity_station_swipe_refresh_layout)
    SwipeRefreshLayout swipeRefreshLayout;
    @BindView(R.id.activity_favorite_star)
    ImageView favoritesImage;
    @BindView(R.id.activity_train_station_steetview_text)
    TextView streetViewText;
    @BindView(R.id.activity_map_image)
    ImageView mapImage;
    @BindView(R.id.map_container)
    LinearLayout mapContainer;
    @BindView(R.id.activity_map_direction)
    ImageView directionImage;
    @BindView(R.id.walk_container)
    LinearLayout walkContainer;
    @BindView(R.id.favorites_container)
    LinearLayout favoritesImageContainer;
    @BindView(R.id.activity_train_station_details)
    LinearLayout stopsView;
    @BindView(R.id.toolbar)
    Toolbar toolbar;

    @BindString(R.string.bundle_train_stationId)
    String bundleTrainStationId;
    @BindString(R.string.analytics_train_details)
    String trainDetails;

    @BindDimen(R.dimen.activity_station_street_map_height)
    int height;
    @BindDimen(R.dimen.activity_station_stops_line3_padding_left)
    int line3PaddingLeft;
    @BindDimen(R.dimen.activity_station_stops_line3_padding_top)
    int line3PaddingTop;

    @BindColor(R.color.grey_5)
    int grey_5;
    @BindColor(R.color.grey)
    int grey;
    @BindColor(R.color.yellowLineDark)
    int yellowLineDark;
    @BindColor(R.color.yellowLine)
    int yellowLine;
    @BindDrawable(R.drawable.ic_arrow_back_white_24dp)
    Drawable arrowBackWhite;

    private LinearLayout.LayoutParams paramsStop;
    private boolean isFavorite;
    private int stationId;
    private Station station;
    private Map<String, Integer> ids;
    private Observable<Optional<TrainArrival>> trainArrivalObservable;
    private final TrainService trainService;

    public StationActivity() {
        trainService = new TrainServiceImpl();
    }

    @Override
    protected final void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        App.checkTrainData(this);
        if (!this.isFinishing()) {
            // Layout setup
            setContentView(R.layout.activity_station);
            ButterKnife.bind(this);
            // Get station id from bundle
            stationId = getIntent().getExtras().getInt(bundleTrainStationId, 0);
            if (stationId != 0) {
                // Get station
                final TrainData trainData = DataHolder.getInstance().getTrainData();
                station = trainData.getStation(stationId).orElse(new Station());

                paramsStop = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);

                final RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) streetViewImage
                        .getLayoutParams();
                final Position position = station.getStops().get(0).getPosition();
                final ViewGroup.LayoutParams params = streetViewImage.getLayoutParams();

                ids = new HashMap<>();
                isFavorite = isFavorite();

                createGoogleStreetObservable(position.getLatitude(), position.getLongitude());
                subscribeToGoogleStreet(streetViewImage, streetViewText);
                createTrainArrivalObservableAndSubscribe();

                streetViewImage.setOnClickListener(
                        new GoogleStreetOnClickListener(position.getLatitude(), position.getLongitude()));
                streetViewImage.setLayoutParams(params);
                streetViewText.setTypeface(null, Typeface.BOLD);
                swipeRefreshLayout.setOnRefreshListener(() -> trainArrivalObservable
                        .subscribe(new SubscriberTrainArrival(this, swipeRefreshLayout)));
                if (isFavorite) {
                    favoritesImage.setColorFilter(yellowLineDark);
                } else {
                    favoritesImage.setColorFilter(grey_5);
                }

                params.height = height;
                params.width = layoutParams.width;
                mapImage.setColorFilter(grey_5);
                directionImage.setColorFilter(grey_5);
                favoritesImageContainer.setOnClickListener(v -> switchFavorite());
                mapContainer.setOnClickListener(
                        new GoogleMapOnClickListener(position.getLatitude(), position.getLongitude()));
                walkContainer.setOnClickListener(
                        new GoogleMapDirectionOnClickListener(position.getLatitude(), position.getLongitude()));

                final Map<TrainLine, List<Stop>> stopByLines = station.getStopByLines();
                final TrainLine randomTrainLine = getRandomLine(stopByLines);
                setUpStopLayouts(stopByLines);
                swipeRefreshLayout.setColorSchemeColors(randomTrainLine.getColor());
                setToolBar(randomTrainLine);

                Util.trackScreen(getApplicationContext(), trainDetails);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void setUpStopLayouts(@NonNull final Map<TrainLine, List<Stop>> stopByLines) {
        Stream.of(stopByLines.entrySet()).forEach(entry -> {
            final TrainLine line = entry.getKey();
            final List<Stop> stops = entry.getValue();
            final View lineTitleView = getLayoutInflater().inflate(R.layout.activity_station_line_title, viewGroup,
                    false);

            final TextView testView = (TextView) lineTitleView.findViewById(R.id.train_line_title);
            testView.setText(line.toStringWithLine());
            testView.setBackgroundColor(line.getColor());
            if (line == TrainLine.YELLOW) {
                testView.setBackgroundColor(yellowLine);
            }

            stopsView.addView(lineTitleView);

            Stream.of(stops).sorted().forEach(stop -> {
                final LinearLayout linearLayout = new LinearLayout(this);
                linearLayout.setOrientation(LinearLayout.HORIZONTAL);
                linearLayout.setLayoutParams(paramsStop);

                final AppCompatCheckBox checkBox = new AppCompatCheckBox(this);
                checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> Preferences
                        .saveTrainFilter(getApplicationContext(), stationId, line, stop.getDirection(), isChecked));
                checkBox.setOnClickListener(v -> {
                    if (checkBox.isChecked()) {
                        trainArrivalObservable.subscribe(new SubscriberTrainArrival(this, swipeRefreshLayout));
                    }
                });
                checkBox.setChecked(
                        Preferences.getTrainFilter(getApplicationContext(), stationId, line, stop.getDirection()));
                checkBox.setTypeface(checkBox.getTypeface(), Typeface.BOLD);
                checkBox.setText(stop.getDirection().toString());
                checkBox.setTextColor(grey);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    checkBox.setBackgroundTintList(ColorStateList.valueOf(line.getColor()));
                    checkBox.setButtonTintList(ColorStateList.valueOf(line.getColor()));
                    if (line == TrainLine.YELLOW) {
                        checkBox.setBackgroundTintList(ColorStateList.valueOf(yellowLine));
                        checkBox.setButtonTintList(ColorStateList.valueOf(yellowLine));
                    }
                }
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    checkBox.setForegroundTintList(ColorStateList.valueOf(line.getColor()));
                    if (line == TrainLine.YELLOW) {
                        checkBox.setForegroundTintList(ColorStateList.valueOf(yellowLine));
                    }
                }

                linearLayout.addView(checkBox);

                final LinearLayout arrivalTrainsLayout = new LinearLayout(this);
                arrivalTrainsLayout.setOrientation(LinearLayout.VERTICAL);
                arrivalTrainsLayout.setLayoutParams(paramsStop);
                int id = Util.generateViewId();
                arrivalTrainsLayout.setId(id);
                ids.put(line.toString() + "_" + stop.getDirection().toString(), id);

                linearLayout.addView(arrivalTrainsLayout);
                stopsView.addView(linearLayout);
            });
        });
    }

    private void setToolBar(@NonNull final TrainLine randomTrainLine) {
        toolbar.inflateMenu(R.menu.main);
        toolbar.setOnMenuItemClickListener(item -> {
            swipeRefreshLayout.setRefreshing(true);
            trainArrivalObservable.subscribe(new SubscriberTrainArrival(this, swipeRefreshLayout));
            return false;
        });

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            toolbar.setElevation(4);
        }

        Util.setWindowsColor(this, toolbar, randomTrainLine);

        toolbar.setTitle(station.getName());
        toolbar.setNavigationIcon(arrowBackWhite);

        toolbar.setOnClickListener(v -> finish());
    }

    @Override
    public void onRestoreInstanceState(final Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        stationId = savedInstanceState.getInt(getString(R.string.bundle_train_stationId));
    }

    @Override
    public void onSaveInstanceState(final Bundle savedInstanceState) {
        savedInstanceState.putInt(getString(R.string.bundle_train_stationId), stationId);
        super.onSaveInstanceState(savedInstanceState);
    }

    /**
     * Is favorite or not ?
     *
     * @return if the station is favorite
     */
    @Override
    protected boolean isFavorite() {
        final List<Integer> favorites = Preferences.getTrainFavorites(getApplicationContext(),
                App.PREFERENCE_FAVORITES_TRAIN);
        return Stream.of(favorites).filter(favorite -> favorite == stationId).findFirst().isPresent();
    }

    // FIXME: delete view instead of hiding it
    public void hideAllArrivalViews() {
        Stream.of(station.getLines())
                .flatMap(trainLine -> Stream.of(TrainDirection.values())
                        .map(trainDirection -> trainLine.toString() + "_" + trainDirection.toString()))
                .forEach(key -> {
                    if (ids.containsKey(key)) {
                        final int id = ids.get(key);
                        final LinearLayout line3View = (LinearLayout) findViewById(id);
                        if (line3View != null) {
                            line3View.setVisibility(View.GONE);
                            if (line3View.getChildCount() > 0) {
                                Stream.range(0, line3View.getChildCount()).forEach(i -> {
                                    final LinearLayout view = (LinearLayout) line3View.getChildAt(i);
                                    final TextView timing = (TextView) view.getChildAt(1);
                                    if (timing != null) {
                                        timing.setText("");
                                    }
                                });
                            }
                        }
                    }
                });
    }

    /**
     * Draw line
     *
     * @param eta the eta
     */
    public void drawAllArrivalsTrain(@NonNull final Eta eta) {
        final TrainLine line = eta.getRouteName();
        final Stop stop = eta.getStop();
        final String key = line.toString() + "_" + stop.getDirection().toString();
        // viewId might be not there if CTA API provide wrong data
        if (ids.containsKey(key)) {
            final int viewId = ids.get(key);
            final LinearLayout line3View = (LinearLayout) findViewById(viewId);
            final Integer id = ids
                    .get(line.toString() + "_" + stop.getDirection().toString() + "_" + eta.getDestName());
            if (id == null) {
                final LinearLayout insideLayout = new LinearLayout(this);
                insideLayout.setOrientation(LinearLayout.HORIZONTAL);
                insideLayout.setLayoutParams(paramsStop);
                final int newId = Util.generateViewId();
                insideLayout.setId(newId);
                ids.put(line.toString() + "_" + stop.getDirection().toString() + "_" + eta.getDestName(), newId);

                final TextView stopName = new TextView(this);
                final String stopNameData = eta.getDestName() + ": ";
                stopName.setText(stopNameData);
                stopName.setTextColor(grey);
                stopName.setPadding(line3PaddingLeft, line3PaddingTop, 0, 0);
                insideLayout.addView(stopName);

                final TextView timing = new TextView(this);
                final String timingData = eta.getTimeLeftDueDelay() + " ";
                timing.setText(timingData);
                timing.setTextColor(grey);
                timing.setLines(1);
                timing.setEllipsize(TruncateAt.END);
                insideLayout.addView(timing);

                line3View.addView(insideLayout);
            } else {
                final LinearLayout insideLayout = (LinearLayout) findViewById(id);
                final TextView timing = (TextView) insideLayout.getChildAt(1);
                final String timingData = timing.getText() + eta.getTimeLeftDueDelay() + " ";
                timing.setText(timingData);
            }
            line3View.setVisibility(View.VISIBLE);
        }
    }

    /**
     * Add/remove favorites
     */
    private void switchFavorite() {
        if (isFavorite) {
            Util.removeFromTrainFavorites(stationId, scrollView);
            isFavorite = false;
            favoritesImage.setColorFilter(grey);
        } else {
            Util.addToTrainFavorites(stationId, scrollView);
            isFavorite = true;
            favoritesImage.setColorFilter(yellowLineDark);
        }
    }

    private TrainLine getRandomLine(@NonNull final Map<TrainLine, List<Stop>> stops) {
        final Random random = new Random();
        final List<TrainLine> keys = new ArrayList<>(stops.keySet());
        return keys.get(random.nextInt(keys.size()));
    }

    private void createTrainArrivalObservableAndSubscribe() {
        trainArrivalObservable = Observable.create((Subscriber<? super Optional<TrainArrival>> subscriber) -> {
            subscriber.onNext(trainService.loadStationTrainArrival(getApplicationContext(), station.getId()));
            subscriber.onCompleted();
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
        trainArrivalObservable.subscribe(new SubscriberTrainArrival(this, swipeRefreshLayout));
    }
}