Update and delete alarms now async
This commit is contained in:
parent
4d2ef227b6
commit
3a86aaf3ba
@ -49,16 +49,28 @@ public final class AsyncItemChangeHandler {
|
||||
}.execute();
|
||||
}
|
||||
|
||||
public void asyncUpdateAlarm(final Alarm oldAlarm, final Alarm newAlarm) {
|
||||
/**
|
||||
* We only need one Alarm param because we called newAlarm.setId(oldAlarm.id())
|
||||
* when we were in the edit activity.
|
||||
* TODO: Consider changing the signature of updateAlarm() in DatabaseManager and
|
||||
* AlarmDatabaseHelper to only require one Alarm param.
|
||||
*/
|
||||
public void asyncUpdateAlarm(final Alarm newAlarm) {
|
||||
new AsyncTask<Void, Void, Integer>() {
|
||||
@Override
|
||||
protected Integer doInBackground(Void... params) {
|
||||
return DatabaseManager.getInstance(mContext).updateAlarm(oldAlarm.id(), newAlarm);
|
||||
return DatabaseManager.getInstance(mContext).updateAlarm(newAlarm.id(), newAlarm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer integer) {
|
||||
// TODO: Snackbar/Toast here? If so, remove the code in AlarmUtils.scheduleAlarm() that does it.
|
||||
AlarmUtils.scheduleAlarm(mContext, newAlarm, true);
|
||||
// The new alarm could have a different sort order from the old alarm.
|
||||
// TODO: Sometimes this won't scrolls to the new alarm if the old alarm is
|
||||
// towards the bottom and the new alarm is ordered towards the top. This
|
||||
// may have something to do with us breaking the stable id guarantee?
|
||||
mScrollHandler.setScrollToStableId(newAlarm.id());
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
@ -23,8 +22,6 @@ import com.philliphsu.clock2.OnListItemInteractionListener;
|
||||
import com.philliphsu.clock2.R;
|
||||
import com.philliphsu.clock2.editalarm.EditAlarmActivity;
|
||||
import com.philliphsu.clock2.model.AlarmsListCursorLoader;
|
||||
import com.philliphsu.clock2.model.DatabaseManager;
|
||||
import com.philliphsu.clock2.util.AlarmUtils;
|
||||
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
@ -39,6 +36,7 @@ public class AlarmsFragment extends Fragment implements LoaderCallbacks<Cursor>,
|
||||
|
||||
private AlarmsCursorAdapter mAdapter;
|
||||
private AsyncItemChangeHandler mAsyncItemChangeHandler;
|
||||
private Handler mHandler = new Handler();
|
||||
private long mScrollToStableId = RecyclerView.NO_ID;
|
||||
|
||||
@Bind(R.id.list) RecyclerView mList;
|
||||
@ -67,7 +65,6 @@ public class AlarmsFragment extends Fragment implements LoaderCallbacks<Cursor>,
|
||||
// TODO Read arguments
|
||||
}
|
||||
|
||||
// Initialize the loader to load the list of runs
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
|
||||
@ -125,32 +122,36 @@ public class AlarmsFragment extends Fragment implements LoaderCallbacks<Cursor>,
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
Log.d(TAG, "onActivityResult()");
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
if (resultCode != Activity.RESULT_OK || data == null)
|
||||
return;
|
||||
final Alarm alarm = data.getParcelableExtra(EditAlarmActivity.EXTRA_MODIFIED_ALARM);
|
||||
if (alarm == null)
|
||||
return;
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/a/27055512/5055032
|
||||
// "RecyclerView does not run animations in the first layout
|
||||
// pass after being attached." A workaround is to postpone
|
||||
// the CRUD operation to the next frame. A delay of 300ms is
|
||||
// short enough to not be noticeable, and long enough to
|
||||
// give us the animation *most of the time*.
|
||||
switch (requestCode) {
|
||||
case REQUEST_CREATE_ALARM:
|
||||
if (data != null) {
|
||||
final Alarm createdAlarm = data.getParcelableExtra(EditAlarmActivity.EXTRA_MODIFIED_ALARM);
|
||||
if (createdAlarm != null) {
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAsyncItemChangeHandler.asyncAddAlarm(createdAlarm);
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
mHandler.postDelayed(
|
||||
new AsyncAddItemRunnable(mAsyncItemChangeHandler, alarm),
|
||||
300);
|
||||
break;
|
||||
case REQUEST_EDIT_ALARM:
|
||||
Alarm deletedAlarm;
|
||||
if (data != null && (deletedAlarm = data.getParcelableExtra(
|
||||
EditAlarmActivity.EXTRA_MODIFIED_ALARM)) != null) {
|
||||
onListItemDeleted(deletedAlarm);
|
||||
if (data.getBooleanExtra(EditAlarmActivity.EXTRA_IS_DELETING, false)) {
|
||||
// TODO: Should we delay this too? It seems animations run
|
||||
// some of the time.
|
||||
mAsyncItemChangeHandler.asyncRemoveAlarm(alarm);
|
||||
} else {
|
||||
// TODO: Increase the delay, because update animation is
|
||||
// more elusive than insert.
|
||||
mHandler.postDelayed(
|
||||
new AsyncUpdateItemRunnable(mAsyncItemChangeHandler, alarm),
|
||||
300);
|
||||
}
|
||||
// TODO: notifyItemRemoved?
|
||||
getLoaderManager().restartLoader(0, null, this);
|
||||
break;
|
||||
default:
|
||||
Log.i(TAG, "Could not handle request code " + requestCode);
|
||||
@ -192,25 +193,67 @@ public class AlarmsFragment extends Fragment implements LoaderCallbacks<Cursor>,
|
||||
mScrollToStableId = RecyclerView.NO_ID;
|
||||
}
|
||||
|
||||
// TODO: This doesn't need to be defined in the interface.
|
||||
// TODO: Rename to showDeletedSnackbar() or something
|
||||
// TODO: This needs to prompt a reload of the list.
|
||||
@Deprecated // TODO: Delete this method.
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void onListItemDeleted(final Alarm item) {
|
||||
Snackbar.make(getActivity().findViewById(R.id.main_content),
|
||||
getString(R.string.snackbar_item_deleted, "Alarm"),
|
||||
Snackbar.LENGTH_LONG) // TODO: not long enough?
|
||||
.setAction(R.string.snackbar_undo_item_deleted, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
DatabaseManager.getInstance(getActivity()).insertAlarm(item);
|
||||
getLoaderManager().restartLoader(0, null, AlarmsFragment.this);
|
||||
if (item.isEnabled()) {
|
||||
AlarmUtils.scheduleAlarm(getActivity(), item, true);
|
||||
}
|
||||
}
|
||||
})
|
||||
.show();
|
||||
// TODO: This doesn't need to be defined in the interface.
|
||||
// TODO: Delete this method.
|
||||
}
|
||||
|
||||
private static abstract class BaseAsyncItemChangeRunnable {
|
||||
// TODO: Will holding onto this cause a memory leak?
|
||||
private final AsyncItemChangeHandler mAsyncItemChangeHandler;
|
||||
private final Alarm mAlarm;
|
||||
|
||||
BaseAsyncItemChangeRunnable(AsyncItemChangeHandler asyncItemChangeHandler, Alarm alarm) {
|
||||
mAsyncItemChangeHandler = asyncItemChangeHandler;
|
||||
mAlarm = alarm;
|
||||
}
|
||||
|
||||
void asyncAddAlarm() {
|
||||
mAsyncItemChangeHandler.asyncAddAlarm(mAlarm);
|
||||
}
|
||||
|
||||
void asyncUpdateAlarm() {
|
||||
mAsyncItemChangeHandler.asyncUpdateAlarm(mAlarm);
|
||||
}
|
||||
|
||||
void asyncRemoveAlarm() {
|
||||
mAsyncItemChangeHandler.asyncRemoveAlarm(mAlarm);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AsyncAddItemRunnable extends BaseAsyncItemChangeRunnable implements Runnable {
|
||||
AsyncAddItemRunnable(AsyncItemChangeHandler asyncItemChangeHandler, Alarm alarm) {
|
||||
super(asyncItemChangeHandler, alarm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
asyncAddAlarm();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AsyncUpdateItemRunnable extends BaseAsyncItemChangeRunnable implements Runnable {
|
||||
AsyncUpdateItemRunnable(AsyncItemChangeHandler asyncItemChangeHandler, Alarm alarm) {
|
||||
super(asyncItemChangeHandler, alarm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
asyncUpdateAlarm();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AsyncRemoveItemRunnable extends BaseAsyncItemChangeRunnable implements Runnable {
|
||||
AsyncRemoveItemRunnable(AsyncItemChangeHandler asyncItemChangeHandler, Alarm alarm) {
|
||||
super(asyncItemChangeHandler, alarm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
asyncRemoveAlarm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +59,7 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi
|
||||
private static final String TAG = "EditAlarmActivity";
|
||||
public static final String EXTRA_ALARM_ID = "com.philliphsu.clock2.editalarm.extra.ALARM_ID";
|
||||
public static final String EXTRA_MODIFIED_ALARM = "com.philliphsu.clock2.editalarm.extra.MODIFIED_ALARM";
|
||||
public static final String EXTRA_IS_DELETING = "com.philliphsu.clock2.editalarm.extra.IS_DELETING";
|
||||
private static final RelativeSizeSpan AMPM_SIZE_SPAN = new RelativeSizeSpan(0.5f);
|
||||
|
||||
private static final int REQUEST_PICK_RINGTONE = 0;
|
||||
@ -211,12 +212,12 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi
|
||||
showRingtonePickerDialog();
|
||||
}
|
||||
|
||||
// TODO: Privatize accessor methods
|
||||
@OnClick(R.id.save)
|
||||
void save() {
|
||||
int hour;
|
||||
int minutes;
|
||||
try {
|
||||
// TODO: Privatize accessor methods
|
||||
hour = getHour();
|
||||
minutes = getMinutes();
|
||||
} catch (IllegalStateException e) {
|
||||
@ -242,16 +243,15 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi
|
||||
Log.d(TAG, "Cancelling old alarm first");
|
||||
cancelAlarm(mOldAlarm, false);
|
||||
}
|
||||
// TODO: Do this in the background. AsyncTask?
|
||||
mDatabaseManager.updateAlarm(mOldAlarm.id(), alarm);
|
||||
} else {
|
||||
//mDatabaseManager.insertAlarm(alarm);
|
||||
intent.putExtra(EXTRA_MODIFIED_ALARM, alarm);
|
||||
alarm.setId(mOldAlarm.id());
|
||||
intent.putExtra(EXTRA_IS_DELETING, false);
|
||||
}
|
||||
intent.putExtra(EXTRA_MODIFIED_ALARM, alarm);
|
||||
|
||||
if (alarm.isEnabled()) {
|
||||
//scheduleAlarm(alarm);
|
||||
}
|
||||
// The reason we don't schedule the alarm here is AlarmUtils
|
||||
// will attempt to retrieve the specified alarm
|
||||
// from the database; however, the alarm hasn't yet
|
||||
// been added to the database at this point.
|
||||
|
||||
setResult(RESULT_OK, intent);
|
||||
showEditorClosed();
|
||||
@ -269,6 +269,7 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi
|
||||
}
|
||||
mDatabaseManager.deleteAlarm(mOldAlarm);
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_IS_DELETING, true);
|
||||
intent.putExtra(EXTRA_MODIFIED_ALARM, mOldAlarm);
|
||||
setResult(RESULT_OK, intent);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user