package com.ianhanniballake.contractiontimer.ui;
import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
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 android.widget.Toast;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.ianhanniballake.contractiontimer.BuildConfig;
import com.ianhanniballake.contractiontimer.R;
import com.ianhanniballake.contractiontimer.appwidget.AppWidgetUpdateHandler;
import com.ianhanniballake.contractiontimer.notification.NotificationUpdateService;
import com.ianhanniballake.contractiontimer.provider.ContractionContract;
import java.util.Date;
/**
* Fragment showing the details of an individual contraction
*/
public class ViewFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private final static String TAG = ViewFragment.class.getSimpleName();
/**
* Whether the current contraction is ongoing (i.e., not yet ended). Null indicates that we haven't checked yet,
* while true or false indicates whether the contraction is ongoing
*/
Boolean isContractionOngoing = null;
/**
* Adapter to display the detailed data
*/
private CursorAdapter adapter;
/**
* Id of the current contraction to show
*/
private long contractionId = -1;
/**
* Handler for asynchronous deletes of contractions
*/
private AsyncQueryHandler contractionQueryHandler;
/**
* Creates a new Fragment to display the given contraction
*
* @param contractionId Id of the Contraction to display
* @return ViewFragment associated with the given id
*/
@NonNull
public static ViewFragment createInstance(final long contractionId) {
final ViewFragment viewFragment = new ViewFragment();
final Bundle args = new Bundle();
args.putLong(BaseColumns._ID, contractionId);
viewFragment.setArguments(args);
return viewFragment;
}
/**
* We need to find the exact view_fragment view as there is a NoSaveStateFrameLayout view inserted in between the
* parent and the view we created in onCreateView
*
* @return View created in onCreateView
*/
@Nullable
private View getFragmentView() {
final View rootView = getView();
return rootView == null ? null : rootView.findViewById(R.id.view_fragment);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
final Context applicationContext = getActivity().getApplicationContext();
contractionQueryHandler = new AsyncQueryHandler(getActivity().getContentResolver()) {
@Override
protected void onDeleteComplete(final int token, final Object cookie, final int result) {
AppWidgetUpdateHandler.createInstance().updateAllWidgets(applicationContext);
NotificationUpdateService.updateNotification(applicationContext);
final Activity activity = getActivity();
if (activity != null)
activity.finish();
}
};
adapter = new
CursorAdapter(getActivity(), null, 0) {
@Override
public void bindView(final View view, final Context context, final Cursor cursor) {
final TextView startTimeView = (TextView) view.findViewById(R.id.start_time);
String timeFormat = "hh:mm:ssa";
if (DateFormat.is24HourFormat(context))
timeFormat = "kk:mm:ss";
final int startTimeColumnIndex = cursor
.getColumnIndex(ContractionContract.Contractions.COLUMN_NAME_START_TIME);
final long startTime = cursor.getLong(startTimeColumnIndex);
startTimeView.setText(DateFormat.format(timeFormat, startTime));
final TextView startDateView = (TextView) view.findViewById(R.id.start_date);
final Date startDate = new Date(startTime);
startDateView.setText(DateFormat.getDateFormat(getActivity()).format(startDate));
final TextView endTimeView = (TextView) view.findViewById(R.id.end_time);
final TextView endDateView = (TextView) view.findViewById(R.id.end_date);
final TextView durationView = (TextView) view.findViewById(R.id.duration);
final int endTimeColumnIndex = cursor
.getColumnIndex(ContractionContract.Contractions.COLUMN_NAME_END_TIME);
isContractionOngoing = cursor.isNull(endTimeColumnIndex);
if (isContractionOngoing) {
endTimeView.setText(" ");
endDateView.setText(" ");
durationView.setText(getString(R.string.duration_ongoing));
} else {
final long endTime = cursor.getLong(endTimeColumnIndex);
endTimeView.setText(DateFormat.format(timeFormat, endTime));
final Date endDate = new Date(endTime);
endDateView.setText(DateFormat.getDateFormat(getActivity()).format(endDate));
final long durationInSeconds = (endTime - startTime) / 1000;
durationView.setText(DateUtils.formatElapsedTime(durationInSeconds));
}
getActivity().supportInvalidateOptionsMenu();
final TextView noteView = (TextView) view.findViewById(R.id.note);
final int noteColumnIndex = cursor.getColumnIndex(ContractionContract.Contractions.COLUMN_NAME_NOTE);
final String note = cursor.getString(noteColumnIndex);
noteView.setText(note);
}
@Override
public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
// View is already inflated in onCreateView
return null;
}
};
if (getArguments() != null) {
contractionId = getArguments().getLong(BaseColumns._ID, 0);
if (contractionId != -1)
getLoaderManager().initLoader(0, null, this);
}
}
@Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
final Uri contractionUri = ContentUris.withAppendedId(ContractionContract.Contractions.CONTENT_ID_URI_PATTERN,
contractionId);
return new CursorLoader(getActivity(), contractionUri, null, null, null, null);
}
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// Only allow editing contractions that have already finished
final boolean showEdit = isContractionOngoing != null && !isContractionOngoing;
final MenuItem editItem = menu.findItem(R.id.menu_edit);
editItem.setVisible(showEdit);
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_view, container, false);
}
@Override
public void onLoaderReset(final Loader<Cursor> data) {
adapter.swapCursor(null);
}
@Override
public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) {
adapter.swapCursor(data);
if (data.moveToFirst())
adapter.bindView(getFragmentView(), getActivity(), data);
getActivity().supportInvalidateOptionsMenu();
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final Uri uri = ContentUris.withAppendedId(ContractionContract.Contractions.CONTENT_ID_URI_BASE, contractionId);
FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(getContext());
switch (item.getItemId()) {
case R.id.menu_edit:
// isContractionOngoing should be non-null at this point, but
// just in case
if (isContractionOngoing == null)
return true;
if (BuildConfig.DEBUG)
Log.d(TAG, "View selected edit");
if (isContractionOngoing)
Toast.makeText(getActivity(), R.string.edit_ongoing_error, Toast.LENGTH_SHORT).show();
else {
analytics.logEvent("edit_open_view", null);
startActivity(new Intent(Intent.ACTION_EDIT, uri).setPackage(getActivity().getPackageName()));
}
return true;
case R.id.menu_delete:
if (BuildConfig.DEBUG)
Log.d(TAG, "View selected delete");
Bundle bundle = new Bundle();
bundle.putString(FirebaseAnalytics.Param.VALUE, Integer.toString(1));
analytics.logEvent("delete_view", bundle);
contractionQueryHandler.startDelete(0, 0, uri, null, null);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}