package org.mtransit.android.ui.fragment; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import org.mtransit.android.R; import org.mtransit.android.commons.BundleUtils; import org.mtransit.android.commons.LocationUtils; import org.mtransit.android.commons.MTLog; import org.mtransit.android.commons.PreferenceUtils; import org.mtransit.android.data.POIArrayAdapter; import org.mtransit.android.data.POIManager; import org.mtransit.android.task.AgencyPOIsLoader; import org.mtransit.android.ui.MTActivityWithLocation; import org.mtransit.android.ui.view.MapViewController; import org.mtransit.android.util.LoaderUtils; import android.app.Activity; import android.content.res.Configuration; import android.location.Location; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; import android.widget.AbsListView; import android.widget.TextView; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.LatLngBounds; public class AgencyPOIsFragment extends MTFragmentV4 implements AgencyTypeFragment.AgencyFragment, LoaderManager.LoaderCallbacks<ArrayList<POIManager>>, MTActivityWithLocation.UserLocationListener, MapViewController.MapMarkerProvider, MapViewController.MapListener { private static final String TAG = AgencyPOIsFragment.class.getSimpleName(); @Override public String getLogTag() { return TAG + "-" + this.authority; } private static final String EXTRA_AGENCY_AUTHORITY = "extra_agency_authority"; private static final String EXTRA_FRAGMENT_POSITION = "extra_fragment_position"; private static final String EXTRA_LAST_VISIBLE_FRAGMENT_POSITION = "extra_last_visible_fragment_position"; private static final String EXTRA_SHOWING_LIST_INSTEAD_OF_MAP = "extra_showing_list_instead_of_map"; public static AgencyPOIsFragment newInstance(int fragmentPosition, int lastVisibleFragmentPosition, String agencyAuthority, Boolean optShowingListInsteadOfMap) { AgencyPOIsFragment f = new AgencyPOIsFragment(); Bundle args = new Bundle(); args.putString(EXTRA_AGENCY_AUTHORITY, agencyAuthority); f.authority = agencyAuthority; if (fragmentPosition >= 0) { args.putInt(EXTRA_FRAGMENT_POSITION, fragmentPosition); f.fragmentPosition = fragmentPosition; } if (lastVisibleFragmentPosition >= 0) { args.putInt(EXTRA_LAST_VISIBLE_FRAGMENT_POSITION, lastVisibleFragmentPosition); f.lastVisibleFragmentPosition = lastVisibleFragmentPosition; } if (optShowingListInsteadOfMap != null) { args.putBoolean(EXTRA_SHOWING_LIST_INSTEAD_OF_MAP, optShowingListInsteadOfMap); f.showingListInsteadOfMap = optShowingListInsteadOfMap; } f.setArguments(args); return f; } private Location userLocation; private int fragmentPosition = -1; private int lastVisibleFragmentPosition = -1; private boolean fragmentVisible = false; private POIArrayAdapter adapter; private String emptyText = null; private String authority; private MapViewController mapViewController = new MapViewController(TAG, this, this, true, true, true, false, false, false, 0, false, true, false, true, false); @Override public String getAgencyAuthority() { return this.authority; } @Override public void onAttach(Activity activity) { super.onAttach(activity); initAdapters(activity); this.mapViewController.onAttach(activity); } @Override public void onDetach() { super.onDetach(); this.mapViewController.onDetach(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); restoreInstanceState(savedInstanceState, getArguments()); this.mapViewController.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View view = inflater.inflate(R.layout.fragment_agency_pois, container, false); this.mapViewController.onCreateView(view, savedInstanceState); return view; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setupView(view); this.mapViewController.onViewCreated(view, savedInstanceState); } @Override public void onSaveInstanceState(Bundle outState) { if (!TextUtils.isEmpty(this.authority)) { outState.putString(EXTRA_AGENCY_AUTHORITY, this.authority); } if (this.fragmentPosition >= 0) { outState.putInt(EXTRA_FRAGMENT_POSITION, this.fragmentPosition); } if (this.lastVisibleFragmentPosition >= 0) { outState.putInt(EXTRA_LAST_VISIBLE_FRAGMENT_POSITION, this.lastVisibleFragmentPosition); } if (this.showingListInsteadOfMap != null) { outState.putBoolean(EXTRA_SHOWING_LIST_INSTEAD_OF_MAP, this.showingListInsteadOfMap); } this.mapViewController.onSaveInstanceState(outState); super.onSaveInstanceState(outState); } private void restoreInstanceState(Bundle... bundles) { String newAuthority = BundleUtils.getString(EXTRA_AGENCY_AUTHORITY, bundles); if (!TextUtils.isEmpty(newAuthority) && !newAuthority.equals(this.authority)) { this.authority = newAuthority; } Boolean newShowingListInsteadOfMap = BundleUtils.getBoolean(EXTRA_SHOWING_LIST_INSTEAD_OF_MAP, bundles); if (newShowingListInsteadOfMap != null) { this.showingListInsteadOfMap = newShowingListInsteadOfMap; } Integer fragmentPosition = BundleUtils.getInt(EXTRA_FRAGMENT_POSITION, bundles); if (fragmentPosition != null) { if (fragmentPosition >= 0) { this.fragmentPosition = fragmentPosition; } else { this.fragmentPosition = -1; } } Integer lastVisibleFragmentPosition = BundleUtils.getInt(EXTRA_LAST_VISIBLE_FRAGMENT_POSITION, bundles); if (lastVisibleFragmentPosition != null) { if (lastVisibleFragmentPosition >= 0) { this.lastVisibleFragmentPosition = lastVisibleFragmentPosition; } else { this.lastVisibleFragmentPosition = -1; } } this.adapter.setTag(this.authority); this.mapViewController.setTag(getLogTag()); } private void initAdapters(Activity activity) { this.adapter = new POIArrayAdapter(activity); } @Override public POIManager getClosestPOI() { return this.adapter == null ? null : this.adapter.getClosestPOI(); } @Override public POIManager getPOI(String uuid) { return this.adapter == null ? null : this.adapter.getItem(uuid); } @Override public Collection<POIManager> getPOIs() { if (this.adapter == null || !this.adapter.isInitialized()) { return null; } HashSet<POIManager> pois = new HashSet<POIManager>(); if (this.adapter != null && this.adapter.hasPois()) { for (int i = 0; i < this.adapter.getPoisCount(); i++) { pois.add(this.adapter.getItem(i)); } } return pois; } @Override public Collection<MapViewController.POIMarker> getPOMarkers() { return null; } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); this.mapViewController.onConfigurationChanged(newConfig); } @Override public void onMapClick(LatLng position) { } @Override public void onCameraChange(LatLngBounds latLngBounds) { } private void linkAdapterWithListView(View view) { if (view == null || this.adapter == null) { return; } View listView = view.findViewById(R.id.list); if (listView != null) { this.adapter.setListView((AbsListView) listView); } } private void setupView(View view) { if (view == null) { return; } if (isShowingListInsteadOfMap()) { // showing list inflateList(view); switchView(view); } } @Override public void setFragmentPosition(int fragmentPosition) { this.fragmentPosition = fragmentPosition; setFragmentVisibleAtPosition(this.lastVisibleFragmentPosition); // force reset visibility } @Override public void setFragmentVisibleAtPosition(int visibleFragmentPosition) { if (this.lastVisibleFragmentPosition == visibleFragmentPosition // && (// (this.fragmentPosition == visibleFragmentPosition && this.fragmentVisible) // || // (this.fragmentPosition != visibleFragmentPosition && !this.fragmentVisible) // ) // ) { return; } this.lastVisibleFragmentPosition = visibleFragmentPosition; if (this.fragmentPosition < 0) { return; } if (this.fragmentPosition == visibleFragmentPosition) { onFragmentVisible(); } else { onFragmentInvisible(); } } private void onFragmentInvisible() { if (!this.fragmentVisible) { return; // already invisible } this.fragmentVisible = false; if (this.adapter != null) { this.adapter.onPause(); } if (!isShowingListInsteadOfMap()) { // map this.mapViewController.onPause(); } } @Override public boolean isFragmentVisible() { return this.fragmentVisible; } private void onFragmentVisible() { if (this.fragmentVisible) { return; // already visible } if (!isResumed()) { return; } this.fragmentVisible = true; if (!isShowingListInsteadOfMap()) { // map this.mapViewController.onResume(); } switchView(getView()); if (!this.adapter.isInitialized()) { LoaderUtils.restartLoader(this, POIS_LOADER, null, this); } else { this.adapter.onResume(getActivity(), this.userLocation); } checkIfShowingListInsteadOfMapChanged(); getActivity().supportInvalidateOptionsMenu(); // initialize action bar list/map switch icon updateListMapToggleMenuItem(); onUserLocationChanged(((MTActivityWithLocation) getActivity()).getUserLocation()); } private static final int POIS_LOADER = 0; @Override public Loader<ArrayList<POIManager>> onCreateLoader(int id, Bundle args) { switch (id) { case POIS_LOADER: if (TextUtils.isEmpty(this.authority)) { return null; } return new AgencyPOIsLoader(getActivity(), this.authority); default: MTLog.w(this, "Loader id '%s' unknown!", id); return null; } } @Override public void onLoaderReset(Loader<ArrayList<POIManager>> loader) { if (this.adapter != null) { this.adapter.clear(); } this.mapViewController.notifyMarkerChanged(this); } @Override public void onLoadFinished(Loader<ArrayList<POIManager>> loader, ArrayList<POIManager> data) { this.adapter.setPois(data); this.mapViewController.notifyMarkerChanged(this); this.adapter.updateDistanceNowAsync(this.userLocation); switchView(getView()); } @Override public void onUserLocationChanged(Location newLocation) { if (newLocation == null) { return; } if (this.userLocation == null || LocationUtils.isMoreRelevant(getLogTag(), this.userLocation, newLocation)) { this.userLocation = newLocation; if (this.adapter != null) { this.adapter.setLocation(newLocation); } } this.mapViewController.onUserLocationChanged(newLocation); } @Override public void onPause() { super.onPause(); onFragmentInvisible(); } @Override public void onResume() { super.onResume(); if (this.fragmentPosition >= 0 && this.fragmentPosition == this.lastVisibleFragmentPosition) { onFragmentVisible(); } // ELSE would be call later if (this.adapter != null) { this.adapter.setActivity(getActivity()); } } @Override public void onLowMemory() { super.onLowMemory(); this.mapViewController.onLowMemory(); } @Override public void onDestroyView() { super.onDestroyView(); this.mapViewController.onDestroyView(); } @Override public void onDestroy() { super.onDestroy(); if (this.adapter != null) { this.adapter.onDestroy(); } this.mapViewController.onDestroy(); } private MenuItem listMapToggleMenuItem; @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); if (menu.findItem(R.id.menu_toggle_list_map) == null) { inflater.inflate(R.menu.menu_agency_pois, menu); this.listMapToggleMenuItem = menu.findItem(R.id.menu_toggle_list_map); if (!this.fragmentVisible) { this.listMapToggleMenuItem.setVisible(false); } } else { this.listMapToggleMenuItem = menu.findItem(R.id.menu_toggle_list_map); } updateListMapToggleMenuItem(); } private void updateListMapToggleMenuItem() { if (!this.fragmentVisible) { return; } if (this.listMapToggleMenuItem == null) { return; } boolean showingListInsteadOfMap = isShowingListInsteadOfMap(); this.listMapToggleMenuItem.setIcon(showingListInsteadOfMap ? R.drawable.ic_action_action_map_holo_dark : R.drawable.ic_action_action_list_holo_dark); this.listMapToggleMenuItem.setTitle(showingListInsteadOfMap ? R.string.menu_action_map : R.string.menu_action_list); this.listMapToggleMenuItem.setVisible(true); } private Boolean showingListInsteadOfMap = null; private boolean isShowingListInsteadOfMap() { if (this.showingListInsteadOfMap == null) { boolean showingListInsteadOfMapLastSet = PreferenceUtils.getPrefDefault(getActivity(), PreferenceUtils.PREFS_AGENCY_POIS_SHOWING_LIST_INSTEAD_OF_MAP_LAST_SET, PreferenceUtils.PREFS_AGENCY_POIS_SHOWING_LIST_INSTEAD_OF_MAP_DEFAULT); this.showingListInsteadOfMap = TextUtils.isEmpty(this.authority) ? showingListInsteadOfMapLastSet : PreferenceUtils.getPrefDefault(getActivity(), PreferenceUtils.getPREFS_AGENCY_POIS_SHOWING_LIST_INSTEAD_OF_MAP(this.authority), showingListInsteadOfMapLastSet); } return this.showingListInsteadOfMap; } private void checkIfShowingListInsteadOfMapChanged() { if (this.showingListInsteadOfMap == null) { return; } boolean showingListInsteadOfMapLastSet = PreferenceUtils.getPrefDefault(getActivity(), PreferenceUtils.PREFS_AGENCY_POIS_SHOWING_LIST_INSTEAD_OF_MAP_LAST_SET, PreferenceUtils.PREFS_AGENCY_POIS_SHOWING_LIST_INSTEAD_OF_MAP_DEFAULT); boolean newShowingListInsteadOfMap = TextUtils.isEmpty(this.authority) ? showingListInsteadOfMapLastSet : PreferenceUtils.getPrefDefault(getActivity(), PreferenceUtils.getPREFS_AGENCY_POIS_SHOWING_LIST_INSTEAD_OF_MAP(this.authority), showingListInsteadOfMapLastSet); if (newShowingListInsteadOfMap != this.showingListInsteadOfMap) { setShowingListInsteadOfMap(newShowingListInsteadOfMap); } } private void setShowingListInsteadOfMap(boolean newShowingListInsteadOfMap) { if (this.showingListInsteadOfMap != null && this.showingListInsteadOfMap == newShowingListInsteadOfMap) { return; // nothing changed } this.showingListInsteadOfMap = newShowingListInsteadOfMap; // switching PreferenceUtils.savePrefDefault(getActivity(), PreferenceUtils.PREFS_AGENCY_POIS_SHOWING_LIST_INSTEAD_OF_MAP_LAST_SET, this.showingListInsteadOfMap, false); if (!TextUtils.isEmpty(this.authority)) { PreferenceUtils.savePrefDefault(getActivity(), PreferenceUtils.getPREFS_AGENCY_POIS_SHOWING_LIST_INSTEAD_OF_MAP(this.authority), this.showingListInsteadOfMap, false); } if (this.adapter != null) { View view = getView(); setupView(view); if (!this.showingListInsteadOfMap) { // map this.mapViewController.onResume(); } else { // list this.mapViewController.onPause(); } switchView(view); } updateListMapToggleMenuItem(); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (!this.fragmentVisible) { return false; // not handled } switch (item.getItemId()) { case R.id.menu_toggle_list_map: setShowingListInsteadOfMap(!isShowingListInsteadOfMap()); // switching return true; // handled } return super.onOptionsItemSelected(item); } private void switchView(View view) { if (this.adapter == null || !this.adapter.isInitialized()) { showLoading(view); } else if (this.adapter.getPoisCount() == 0) { showEmpty(view); } else { showListOrMap(view); } } private void showListOrMap(View view) { if (isShowingListInsteadOfMap()) { // list this.mapViewController.hideMap(); inflateList(view); view.findViewById(R.id.list).setVisibility(View.VISIBLE); // show } else { // map this.mapViewController.showMap(view); if (view.findViewById(R.id.list) != null) { // IF inflated/present DO view.findViewById(R.id.list).setVisibility(View.GONE); // hide } } if (view.findViewById(R.id.loading) != null) { // IF inflated/present DO view.findViewById(R.id.loading).setVisibility(View.GONE); // hide } if (view.findViewById(R.id.empty) != null) { // IF inflated/present DO view.findViewById(R.id.empty).setVisibility(View.GONE); // hide } } private void inflateList(View view) { if (view.findViewById(R.id.list) == null) { // IF NOT present/inflated DO ((ViewStub) view.findViewById(R.id.list_stub)).inflate(); // inflate ((AbsListView) view.findViewById(R.id.list)).setFastScrollEnabled(true); // long list linkAdapterWithListView(view); } } private void showLoading(View view) { if (view.findViewById(R.id.list) != null) { // IF inflated/present DO view.findViewById(R.id.list).setVisibility(View.GONE); // hide } this.mapViewController.hideMap(); if (view.findViewById(R.id.empty) != null) { // IF inflated/present DO view.findViewById(R.id.empty).setVisibility(View.GONE); // hide } view.findViewById(R.id.loading).setVisibility(View.VISIBLE); // show } private void showEmpty(View view) { if (view.findViewById(R.id.list) != null) { // IF inflated/present DO view.findViewById(R.id.list).setVisibility(View.GONE); // hide } this.mapViewController.hideMap(); if (view.findViewById(R.id.loading) != null) { // IF inflated/present DO view.findViewById(R.id.loading).setVisibility(View.GONE); // hide } if (view.findViewById(R.id.empty) == null) { // IF NOT present/inflated DO ((ViewStub) view.findViewById(R.id.empty_stub)).inflate(); // inflate } if (!TextUtils.isEmpty(this.emptyText)) { ((TextView) view.findViewById(R.id.empty_text)).setText(this.emptyText); } view.findViewById(R.id.empty).setVisibility(View.VISIBLE); // show } }