New update and delete callbacks for OnListItemInteractionListener

This commit is contained in:
Phillip Hsu 2016-08-01 01:18:44 -07:00
parent 9561388425
commit 5ac5b34640
8 changed files with 76 additions and 20 deletions

View File

@ -14,4 +14,5 @@ package com.philliphsu.clock2;
public interface OnListItemInteractionListener<T> { public interface OnListItemInteractionListener<T> {
void onListItemClick(T item, int position); void onListItemClick(T item, int position);
void onListItemDeleted(T item); void onListItemDeleted(T item);
void onListItemUpdate(T item, int position);
} }

View File

@ -84,7 +84,6 @@ public abstract class RecyclerViewFragment<
*/ */
@Override @Override
protected int contentLayout() { protected int contentLayout() {
// TODO: Rename to fragment_recycler_view return R.layout.fragment_recycler_view;
return R.layout.fragment_alarms;
} }
} }

View File

@ -26,13 +26,15 @@ public class AlarmsFragment extends RecyclerViewFragment<
Alarm, Alarm,
BaseAlarmViewHolder, BaseAlarmViewHolder,
AlarmCursor, AlarmCursor,
AlarmsCursorAdapter> implements ScrollHandler { AlarmsCursorAdapter> implements ScrollHandler { // TODO: Move interface to base class
private static final String TAG = "AlarmsFragment"; private static final String TAG = "AlarmsFragment";
private static final int REQUEST_EDIT_ALARM = 0; private static final int REQUEST_EDIT_ALARM = 0;
// Public because MainActivity needs to use it. // Public because MainActivity needs to use it.
// TODO: private because we handle fab clicks in the fragment now
public static final int REQUEST_CREATE_ALARM = 1; public static final int REQUEST_CREATE_ALARM = 1;
// private AlarmsCursorAdapter mAdapter; // private AlarmsCursorAdapter mAdapter;
// TODO: Since we only use this in onActivityResult(), we also don't need this anymore.
private AsyncItemChangeHandler mAsyncItemChangeHandler; private AsyncItemChangeHandler mAsyncItemChangeHandler;
private AlarmController mAlarmController; private AlarmController mAlarmController;
private Handler mHandler = new Handler(); private Handler mHandler = new Handler();
@ -91,6 +93,7 @@ public class AlarmsFragment extends RecyclerViewFragment<
super.onLoadFinished(loader, data); super.onLoadFinished(loader, data);
// This may have been a requery due to content change. If the change // This may have been a requery due to content change. If the change
// was an insertion, scroll to the last modified alarm. // was an insertion, scroll to the last modified alarm.
// TODO: If the change was an update, this presents a problem.
performScrollToStableId(); performScrollToStableId();
} }
@ -109,6 +112,8 @@ public class AlarmsFragment extends RecyclerViewFragment<
return new AlarmsCursorAdapter(this, mAlarmController); return new AlarmsCursorAdapter(this, mAlarmController);
} }
// TODO: We're not using EditAlarmActivity anymore, so move this logic somewhere else.
// We also don't need to delay the change to get animations working.
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult()"); Log.d(TAG, "onActivityResult()");
@ -160,6 +165,26 @@ public class AlarmsFragment extends RecyclerViewFragment<
} }
} }
@Override
// TODO: Rename to onListItem***Delete*** because the item hasn't been deleted from our db yet
public void onListItemDeleted(final Alarm item) {
// The corresponding VH will be automatically removed from view following
// the requery, so we don't have to do anything to it.
mAsyncItemChangeHandler.asyncDelete(item);
}
@Override
public void onListItemUpdate(Alarm item, int position) {
// Once we update the relevant row in the db table, the VH will still
// be in view. While the requery will probably update the values displayed
// by the VH, the VH remains in its expanded state from before we were
// called. Tell the adapter reset its expanded position.
// TODO: Implement editing in the expanded VH. Then verify that changes
// while in that VH are saved and updated after the requery.
// getAdapter().collapse(position);
mAsyncItemChangeHandler.asyncUpdate(item.getId(), item);
}
@Override @Override
public void setScrollToStableId(long id) { public void setScrollToStableId(long id) {
mScrollToStableId = id; mScrollToStableId = id;
@ -181,21 +206,20 @@ public class AlarmsFragment extends RecyclerViewFragment<
} }
if (position >= 0) { if (position >= 0) {
scrollToPosition(position); scrollToPosition(position);
// We were called because of a requery due to an insertion. // We were called because of a requery. If it was due to an insertion,
getAdapter().expand(position); // expand the newly added alarm.
boolean expanded = getAdapter().expand(position);
if (!expanded) {
// Otherwise, it was due to an item update. The VH is expanded
// at this point, so reset it.
getAdapter().collapse(position);
}
} }
} }
// Reset // Reset
mScrollToStableId = RecyclerView.NO_ID; mScrollToStableId = RecyclerView.NO_ID;
} }
@Deprecated
@Override
public void onListItemDeleted(final Alarm item) {
// TODO: This doesn't need to be defined in the interface.
// TODO: Delete this method.
}
private static abstract class BaseAsyncItemChangeRunnable { private static abstract class BaseAsyncItemChangeRunnable {
// TODO: Will holding onto this cause a memory leak? // TODO: Will holding onto this cause a memory leak?
private final AsyncItemChangeHandler mAsyncItemChangeHandler; private final AsyncItemChangeHandler mAsyncItemChangeHandler;

View File

@ -38,6 +38,7 @@ public class CollapsedAlarmViewHolder extends BaseAlarmViewHolder implements Ala
@Override @Override
public void onBind(Alarm alarm) { public void onBind(Alarm alarm) {
super.onBind(alarm); super.onBind(alarm);
// TOneverDO: do custom binding before super call, or else NPEs.
bindCountdown(alarm.isEnabled(), alarm.ringsIn()); bindCountdown(alarm.isEnabled(), alarm.ringsIn());
bindDays(alarm); bindDays(alarm);
} }
@ -62,7 +63,14 @@ public class CollapsedAlarmViewHolder extends BaseAlarmViewHolder implements Ala
protected void bindLabel(boolean visible, String label) { protected void bindLabel(boolean visible, String label) {
// Should also be visible even if label has zero length so mCountdown is properly positioned // Should also be visible even if label has zero length so mCountdown is properly positioned
// next to mLabel. That is, mCountdown's layout position is dependent on mLabel being present. // next to mLabel. That is, mCountdown's layout position is dependent on mLabel being present.
super.bindLabel(visible || mCountdown.getVisibility() == VISIBLE, label);
// The countdown is visible if the alarm is enabled. We must keep this invariant in sync
// with our bindCountdown() logic. If we test against the
// visibility of the countdown view itself, we will find it is always visible
// at this point, because bindCountdown() has not been called yet. As such, that is
// not a valid solution. We unfortunately
// cannot change the order of the view binding done in onBind().
super.bindLabel(visible || getAlarm().isEnabled(), label);
} }
private void bindDays(Alarm alarm) { private void bindDays(Alarm alarm) {

View File

@ -2,6 +2,7 @@ package com.philliphsu.clock2.alarms;
import android.media.RingtoneManager; import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
@ -29,9 +30,23 @@ public class ExpandedAlarmViewHolder extends BaseAlarmViewHolder {
@Bind({R.id.day0, R.id.day1, R.id.day2, R.id.day3, R.id.day4, R.id.day5, R.id.day6}) @Bind({R.id.day0, R.id.day1, R.id.day2, R.id.day3, R.id.day4, R.id.day5, R.id.day6})
ToggleButton[] mDays; ToggleButton[] mDays;
public ExpandedAlarmViewHolder(ViewGroup parent, OnListItemInteractionListener<Alarm> listener, public ExpandedAlarmViewHolder(ViewGroup parent, final OnListItemInteractionListener<Alarm> listener,
AlarmController controller) { AlarmController controller) {
super(parent, R.layout.item_expanded_alarm, listener, controller); super(parent, R.layout.item_expanded_alarm, listener, controller);
// Manually bind listeners, or else you'd need to write a getter for the
// OnListItemInteractionListener in the BaseViewHolder for use in method binding.
mDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onListItemDeleted(getAlarm());
}
});
mSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onListItemUpdate(getAlarm(), getAdapterPosition());
}
});
} }
@Override @Override
@ -52,10 +67,10 @@ public class ExpandedAlarmViewHolder extends BaseAlarmViewHolder {
// TODO // TODO
} }
@OnClick(R.id.delete) // @OnClick(R.id.delete)
void delete() { // void delete() {
// TODO // // TODO
} // }
@OnClick(R.id.ringtone) @OnClick(R.id.ringtone)
void showRingtonePickerDialog() { void showRingtonePickerDialog() {

View File

@ -54,4 +54,9 @@ public class TimersFragment extends RecyclerViewFragment<
public void onListItemDeleted(Timer item) { public void onListItemDeleted(Timer item) {
} }
@Override
public void onListItemUpdate(Timer item, int position) {
}
} }

View File

@ -9,13 +9,17 @@
--> -->
<!-- TODO: Write a layout for v21 that instead uses the elevation attribute normally. <!-- TODO: Write a layout for v21 that instead uses the elevation attribute normally.
- You may have to set a non-transparent background on the main view. - You may have to set a non-transparent background on the main view.
- Alternatively, just keep the CardView because that takes care of the non-transparent
- background issue for free.
--> -->
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardElevation="2dp" app:cardElevation="2dp"
app:cardCornerRadius="0dp"> app:cardCornerRadius="0dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"