/* * Copyright (C) 2012-2013 Paul Watts (paulcwatts@gmail.com) * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 org.onebusaway.android.ui; import org.onebusaway.android.R; import org.onebusaway.android.app.Application; import org.onebusaway.android.directions.model.Direction; import org.onebusaway.android.directions.realtime.RealtimeService; import org.onebusaway.android.directions.util.ConversionUtils; import org.onebusaway.android.directions.util.DirectionExpandableListAdapter; import org.onebusaway.android.directions.util.DirectionsGenerator; import org.onebusaway.android.directions.util.OTPConstants; import org.onebusaway.android.map.MapParams; import org.onebusaway.android.map.googlemapsv2.BaseMapFragment; import org.opentripplanner.api.model.Itinerary; import android.content.Intent; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.DrawableRes; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ExpandableListView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; public class TripResultsFragment extends Fragment { private static final String TAG = "TripResultsFragment"; private static final int LIST_TAB_POSITION = 0; private static final int MAP_TAB_POSITION = 1; private View mDirectionsFrame; private BaseMapFragment mMapFragment; private ExpandableListView mDirectionsListView; private View mMapFragmentFrame; private boolean mShowingMap = false; private RoutingOptionPicker[] mOptions = new RoutingOptionPicker[3]; private Listener mListener; private Bundle mMapBundle = new Bundle(); /** * This listener is a helper for the parent activity to handle the sliding panel, * which interacts with sliding views (i.e., list view and map view) in subtle ways. */ public interface Listener { /** * Called when the result views have been created * * @param containerView the view which contains the directions list and the map * @param listView the directions list view * @param mapView the map frame */ void onResultViewCreated(View containerView, ListView listView, View mapView); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreate(savedInstanceState); final View view = inflater.inflate(R.layout.fragment_trip_plan_results, container, false); mDirectionsFrame = view.findViewById(R.id.directionsFrame); mDirectionsListView = (ExpandableListView) view.findViewById(R.id.directionsListView); mMapFragmentFrame = view.findViewById(R.id.mapFragment); mOptions[0] = new RoutingOptionPicker(view, R.id.option1LinearLayout, R.id.option1Title, R.id.option1Duration, R.id.option1Interval); mOptions[1] = new RoutingOptionPicker(view, R.id.option2LinearLayout, R.id.option2Title, R.id.option2Duration, R.id.option2Interval); mOptions[2] = new RoutingOptionPicker(view, R.id.option3LinearLayout, R.id.option3Title, R.id.option3Duration, R.id.option3Interval); int rank = getArguments().getInt(OTPConstants.SELECTED_ITINERARY); // defaults to 0 mShowingMap = getArguments().getBoolean(OTPConstants.SHOW_MAP); initInfoAndMap(rank); TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout_switch_view); tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { boolean show = (tab.getPosition() == MAP_TAB_POSITION); showMap(show); } @Override public void onTabUnselected(TabLayout.Tab tab) { // unused } @Override public void onTabReselected(TabLayout.Tab tab) { // unused } }); setTabDrawable(tabLayout.getTabAt(LIST_TAB_POSITION), R.drawable.ic_list); setTabDrawable(tabLayout.getTabAt(MAP_TAB_POSITION), R.drawable.ic_arrivals_styleb_action_map); if (mShowingMap) { tabLayout.getTabAt(MAP_TAB_POSITION).select(); } if (mListener != null) { mListener.onResultViewCreated(mDirectionsFrame, mDirectionsListView, mMapFragmentFrame); } return view; } @Override public void onDestroy() { super.onDestroy(); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { NavHelp.goUp(getActivity()); return true; } if (item.getItemId() == R.id.show_on_map) { showMap(true); } if (item.getItemId() == R.id.list) { showMap(false); } return false; } /** * Set the listener for this fragment. * * @param listener the new listener */ public void setListener(Listener listener) { mListener = listener; } /** * Get whether map is showing. * * @return true if map is showing, false otherwise */ public boolean isMapShowing() { return mShowingMap; } private void setTabDrawable(TabLayout.Tab tab, @DrawableRes int res) { View view = tab.getCustomView(); TextView tv = ((TextView) view.findViewById(android.R.id.text1)); Drawable drawable = getResources().getDrawable(res); int dp = (int) getResources().getDimension(R.dimen.trip_results_icon_size); drawable.setBounds(0, 0, dp, dp); drawable.setColorFilter(getResources().getColor(R.color.trip_option_icon_tint), PorterDuff.Mode.SRC_IN); tv.setCompoundDrawables(drawable, null, null, null); } private void initMap(int trip) { Itinerary itinerary = getItineraries().get(trip); mMapBundle.putString(MapParams.MODE, MapParams.MODE_DIRECTIONS); mMapBundle.putSerializable(MapParams.ITINERARY, itinerary); Intent intent = new Intent().putExtras(mMapBundle); getActivity().setIntent(intent); FragmentManager fm = getChildFragmentManager(); if (mMapFragment == null) { // First check to see if an instance of BaseMapFragment already exists mMapFragment = (BaseMapFragment) fm.findFragmentByTag(BaseMapFragment.TAG); if (mMapFragment == null) { // No existing fragment was found, so create a new one Log.d(TAG, "Creating new BaseMapFragment"); mMapFragment = BaseMapFragment.newInstance(); fm.beginTransaction() .add(R.id.mapFragment, mMapFragment, BaseMapFragment.TAG) .commit(); } } } private void showMap(boolean show) { mShowingMap = show; if (show) { mMapFragmentFrame.bringToFront(); mMapFragment.setMapMode(MapParams.MODE_DIRECTIONS, mMapBundle); } else { mDirectionsListView.bringToFront(); } getArguments().putBoolean(OTPConstants.SHOW_MAP, mShowingMap); } private void initInfoAndMap(int trip) { initMap(trip); for (int i = 0; i < mOptions.length; i++) { mOptions[i].setItinerary(i); } mOptions[trip].select(); showMap(mShowingMap); } public void displayNewResults() { int rank = getArguments().getInt(OTPConstants.SELECTED_ITINERARY); showMap(mShowingMap); initInfoAndMap(rank); } private String toDateFmt(long ms) { Date d = new Date(ms); String s = new SimpleDateFormat(OTPConstants.TRIP_RESULTS_TIME_STRING_FORMAT_SUMMARY, Locale.getDefault()).format(d); return s.substring(0, 6).toLowerCase(); } private String formatTimeString(String ms, double durationSec) { long start = Long.parseLong(ms); String fromString = toDateFmt(start); String toString = toDateFmt(start + (long) durationSec); return fromString + " - " + toString; } private List<Itinerary> getItineraries() { return (List<Itinerary>) getArguments().getSerializable(OTPConstants.ITINERARIES); } private class RoutingOptionPicker { LinearLayout linearLayout; TextView titleView; TextView durationView; TextView intervalView; Itinerary itinerary; int rank; RoutingOptionPicker(View view, int linearLayout, int titleView, int durationView, int intervalView) { this.linearLayout = (LinearLayout) view.findViewById(linearLayout); this.titleView = (TextView) view.findViewById(titleView); this.durationView = (TextView) view.findViewById(durationView); this.intervalView = (TextView) view.findViewById(intervalView); this.linearLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { RoutingOptionPicker.this.select(); } }); } void select() { for (RoutingOptionPicker picker : mOptions) { picker.linearLayout.setBackgroundColor(getResources().getColor(R.color.trip_option_background)); } linearLayout.setBackgroundResource(R.drawable.trip_option_selected_item); getArguments().putInt(OTPConstants.SELECTED_ITINERARY, rank); updateInfo(); updateMap(); } void setItinerary(int rank) { List<Itinerary> trips = getItineraries(); if (rank >= trips.size()) { this.itinerary = null; linearLayout.setVisibility(View.GONE); return; } this.itinerary = trips.get(rank); this.rank = rank; String title = new DirectionsGenerator(itinerary.legs, getContext()).getItineraryTitle(); String duration = ConversionUtils.getFormattedDurationTextNoSeconds(itinerary.duration, false, getContext()); String interval = formatTimeString(itinerary.startTime, itinerary.duration * 1000); titleView.setText(title); durationView.setText(duration); intervalView.setText(interval); } void updateInfo() { DirectionsGenerator gen = new DirectionsGenerator(itinerary.legs, getActivity().getApplicationContext()); List<Direction> directions = gen.getDirections(); Direction direction_data[] = directions.toArray(new Direction[directions.size()]); DirectionExpandableListAdapter adapter = new DirectionExpandableListAdapter( getActivity(), R.layout.list_direction_item, R.layout.list_subdirection_item, direction_data); mDirectionsListView.setAdapter(adapter); mDirectionsListView.setGroupIndicator(null); if(Application.getPrefs() .getBoolean(getString(R.string.preference_key_trip_plan_notifications), true)) { RealtimeService.start(getActivity(), getArguments()); } } void updateMap() { mMapBundle.putSerializable(MapParams.ITINERARY, itinerary); mMapFragment.setMapMode(MapParams.MODE_DIRECTIONS, mMapBundle); } } }