RecyclerViewFragment and other abstract classes in use for alarms and timers

This commit is contained in:
Phillip Hsu
2016-07-30 14:36:33 -07:00
parent b43ff03662
commit 066ac67325
21 changed files with 605 additions and 133 deletions
@@ -1,13 +1,10 @@
package com.philliphsu.clock2.alarms;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.ViewGroup;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.BaseCursorAdapter;
import com.philliphsu.clock2.OnListItemInteractionListener;
import com.philliphsu.clock2.model.AlarmDatabaseHelper.AlarmCursor;
import com.philliphsu.clock2.util.AlarmController;
/**
@@ -15,63 +12,19 @@ import com.philliphsu.clock2.util.AlarmController;
*
* TODO: Extend from BaseCursorAdapter
*/
public class AlarmsCursorAdapter extends RecyclerView.Adapter<AlarmViewHolder> {
public class AlarmsCursorAdapter extends BaseCursorAdapter<Alarm, AlarmViewHolder, com.philliphsu.clock2.model.AlarmCursor> {
private static final String TAG = "AlarmsCursorAdapter";
private final OnListItemInteractionListener<Alarm> mListener;
private final AlarmController mAlarmController;
private AlarmCursor mCursor;
public AlarmsCursorAdapter(OnListItemInteractionListener<Alarm> listener,
AlarmController alarmController) {
mListener = listener;
super(listener);
mAlarmController = alarmController;
// Excerpt from docs of notifyDataSetChanged():
// "RecyclerView will attempt to synthesize [artificially create?]
// visible structural change events [when items are inserted, removed or
// moved] for adapters that report that they have stable IDs when
// [notifyDataSetChanged()] is used. This can help for the purposes of
// animation and visual object persistence [?] but individual item views
// will still need to be rebound and relaid out."
setHasStableIds(true);
}
@Override
public AlarmViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new AlarmViewHolder(parent, mListener, mAlarmController);
}
@Override
public void onBindViewHolder(AlarmViewHolder holder, int position) {
if (!mCursor.moveToPosition(position)) {
Log.e(TAG, "Failed to bind alarm " + position);
return;
}
holder.onBind(mCursor.getAlarm());
}
@Override
public int getItemCount() {
return mCursor == null ? 0 : mCursor.getCount();
}
@Override
public long getItemId(int position) {
if (mCursor == null || !mCursor.moveToPosition(position)) {
return super.getItemId(position); // -1
}
return mCursor.getId();
}
// TODO: Cursor param should be the appropriate subclass?
public void swapCursor(Cursor cursor) {
if (mCursor == cursor) {
return;
}
if (mCursor != null) {
mCursor.close();
}
mCursor = (AlarmCursor) cursor;
notifyDataSetChanged();
protected AlarmViewHolder onCreateViewHolder(ViewGroup parent, OnListItemInteractionListener<Alarm> listener) {
return new AlarmViewHolder(parent, listener, mAlarmController);
}
}
@@ -1,26 +1,20 @@
package com.philliphsu.clock2.alarms;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.AsyncItemChangeHandler;
import com.philliphsu.clock2.OnListItemInteractionListener;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.RecyclerViewFragment;
import com.philliphsu.clock2.editalarm.EditAlarmActivity;
import com.philliphsu.clock2.model.AlarmCursor;
import com.philliphsu.clock2.model.AlarmsListCursorLoader;
import com.philliphsu.clock2.util.AlarmController;
import com.philliphsu.clock2.util.DelayedSnackbarHandler;
@@ -28,10 +22,11 @@ import com.philliphsu.clock2.util.DelayedSnackbarHandler;
import butterknife.Bind;
import butterknife.ButterKnife;
// TODO: Use native fragments since we're targeting API >=19?
// TODO: Use native LoaderCallbacks.
public class AlarmsFragment extends Fragment implements LoaderCallbacks<Cursor>,
OnListItemInteractionListener<Alarm>, ScrollHandler {
public class AlarmsFragment extends RecyclerViewFragment<
Alarm,
AlarmViewHolder,
AlarmCursor,
AlarmsCursorAdapter> implements ScrollHandler {
private static final String TAG = "AlarmsFragment";
private static final int REQUEST_EDIT_ALARM = 0;
// Public because MainActivity needs to use it.
@@ -76,23 +71,6 @@ public class AlarmsFragment extends Fragment implements LoaderCallbacks<Cursor>,
mAlarmController = new AlarmController(getActivity(), mSnackbarAnchor);
mAsyncItemChangeHandler = new AsyncItemChangeHandler(getActivity(),
mSnackbarAnchor, this, mAlarmController);
getLoaderManager().initLoader(0, null, this);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_alarms, container, false);
ButterKnife.bind(this, view);
// Set the adapter
Context context = view.getContext();
mList.setLayoutManager(new LinearLayoutManager(context));
mAdapter = new AlarmsCursorAdapter(this, mAlarmController);
mList.setAdapter(mAdapter);
return view;
}
@Override
@@ -110,20 +88,29 @@ public class AlarmsFragment extends Fragment implements LoaderCallbacks<Cursor>,
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
public Loader<AlarmCursor> onCreateLoader(int id, Bundle args) {
return new AlarmsListCursorLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
public void onLoadFinished(Loader<AlarmCursor> loader, AlarmCursor data) {
super.onLoadFinished(loader, data);
// Scroll to the last modified alarm
performScrollToStableId();
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
public void onFabClick() {
Intent intent = new Intent(getActivity(), EditAlarmActivity.class);
startActivityForResult(intent, REQUEST_CREATE_ALARM);
}
@Override
protected AlarmsCursorAdapter getAdapter() {
if (mAdapter == null) {
mAdapter = new AlarmsCursorAdapter(this, mAlarmController);
}
return mAdapter;
}
@Override