diff --git a/app/src/main/java/com/philliphsu/clock2/OnListItemInteractionListener.java b/app/src/main/java/com/philliphsu/clock2/OnListItemInteractionListener.java index 098f27f..144a10f 100644 --- a/app/src/main/java/com/philliphsu/clock2/OnListItemInteractionListener.java +++ b/app/src/main/java/com/philliphsu/clock2/OnListItemInteractionListener.java @@ -14,4 +14,5 @@ package com.philliphsu.clock2; public interface OnListItemInteractionListener { void onListItemClick(T item, int position); void onListItemDeleted(T item); + void onListItemUpdate(T item, int position); } diff --git a/app/src/main/java/com/philliphsu/clock2/RecyclerViewFragment.java b/app/src/main/java/com/philliphsu/clock2/RecyclerViewFragment.java index b27e234..c3096b1 100644 --- a/app/src/main/java/com/philliphsu/clock2/RecyclerViewFragment.java +++ b/app/src/main/java/com/philliphsu/clock2/RecyclerViewFragment.java @@ -84,7 +84,6 @@ public abstract class RecyclerViewFragment< */ @Override protected int contentLayout() { - // TODO: Rename to fragment_recycler_view - return R.layout.fragment_alarms; + return R.layout.fragment_recycler_view; } } diff --git a/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java index c089676..259424d 100644 --- a/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java +++ b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java @@ -26,13 +26,15 @@ public class AlarmsFragment extends RecyclerViewFragment< Alarm, BaseAlarmViewHolder, AlarmCursor, - AlarmsCursorAdapter> implements ScrollHandler { + AlarmsCursorAdapter> implements ScrollHandler { // TODO: Move interface to base class private static final String TAG = "AlarmsFragment"; private static final int REQUEST_EDIT_ALARM = 0; // 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; // private AlarmsCursorAdapter mAdapter; + // TODO: Since we only use this in onActivityResult(), we also don't need this anymore. private AsyncItemChangeHandler mAsyncItemChangeHandler; private AlarmController mAlarmController; private Handler mHandler = new Handler(); @@ -91,6 +93,7 @@ public class AlarmsFragment extends RecyclerViewFragment< super.onLoadFinished(loader, data); // This may have been a requery due to content change. If the change // was an insertion, scroll to the last modified alarm. + // TODO: If the change was an update, this presents a problem. performScrollToStableId(); } @@ -109,6 +112,8 @@ public class AlarmsFragment extends RecyclerViewFragment< 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 public void onActivityResult(int requestCode, int resultCode, Intent data) { 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 public void setScrollToStableId(long id) { mScrollToStableId = id; @@ -181,21 +206,20 @@ public class AlarmsFragment extends RecyclerViewFragment< } if (position >= 0) { scrollToPosition(position); - // We were called because of a requery due to an insertion. - getAdapter().expand(position); + // We were called because of a requery. If it was due to an insertion, + // 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 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 { // TODO: Will holding onto this cause a memory leak? private final AsyncItemChangeHandler mAsyncItemChangeHandler; diff --git a/app/src/main/java/com/philliphsu/clock2/alarms/CollapsedAlarmViewHolder.java b/app/src/main/java/com/philliphsu/clock2/alarms/CollapsedAlarmViewHolder.java index d78465b..9ac0382 100644 --- a/app/src/main/java/com/philliphsu/clock2/alarms/CollapsedAlarmViewHolder.java +++ b/app/src/main/java/com/philliphsu/clock2/alarms/CollapsedAlarmViewHolder.java @@ -38,6 +38,7 @@ public class CollapsedAlarmViewHolder extends BaseAlarmViewHolder implements Ala @Override public void onBind(Alarm alarm) { super.onBind(alarm); + // TOneverDO: do custom binding before super call, or else NPEs. bindCountdown(alarm.isEnabled(), alarm.ringsIn()); bindDays(alarm); } @@ -62,7 +63,14 @@ public class CollapsedAlarmViewHolder extends BaseAlarmViewHolder implements Ala protected void bindLabel(boolean visible, String label) { // 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. - 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) { diff --git a/app/src/main/java/com/philliphsu/clock2/alarms/ExpandedAlarmViewHolder.java b/app/src/main/java/com/philliphsu/clock2/alarms/ExpandedAlarmViewHolder.java index b99d2a7..f8303d2 100644 --- a/app/src/main/java/com/philliphsu/clock2/alarms/ExpandedAlarmViewHolder.java +++ b/app/src/main/java/com/philliphsu/clock2/alarms/ExpandedAlarmViewHolder.java @@ -2,6 +2,7 @@ package com.philliphsu.clock2.alarms; import android.media.RingtoneManager; import android.net.Uri; +import android.view.View; import android.view.ViewGroup; import android.widget.Button; 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}) ToggleButton[] mDays; - public ExpandedAlarmViewHolder(ViewGroup parent, OnListItemInteractionListener listener, + public ExpandedAlarmViewHolder(ViewGroup parent, final OnListItemInteractionListener listener, AlarmController 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 @@ -52,10 +67,10 @@ public class ExpandedAlarmViewHolder extends BaseAlarmViewHolder { // TODO } - @OnClick(R.id.delete) - void delete() { - // TODO - } +// @OnClick(R.id.delete) +// void delete() { +// // TODO +// } @OnClick(R.id.ringtone) void showRingtonePickerDialog() { diff --git a/app/src/main/java/com/philliphsu/clock2/timers/TimersFragment.java b/app/src/main/java/com/philliphsu/clock2/timers/TimersFragment.java index 9d4342c..83890d9 100644 --- a/app/src/main/java/com/philliphsu/clock2/timers/TimersFragment.java +++ b/app/src/main/java/com/philliphsu/clock2/timers/TimersFragment.java @@ -54,4 +54,9 @@ public class TimersFragment extends RecyclerViewFragment< public void onListItemDeleted(Timer item) { } + + @Override + public void onListItemUpdate(Timer item, int position) { + + } } diff --git a/app/src/main/res/layout/fragment_alarms.xml b/app/src/main/res/layout/fragment_recycler_view.xml similarity index 100% rename from app/src/main/res/layout/fragment_alarms.xml rename to app/src/main/res/layout/fragment_recycler_view.xml diff --git a/app/src/main/res/layout/item_expanded_alarm.xml b/app/src/main/res/layout/item_expanded_alarm.xml index 8cb44bc..8fa3d3b 100644 --- a/app/src/main/res/layout/item_expanded_alarm.xml +++ b/app/src/main/res/layout/item_expanded_alarm.xml @@ -9,13 +9,17 @@ --> + app:cardCornerRadius="0dp" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp">