package org.michenux.yourappidea.aroundme;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.IntentSender;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
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.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.tbruyelle.rxpermissions.RxPermissions;
import org.michenux.drodrolib.network.connectivity.ConnectivityUtils;
import org.michenux.drodrolib.ui.snackbar.SnackbarHelper;
import org.michenux.yourappidea.BuildConfig;
import org.michenux.yourappidea.R;
import org.michenux.yourappidea.YourApplication;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import rx.Subscription;
public class AroundMeFragment extends Fragment implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
PlaceLocalProvider.PlaceLoaderCallback {
private static final int LOCATIONSERVICES_RESOLUTION_RESULCODE = 765;
private static final int SELECTCITY_REQUESTCODE = 1000;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mRequest;
private Geocoder mGeocoder;
private PlaceRecyclerAdapter mPlaceListAdapter;
private String mCityName;
private PlaceProvider mPlaceProvider;
private boolean mLocalProvider = true;
private boolean mUseLocationClient = true;
private Location mCurrentLocation;
private Subscription mSubscription;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((YourApplication) getActivity().getApplication()).inject(this);
setRetainInstance(true);
setHasOptionsMenu(true);
mGoogleApiClient = new GoogleApiClient.Builder(this.getActivity())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mRequest = LocationRequest.create()
.setInterval(15000)
.setFastestInterval(5000)
.setSmallestDisplacement(50)
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mGeocoder = new Geocoder(this.getActivity(), Locale.getDefault());
mPlaceListAdapter = new PlaceRecyclerAdapter(new ArrayList<Place>());
if (savedInstanceState != null) {
this.mUseLocationClient = savedInstanceState.getBoolean("useLocationClient", true);
this.mCityName = savedInstanceState.getString("cityName");
this.mCurrentLocation = savedInstanceState.getParcelable("currentLocation");
this.mLocalProvider = savedInstanceState.getBoolean("localProvider", true);
}
if (this.mLocalProvider) {
mPlaceProvider = new PlaceLocalProvider(this, this);
} else {
mPlaceProvider = new PlaceRemoteProvider(this, this);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.aroundme_menu, menu);
MenuItem localMenuItem = menu.findItem(R.id.aroundme_menu_localprovider);
MenuItem remoteMenuItem = menu.findItem(R.id.aroundme_menu_remoteprovider);
if (this.mLocalProvider) {
localMenuItem.setChecked(true);
} else {
remoteMenuItem.setChecked(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.aroundme_menu_info:
new MaterialDialog.Builder(this.getActivity())
.title(R.string.aroundme_info_title)
.items(R.array.aroundme_info_details)
.positiveText(R.string.close)
.show();
return true;
case R.id.aroundme_menu_myposition:
if (!this.mUseLocationClient) {
this.mUseLocationClient = true;
((TextView) this.getView().findViewById(R.id.aroundme_cityname)).setText(R.string.aroundme_nolocation);
this.mPlaceListAdapter.clear();
this.mPlaceListAdapter.notifyDataSetChanged();
this.connectLocationClient();
}
return true;
case R.id.aroundme_menu_selectlocation:
Intent oIntent = new Intent(getActivity(), CityActivity.class);
startActivityForResult(oIntent, SELECTCITY_REQUESTCODE);
// no animation
getActivity().overridePendingTransition(0, 0);
return true;
case R.id.aroundme_menu_localprovider:
if (!mLocalProvider) {
item.setChecked(true);
this.mLocalProvider = true;
this.mPlaceProvider = new PlaceLocalProvider(this, this);
this.mPlaceProvider.onLocationChanged(this.mCurrentLocation);
}
return true;
case R.id.aroundme_menu_remoteprovider:
if (mLocalProvider) {
item.setChecked(true);
this.mLocalProvider = false;
this.mPlaceProvider = new PlaceRemoteProvider(this, this);
this.mPlaceProvider.onLocationChanged(this.mCurrentLocation);
}
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.aroundme_fragment, container, false);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.aroundme_listview);
recyclerView.setAdapter(this.mPlaceListAdapter);
recyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
if (mCityName != null) {
TextView textView = (TextView) view.findViewById(R.id.aroundme_cityname);
textView.setText(mCityName);
}
return view;
}
@Override
public void onResume() {
super.onResume();
mSubscription = RxPermissions.getInstance(this.getActivity())
.request(Manifest.permission.ACCESS_FINE_LOCATION)
.subscribe(granted -> {
if (granted) {
this.connectLocationClient();
} else {
SnackbarHelper.showInfoLongMessage(this.getView(), R.string.error_permissionfinelocationrequired);
}
});
}
@Override
public void onPause() {
super.onPause();
this.disconnectLocationClient();
mSubscription.unsubscribe();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("useLocationClient", this.mUseLocationClient);
outState.putParcelable("currentLocation", this.mCurrentLocation);
outState.putString("cityName", this.mCityName);
outState.putBoolean("localProvider", this.mLocalProvider);
}
@Override
public void onConnected(Bundle bundle) {
registerLocationUpdates();
}
@SuppressLint("MissingPermission") // Permissions enforced through RxPermissions
private void registerLocationUpdates() {
PendingResult<Status> result = LocationServices.FusedLocationApi
.requestLocationUpdates(
mGoogleApiClient,
mRequest,
this);
result.setResultCallback(new ResultCallback<Status>() {
public void onResult(Status status) {
if (status.isSuccess()) {
// Successfully registered
} else if (status.hasResolution()) {
// Google provides a way to fix the issue
try {
status.startResolutionForResult(
AroundMeFragment.this.getActivity(), // your current activity used to receive the result
LOCATIONSERVICES_RESOLUTION_RESULCODE); // the result code you'll look for in your onActivityResult method to retry registering
} catch (IntentSender.SendIntentException e) {
Log.e(YourApplication.LOG_TAG, "SimpleMapFragment start resolution failure: ", e);
}
} else {
// No recovery. Weep softly or inform the user.
Log.e(YourApplication.LOG_TAG, "SimpleMapFragment registering failed: " + status.getStatusMessage());
}
}
});
}
@Override
public void onLocationChanged(Location location) {
if (BuildConfig.DEBUG) {
Log.d(YourApplication.LOG_TAG, "AroundmeFragment.onLocationChanged() - new loc: " + location);
}
this.mCurrentLocation = location;
try {
if (ConnectivityUtils.isConnected(this.getActivity())) {
List<Address> addresses = mGeocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
if (addresses != null && !addresses.isEmpty()) {
Address address = addresses.get(0);
this.updateCityView(address.getLocality(), address.getCountryName());
}
} else {
this.updateCityView("Lat:" + location.getLatitude(), " Long: " + location.getLongitude());
}
this.mPlaceProvider.onLocationChanged(location);
} catch (Exception e) {
Log.e(YourApplication.LOG_TAG, "AroundmeFragment.onLocationChanged()", e);
}
}
private void updateCityView(String name, String country) {
this.mCityName = name + " (" + country + ")";
TextView textView = (TextView) getView().findViewById(R.id.aroundme_cityname);
textView.setText(this.mCityName);
}
@Override
public void onPlaceLoadFinished(List<Place> places) {
this.mPlaceListAdapter.clear();
for (Place place : places) {
mPlaceListAdapter.add(place);
}
this.mPlaceListAdapter.notifyDataSetChanged();
}
@Override
public void onDestroy() {
mPlaceProvider.onDestroy();
super.onDestroy();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SELECTCITY_REQUESTCODE && resultCode == CityActivity.RESULT_OK) {
this.updateCityView(data.getStringExtra(CityListFragment.CITY_NAME), data.getStringExtra(CityListFragment.CITY_COUNTRY));
this.mCurrentLocation = new Location("manual");
this.mCurrentLocation.setLatitude(data.getDoubleExtra(CityListFragment.CITY_LATITUDE, 0));
this.mCurrentLocation.setLongitude(data.getDoubleExtra(CityListFragment.CITY_LONGITUDE, 0));
this.mUseLocationClient = false;
this.mPlaceProvider.onLocationChanged(this.mCurrentLocation);
}
}
private void connectLocationClient() {
if (mUseLocationClient) {
mGoogleApiClient.connect();
}
}
private void disconnectLocationClient() {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
mGoogleApiClient.disconnect();
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
SnackbarHelper.showInfoLongMessage(this.getView(), R.string.error_connectionfailed);
}
@Override
public void onConnectionSuspended(int i) {
SnackbarHelper.showInfoLongMessage(this.getView(), R.string.error_connectionsuspended);
}
}