package org.mtransit.android.ui.fragment;
import java.util.ArrayList;
import org.mtransit.android.R;
import org.mtransit.android.commons.LocationUtils;
import org.mtransit.android.commons.MTLog;
import org.mtransit.android.commons.TaskUtils;
import org.mtransit.android.commons.ThemeUtils;
import org.mtransit.android.commons.ToastUtils;
import org.mtransit.android.commons.task.MTAsyncTask;
import org.mtransit.android.data.DataSourceType;
import org.mtransit.android.data.POIArrayAdapter;
import org.mtransit.android.data.POIManager;
import org.mtransit.android.provider.FavoriteManager;
import org.mtransit.android.task.HomePOILoader;
import org.mtransit.android.ui.MTActivityWithLocation;
import org.mtransit.android.ui.MainActivity;
import org.mtransit.android.ui.widget.ListViewSwipeRefreshLayout;
import org.mtransit.android.util.LoaderUtils;
import android.app.Activity;
import android.content.Context;
import android.location.Address;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.widget.SwipeRefreshLayout;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.AbsListView;
import android.widget.PopupWindow;
public class HomeFragment extends ABFragment implements LoaderManager.LoaderCallbacks<ArrayList<POIManager>>, MTActivityWithLocation.UserLocationListener,
FavoriteManager.FavoriteUpdateListener, SwipeRefreshLayout.OnRefreshListener, POIArrayAdapter.TypeHeaderButtonsClickListener,
POIArrayAdapter.InfiniteLoadingListener {
private static final String TAG = HomeFragment.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private static final String TRACKING_SCREEN_NAME = "Home";
@Override
public String getScreenName() {
return TRACKING_SCREEN_NAME;
}
private static final String EXTRA_NEARBY_LOCATION = "extra_nearby_location";
public static HomeFragment newInstance(Location optNearbyLocation) {
HomeFragment f = new HomeFragment();
Bundle args = new Bundle();
if (optNearbyLocation != null) {
args.putParcelable(EXTRA_NEARBY_LOCATION, optNearbyLocation);
}
f.setArguments(args);
return f;
}
private POIArrayAdapter adapter;
private Location userLocation;
private Location nearbyLocation;
private String nearbyLocationAddress;
private ListViewSwipeRefreshLayout swipeRefreshLayout;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
initAdapters(activity);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
restoreInstanceState(savedInstanceState, getArguments());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_home, container, false);
setupView(view);
return view;
}
@Override
public void onRefresh() {
initiateRefresh();
}
private boolean initiateRefresh() {
if (LocationUtils.areAlmostTheSame(this.nearbyLocation, this.userLocation, LocationUtils.LOCATION_CHANGED_ALLOW_REFRESH_IN_METERS)) {
setSwipeRefreshLayoutRefreshing(false);
return false;
}
useNewNearbyLocation(this.userLocation);
return true;
}
private boolean modulesUpdated = false;
@Override
public void onModulesUpdated() {
this.modulesUpdated = true;
if (!isResumed()) {
return;
}
this.nearbyLocation = null; // force refresh
initiateRefresh();
this.modulesUpdated = false; // processed
}
private void restoreInstanceState(Bundle... bundles) {
}
@Override
public void onSaveInstanceState(Bundle outState) {
if (this.nearbyLocation != null) {
outState.putParcelable(EXTRA_NEARBY_LOCATION, this.nearbyLocation);
}
super.onSaveInstanceState(outState);
}
@Override
public void onResume() {
super.onResume();
View view = getView();
if (this.modulesUpdated) {
if (view != null) {
view.post(new Runnable() {
@Override
public void run() {
if (HomeFragment.this.modulesUpdated) {
onModulesUpdated();
}
}
});
}
}
switchView(view);
if (this.adapter != null) {
this.adapter.onResume(getActivity(), this.userLocation);
}
onUserLocationChanged(((MTActivityWithLocation) getActivity()).getLastLocation());
}
private MTAsyncTask<Location, Void, String> findNearbyLocationTask;
private void findNearbyLocation() {
if (!TextUtils.isEmpty(this.nearbyLocationAddress)) {
return;
}
TaskUtils.cancelQuietly(this.findNearbyLocationTask, true);
this.findNearbyLocationTask = new MTAsyncTask<Location, Void, String>() {
@Override
public String getLogTag() {
return HomeFragment.this.getLogTag();
}
@Override
protected String doInBackgroundMT(Location... locations) {
Activity activity = getActivity();
Location nearbyLocation = locations[0];
if (activity == null || nearbyLocation == null) {
return null;
}
Address address = LocationUtils.getLocationAddress(activity, nearbyLocation);
return LocationUtils.getLocationString(activity, null, address, nearbyLocation.getAccuracy());
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
boolean refreshRequired = result != null && !result.equals(HomeFragment.this.nearbyLocationAddress);
HomeFragment.this.nearbyLocationAddress = result;
if (refreshRequired) {
Activity activity = getActivity();
if (activity != null) {
getAbController().setABSubtitle(HomeFragment.this, getABSubtitle(activity), false);
getAbController().setABReady(HomeFragment.this, isABReady(), true);
}
}
}
};
TaskUtils.execute(this.findNearbyLocationTask, this.nearbyLocation);
}
@Override
public void onDestroy() {
super.onDestroy();
this.userLocation = null;
if (this.adapter != null) {
this.adapter.onDestroy();
this.adapter = null;
}
this.loadFinished = false;
TaskUtils.cancelQuietly(this.findNearbyLocationTask, true);
}
private static final int POIS_LOADER = 0;
@Override
public Loader<ArrayList<POIManager>> onCreateLoader(int id, Bundle args) {
switch (id) {
case POIS_LOADER:
if (this.nearbyLocation == null) {
return null;
}
this.loadFinished = false;
return new HomePOILoader(this, getActivity(), this.nearbyLocation.getLatitude(), this.nearbyLocation.getLongitude(),
this.nearbyLocation.getAccuracy());
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.loadFinished = false;
}
public void onLoadPartial(ArrayList<POIManager> data) {
addPOIs(data);
}
@Override
public void onLoadFinished(Loader<ArrayList<POIManager>> loader, ArrayList<POIManager> data) {
this.loadFinished = true;
addPOIs(data);
this.adapter.updateDistanceNowAsync(this.userLocation);
findNearbyLocation();
}
private void addPOIs(ArrayList<POIManager> data) {
if (this.adapter == null) {
return; // too late
}
boolean scrollToTop = this.adapter.getPoisCount() == 0;
this.adapter.appendPois(data);
View view = getView();
if (scrollToTop && view != null && view.findViewById(R.id.list) != null) {
((AbsListView) view.findViewById(R.id.list)).setSelection(0);
}
}
@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);
}
}
if (this.nearbyLocation == null) {
useNewNearbyLocation(newLocation);
} else {
if (this.adapter != null && this.adapter.isInitialized()
&& !LocationUtils.areAlmostTheSame(this.nearbyLocation, this.userLocation, LocationUtils.LOCATION_CHANGED_NOTIFY_USER_IN_METERS)) {
showLocationToast();
} else {
hideLocationToast();
}
}
}
private PopupWindow locationToast = null;
private PopupWindow getLocationToast() {
if (this.locationToast == null) {
initLocationPopup();
}
return this.locationToast;
}
private void initLocationPopup() {
this.locationToast = ToastUtils.getNewTouchableToast(getActivity(), R.string.new_location_toast);
if (this.locationToast != null) {
this.locationToast.setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent me) {
if (me.getAction() == MotionEvent.ACTION_DOWN) {
boolean handled = initiateRefresh();
hideLocationToast();
return handled;
}
return false; // not handled
}
});
this.locationToast.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
HomeFragment.this.toastShown = false;
}
});
}
}
private boolean toastShown = false;
private void showLocationToast() {
if (!this.toastShown) {
PopupWindow locationToast = getLocationToast();
if (locationToast != null) {
this.toastShown = ToastUtils.showTouchableToast(getActivity(), locationToast, getView());
}
}
}
private void hideLocationToast() {
if (this.locationToast != null) {
this.locationToast.dismiss();
}
this.toastShown = false;
}
private void useNewNearbyLocation(Location newNearbyLocation) {
if (newNearbyLocation == null) {
return;
}
if (LocationUtils.areTheSame(newNearbyLocation, this.nearbyLocation)) {
return;
}
this.nearbyLocation = newNearbyLocation;
if (this.adapter != null) {
this.adapter.clear();
}
this.loadFinished = false;
switchView(getView());
if (this.nearbyLocation != null) {
LoaderUtils.restartLoader(this, POIS_LOADER, null, this);
}
hideLocationToast();
setSwipeRefreshLayoutRefreshing(false);
this.nearbyLocationAddress = null;
getAbController().setABSubtitle(this, getABSubtitle(getActivity()), false);
getAbController().setABReady(this, isABReady(), true);
}
public void setSwipeRefreshLayoutRefreshing(boolean refreshing) {
if (this.swipeRefreshLayout != null) {
if (refreshing) {
if (!this.swipeRefreshLayout.isRefreshing()) {
this.swipeRefreshLayout.setRefreshing(true);
}
} else {
this.swipeRefreshLayout.setRefreshing(false);
}
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_home, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_show_map:
((MainActivity) getActivity()).addFragmentToStack(MapFragment.newInstance(null, null, null));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onPause() {
super.onPause();
if (this.adapter != null) {
this.adapter.onPause();
}
hideLocationToast();
}
@Override
public void onFavoriteUpdated() {
if (this.adapter != null) {
this.adapter.onFavoriteUpdated();
}
}
private void initAdapters(Activity activity) {
this.adapter = new POIArrayAdapter(activity);
this.adapter.setTag(getLogTag());
this.adapter.setFavoriteUpdateListener(this);
this.adapter.setShowBrowseHeaderSection(true);
this.adapter.setShowTypeHeader(POIArrayAdapter.TYPE_HEADER_MORE);
this.adapter.setShowTypeHeaderNearby(true);
this.adapter.setInfiniteLoading(true);
this.adapter.setInfiniteLoadingListener(this);
this.adapter.setOnTypeHeaderButtonsClickListener(this);
}
private boolean loadFinished = false;
@Override
public boolean isLoadingMore() {
return this.adapter == null || this.adapter.getPoisCount() == 0 || !this.loadFinished;
}
@Override
public boolean showingDone() {
return false;
}
@Override
public boolean onTypeHeaderButtonClick(int buttonId, DataSourceType type) {
if (buttonId == POIArrayAdapter.TypeHeaderButtonsClickListener.BUTTON_MORE) {
((MainActivity) getActivity()).addFragmentToStack(NearbyFragment.newNearbyInstance(null, type.getId()));
return true; // handled
}
return false; // not handled
}
private void setupView(View view) {
if (view == null) {
return;
}
this.swipeRefreshLayout = (ListViewSwipeRefreshLayout) view.findViewById(R.id.swiperefresh);
this.swipeRefreshLayout.setColorSchemeColors(ThemeUtils.resolveColorAttribute(getActivity(), R.attr.colorAccent));
this.swipeRefreshLayout.setOnRefreshListener(this);
inflateList(view);
switchView(view);
linkAdapterWithListView(view);
}
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 switchView(View view) {
if (view == null) {
return;
}
showList(view);
}
private void showList(View view) {
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
}
inflateList(view);
view.findViewById(R.id.list).setVisibility(View.VISIBLE); // show
}
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
if (this.swipeRefreshLayout != null) {
this.swipeRefreshLayout.setListViewWR((AbsListView) view.findViewById(R.id.list));
}
}
}
@Override
public CharSequence getABTitle(Context context) {
return context.getString(R.string.app_name);
}
@Override
public CharSequence getABSubtitle(Context context) {
return this.nearbyLocationAddress;
}
}