From 17ad81d55e0544b5d2f993fa59bacf629fa1fc9e Mon Sep 17 00:00:00 2001 From: Phillip Hsu Date: Wed, 7 Sep 2016 02:20:11 -0700 Subject: [PATCH] Create DialogFragmentController to manage showing and restoring dialogs --- .../clock2/AddLabelDialogController.java | 18 ++- .../clock2/DialogFragmentController.java | 44 ++++++++ .../clock2/TimePickerDialogController.java | 64 +++++++++++ .../clock2/alarms/AlarmsFragment.java | 33 +++--- .../clock2/alarms/BaseAlarmViewHolder.java | 103 ++++++++---------- .../clock2/editalarm/TimePickerHelper.java | 42 ------- .../clock2/edittimer/EditTimerActivity.java | 10 +- .../clock2/timers/TimerViewHolder.java | 11 +- .../clock2/util/FragmentTagUtils.java | 25 +++++ 9 files changed, 219 insertions(+), 131 deletions(-) create mode 100644 app/src/main/java/com/philliphsu/clock2/DialogFragmentController.java create mode 100644 app/src/main/java/com/philliphsu/clock2/TimePickerDialogController.java delete mode 100644 app/src/main/java/com/philliphsu/clock2/editalarm/TimePickerHelper.java create mode 100644 app/src/main/java/com/philliphsu/clock2/util/FragmentTagUtils.java diff --git a/app/src/main/java/com/philliphsu/clock2/AddLabelDialogController.java b/app/src/main/java/com/philliphsu/clock2/AddLabelDialogController.java index 50ea7ad..a29fd58 100644 --- a/app/src/main/java/com/philliphsu/clock2/AddLabelDialogController.java +++ b/app/src/main/java/com/philliphsu/clock2/AddLabelDialogController.java @@ -6,26 +6,24 @@ import android.util.Log; /** * Created by Phillip Hsu on 9/6/2016. */ -public final class AddLabelDialogController { - private static final String TAG = "add_label_dialog"; +public final class AddLabelDialogController extends DialogFragmentController { + private static final String TAG = "AddLabelController"; - private final FragmentManager mFragmentManager; private final AddLabelDialog.OnLabelSetListener mListener; public AddLabelDialogController(FragmentManager fragmentManager, AddLabelDialog.OnLabelSetListener listener) { - mFragmentManager = fragmentManager; + super(fragmentManager); mListener = listener; } - public void show(CharSequence initialText) { + public void show(CharSequence initialText, String tag) { AddLabelDialog dialog = AddLabelDialog.newInstance(mListener, initialText); - dialog.show(mFragmentManager, TAG); -// show(dialog, TAG); + show(dialog, tag); } - // TODO: Rename to onConfigurationChange()? - public void tryRestoreCallback() { - AddLabelDialog labelDialog = (AddLabelDialog) mFragmentManager.findFragmentByTag(TAG); + @Override + public void tryRestoreCallback(String tag) { + AddLabelDialog labelDialog = findDialog(tag); if (labelDialog != null) { Log.i(TAG, "Restoring add label callback"); labelDialog.setOnLabelSetListener(mListener); diff --git a/app/src/main/java/com/philliphsu/clock2/DialogFragmentController.java b/app/src/main/java/com/philliphsu/clock2/DialogFragmentController.java new file mode 100644 index 0000000..5ac111a --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/DialogFragmentController.java @@ -0,0 +1,44 @@ +package com.philliphsu.clock2; + +import android.support.annotation.Nullable; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentManager; +import android.util.Log; + +/** + * Created by Phillip Hsu on 9/6/2016. + */ +public abstract class DialogFragmentController { + private static final String TAG = "DialogController"; + + private final FragmentManager mFragmentManager; + + // TODO: Rename to onConfigurationChange()? + public abstract void tryRestoreCallback(String tag); + + public DialogFragmentController(FragmentManager fragmentManager) { + mFragmentManager = fragmentManager; + } + + /** + * Shows the dialog with the given tag. + */ + protected final void show(T dialog, String tag) { + Log.d(TAG, "Showing dialog " + dialog + "with tag " + tag); + dialog.show(mFragmentManager, tag); + } + + /** + * Tries to find the dialog in our {@code FragmentManager} with the provided tag. + */ + @Nullable + @SuppressWarnings("unchecked") + protected final T findDialog(String tag) { + // https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#cannotCast + // Typically, we can't cast to a generic type. However, I've written non-generic code that + // blindly casts the result to an arbitrary type that I expect is correct, so this is + // pretty much the same thing. + Log.d(TAG, "Finding dialog with tag " + tag); + return (T) mFragmentManager.findFragmentByTag(tag); + } +} diff --git a/app/src/main/java/com/philliphsu/clock2/TimePickerDialogController.java b/app/src/main/java/com/philliphsu/clock2/TimePickerDialogController.java new file mode 100644 index 0000000..283dc79 --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/TimePickerDialogController.java @@ -0,0 +1,64 @@ +package com.philliphsu.clock2; + +import android.content.Context; +import android.preference.PreferenceManager; +import android.support.v4.app.FragmentManager; +import android.text.format.DateFormat; +import android.util.Log; + +import com.philliphsu.clock2.editalarm.BaseTimePickerDialog; +import com.philliphsu.clock2.editalarm.NumberGridTimePickerDialog; +import com.philliphsu.clock2.editalarm.NumpadTimePickerDialog; + +/** + * Created by Phillip Hsu on 9/6/2016. + */ +public final class TimePickerDialogController extends DialogFragmentController { + private static final String TAG = "TimePickerController"; + + private final BaseTimePickerDialog.OnTimeSetListener mListener; + private final Context mContext; + + /** + * @param context Used to read the user's preference for the style of the time picker dialog to show. + */ + public TimePickerDialogController(FragmentManager fragmentManager, Context context, + BaseTimePickerDialog.OnTimeSetListener listener) { + super(fragmentManager); + mContext = context; + mListener = listener; + } + + public void show(int initialHourOfDay, int initialMinute, String tag) { + BaseTimePickerDialog dialog = null; + String numpadStyle = mContext.getString(R.string.number_pad); + String gridStyle = mContext.getString(R.string.grid_selector); + String prefTimePickerStyle = PreferenceManager.getDefaultSharedPreferences(mContext).getString( + // key for the preference value to retrieve + mContext.getString(R.string.key_time_picker_style), + // default value + numpadStyle); + if (prefTimePickerStyle.equals(numpadStyle)) { + dialog = NumpadTimePickerDialog.newInstance(mListener); + } else if (prefTimePickerStyle.equals(gridStyle)) { + dialog = NumberGridTimePickerDialog.newInstance( + mListener, + initialHourOfDay, + initialMinute, + DateFormat.is24HourFormat(mContext)); + } + // We don't have a default case, because we don't need one; prefTimePickerStyle + // will ALWAYS match one of numpadStyle or gridStyle. As such, the dialog + // will NEVER be null. + show(dialog, tag); + } + + @Override + public void tryRestoreCallback(String tag) { + BaseTimePickerDialog picker = findDialog(tag); + if (picker != null) { + Log.i(TAG, "Restoring time picker callback: " + mListener); + picker.setOnTimeSetListener(mListener); + } + } +} 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 6983134..3f1c357 100644 --- a/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java +++ b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java @@ -16,13 +16,15 @@ import com.philliphsu.clock2.Alarm; import com.philliphsu.clock2.AsyncAlarmsTableUpdateHandler; import com.philliphsu.clock2.R; import com.philliphsu.clock2.RecyclerViewFragment; +import com.philliphsu.clock2.TimePickerDialogController; import com.philliphsu.clock2.editalarm.BaseTimePickerDialog; -import com.philliphsu.clock2.editalarm.TimePickerHelper; import com.philliphsu.clock2.model.AlarmCursor; import com.philliphsu.clock2.model.AlarmsListCursorLoader; import com.philliphsu.clock2.util.AlarmController; import com.philliphsu.clock2.util.DelayedSnackbarHandler; +import static com.philliphsu.clock2.util.FragmentTagUtils.makeTag; + public class AlarmsFragment extends RecyclerViewFragment< Alarm, BaseAlarmViewHolder, @@ -32,8 +34,6 @@ public class AlarmsFragment extends RecyclerViewFragment< BaseTimePickerDialog.OnTimeSetListener { private static final String TAG = "AlarmsFragment"; - static final String TAG_TIME_PICKER = "time_picker"; - private static final String KEY_EXPANDED_POSITION = "expanded_position"; // TODO: Delete these constants. We no longer use EditAlarmActivity. @@ -44,13 +44,15 @@ public class AlarmsFragment extends RecyclerViewFragment< // @Deprecated // public static final int REQUEST_CREATE_ALARM = 1; + // TODO: Delete this. We no longer use the system's ringtone picker. public static final int REQUEST_PICK_RINGTONE = 1; -// private AlarmsCursorAdapter mAdapter; private AsyncAlarmsTableUpdateHandler mAsyncUpdateHandler; private AlarmController mAlarmController; + // TODO: Delete this. If I recall correctly, this was just used for delaying item animations. private Handler mHandler = new Handler(); private View mSnackbarAnchor; + private TimePickerDialogController mTimePickerDialogController; private int mExpandedPosition = RecyclerView.NO_POSITION; @@ -91,6 +93,9 @@ public class AlarmsFragment extends RecyclerViewFragment< mAlarmController = new AlarmController(getActivity(), mSnackbarAnchor); mAsyncUpdateHandler = new AsyncAlarmsTableUpdateHandler(getActivity(), mSnackbarAnchor, this, mAlarmController); + mTimePickerDialogController = new TimePickerDialogController( + getFragmentManager(), getActivity(), this); + mTimePickerDialogController.tryRestoreCallback(makeTimePickerDialogTag()); } @Override @@ -120,21 +125,7 @@ public class AlarmsFragment extends RecyclerViewFragment< @Override public void onFabClick() { -// Intent intent = new Intent(getActivity(), EditAlarmActivity.class); -// startActivityForResult(intent, REQUEST_CREATE_ALARM); - - // Close the keyboard first, or else our dialog will be screwed up. - // If not open, this does nothing. - // TODO: I don't think the keyboard can possibly be open in this Fragment? -// hideKeyboard(this); // This is only important for BottomSheetDialogs! - - // Create a new instance each time we want to show the dialog. - // If we keep a reference to the dialog, we keep its previous state as well. - // So the next time we call show() on it, the input field will show the - // last inputted time. - BaseTimePickerDialog dialog = TimePickerHelper.newDialog(getActivity(), this, 0, 0); - // DISREGARD THE LINT WARNING ABOUT DIALOG BEING NULL. - dialog.show(getFragmentManager(), TAG_TIME_PICKER); + mTimePickerDialogController.show(0, 0, makeTimePickerDialogTag()); } @Override @@ -304,6 +295,10 @@ public class AlarmsFragment extends RecyclerViewFragment< } } + private static String makeTimePickerDialogTag() { + return makeTag(AlarmsFragment.class, R.id.fab); + } + ///////////////////////////////////////////////////////////////////////////////////// // TODO: We won't need these anymore, since we won't handle the db // update in onActivityResult() anymore. diff --git a/app/src/main/java/com/philliphsu/clock2/alarms/BaseAlarmViewHolder.java b/app/src/main/java/com/philliphsu/clock2/alarms/BaseAlarmViewHolder.java index 912e0e2..b4a0d60 100644 --- a/app/src/main/java/com/philliphsu/clock2/alarms/BaseAlarmViewHolder.java +++ b/app/src/main/java/com/philliphsu/clock2/alarms/BaseAlarmViewHolder.java @@ -2,6 +2,7 @@ package com.philliphsu.clock2.alarms; import android.content.res.ColorStateList; import android.graphics.drawable.Drawable; +import android.support.annotation.IdRes; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.v4.app.FragmentManager; @@ -9,7 +10,6 @@ import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SwitchCompat; import android.text.format.DateFormat; -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -22,13 +22,13 @@ import com.philliphsu.clock2.Alarm; import com.philliphsu.clock2.BaseViewHolder; import com.philliphsu.clock2.OnListItemInteractionListener; import com.philliphsu.clock2.R; +import com.philliphsu.clock2.TimePickerDialogController; import com.philliphsu.clock2.aospdatetimepicker.Utils; -import com.philliphsu.clock2.editalarm.BaseTimePickerDialog; import com.philliphsu.clock2.editalarm.BaseTimePickerDialog.OnTimeSetListener; -import com.philliphsu.clock2.editalarm.TimePickerHelper; import com.philliphsu.clock2.editalarm.TimeTextUtils; import com.philliphsu.clock2.util.AlarmController; import com.philliphsu.clock2.util.AlarmUtils; +import com.philliphsu.clock2.util.FragmentTagUtils; import java.util.Date; @@ -49,12 +49,14 @@ public abstract class BaseAlarmViewHolder extends BaseViewHolder { private final AlarmController mAlarmController; private final AddLabelDialogController mAddLabelDialogController; + private final TimePickerDialogController mTimePickerDialogController; // TODO: Should we use VectorDrawable type? private final Drawable mDismissNowDrawable; private final Drawable mCancelSnoozeDrawable; - // Exposed for use by subclasses (obviously in this package. + // TODO: THis is still here for ExpandedVH's RingtonePickerDialog. If we ever write a + // Controller for it, finally delete this. final FragmentManager mFragmentManager; @Bind(R.id.time) TextView mTime; @@ -76,30 +78,48 @@ public abstract class BaseAlarmViewHolder extends BaseViewHolder { // or simply pass in an instance of FragmentManager to the ctor. AppCompatActivity act = (AppCompatActivity) getContext(); mFragmentManager = act.getSupportFragmentManager(); - mAddLabelDialogController = new AddLabelDialogController( - mFragmentManager, - new AddLabelDialog.OnLabelSetListener() { - @Override - public void onLabelSet(String label) { - final Alarm oldAlarm = getAlarm(); - Alarm newAlarm = oldAlarm.toBuilder() - .label(label) - .build(); - oldAlarm.copyMutableFieldsTo(newAlarm); - persistUpdatedAlarm(newAlarm, false); - } - }); + mAddLabelDialogController = new AddLabelDialogController(mFragmentManager, + // TODO: Why can't we implement the interface and pass `this` instead? + new AddLabelDialog.OnLabelSetListener() { + @Override + public void onLabelSet(String label) { + final Alarm oldAlarm = getAlarm(); + Alarm newAlarm = oldAlarm.toBuilder() + .label(label) + .build(); + oldAlarm.copyMutableFieldsTo(newAlarm); + persistUpdatedAlarm(newAlarm, false); + } + } + ); + mTimePickerDialogController = new TimePickerDialogController(mFragmentManager, getContext(), + // TODO: Why can't we implement the interface and pass `this` instead? + new OnTimeSetListener() { + @Override + public void onTimeSet(ViewGroup viewGroup, int hourOfDay, int minute) { + final Alarm oldAlarm = getAlarm(); + // I don't think we need this; scheduling a new alarm that is considered + // equal to a previous alarm will overwrite the previous alarm. +// mAlarmController.cancelAlarm(oldAlarm, false); + Alarm newAlarm = oldAlarm.toBuilder() + .hour(hourOfDay) + .minutes(minute) + .build(); + oldAlarm.copyMutableFieldsTo(newAlarm); + // ------------------------------------------- + // TOneverDO: precede copyMutableFieldsTo() + newAlarm.setEnabled(true); // Always enabled, esp. if oldAlarm is not enabled + // ---------------------------------------------- + persistUpdatedAlarm(newAlarm, true); + } + } + ); // Are we recreating this because of a rotation? // If so, try finding any dialog that was last shown in our backstack, // and restore the callback. - BaseTimePickerDialog picker = (BaseTimePickerDialog) - mFragmentManager.findFragmentByTag(AlarmsFragment.TAG_TIME_PICKER); - if (picker != null) { - Log.i(TAG, "Restoring time picker callback"); - picker.setOnTimeSetListener(newOnTimeSetListener()); - } - mAddLabelDialogController.tryRestoreCallback(); + mAddLabelDialogController.tryRestoreCallback(makeTag(R.id.label)); + mTimePickerDialogController.tryRestoreCallback(makeTag(R.id.time)); } @Override @@ -204,14 +224,12 @@ public abstract class BaseAlarmViewHolder extends BaseViewHolder { @OnClick(R.id.time) void openTimePicker() { Alarm alarm = getAlarm(); - BaseTimePickerDialog dialog = TimePickerHelper.newDialog(getContext(), - newOnTimeSetListener(), alarm.hour(), alarm.minutes()); - dialog.show(mFragmentManager, AlarmsFragment.TAG_TIME_PICKER); + mTimePickerDialogController.show(alarm.hour(), alarm.minutes(), makeTag(R.id.time)); } @OnClick(R.id.label) void openLabelEditor() { - mAddLabelDialogController.show(mLabel.getText()); + mAddLabelDialogController.show(mLabel.getText(), makeTag(R.id.label)); } /** @@ -282,32 +300,7 @@ public abstract class BaseAlarmViewHolder extends BaseViewHolder { bindLabel(visible, label); } - private OnTimeSetListener newOnTimeSetListener() { - // Create a new listener per request. This is primarily used for - // setting the dialog callback again after a rotation. - // - // If we saved a reference to a listener, it would be tied to - // its ViewHolder instance. ViewHolders are reused, so we - // could accidentally leak this reference to other Alarm items - // in the list. - return new OnTimeSetListener() { - @Override - public void onTimeSet(ViewGroup viewGroup, int hourOfDay, int minute) { - final Alarm oldAlarm = getAlarm(); - // I don't think we need this; scheduling a new alarm that is considered - // equal to a previous alarm will overwrite the previous alarm. -// mAlarmController.cancelAlarm(oldAlarm, false); - Alarm newAlarm = oldAlarm.toBuilder() - .hour(hourOfDay) - .minutes(minute) - .build(); - oldAlarm.copyMutableFieldsTo(newAlarm); - // ------------------------------------------- - // TOneverDO: precede copyMutableFieldsTo() - newAlarm.setEnabled(true); // Always enabled, esp. if oldAlarm is not enabled - // ---------------------------------------------- - persistUpdatedAlarm(newAlarm, true); - } - }; + private String makeTag(@IdRes int viewId) { + return FragmentTagUtils.makeTag(BaseAlarmViewHolder.class, viewId, getItemId()); } } diff --git a/app/src/main/java/com/philliphsu/clock2/editalarm/TimePickerHelper.java b/app/src/main/java/com/philliphsu/clock2/editalarm/TimePickerHelper.java deleted file mode 100644 index 88a0241..0000000 --- a/app/src/main/java/com/philliphsu/clock2/editalarm/TimePickerHelper.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.philliphsu.clock2.editalarm; - -import android.content.Context; -import android.preference.PreferenceManager; -import android.text.format.DateFormat; - -import com.philliphsu.clock2.R; - -/** - * Created by Phillip Hsu on 9/2/2016. - * - * Helper for creating a time picker dialog. - */ -public final class TimePickerHelper { - - public static BaseTimePickerDialog newDialog(Context context, BaseTimePickerDialog.OnTimeSetListener l, - int initialHourOfDay, int initialMinute) { - BaseTimePickerDialog dialog = null; - String numpadStyle = context.getString(R.string.number_pad); - String gridStyle = context.getString(R.string.grid_selector); - String prefTimePickerStyle = PreferenceManager.getDefaultSharedPreferences(context).getString( - // key for the preference value to retrieve - context.getString(R.string.key_time_picker_style), - // default value - numpadStyle); - if (prefTimePickerStyle.equals(numpadStyle)) { - dialog = NumpadTimePickerDialog.newInstance(l); - } else if (prefTimePickerStyle.equals(gridStyle)) { - dialog = NumberGridTimePickerDialog.newInstance( - l, - initialHourOfDay, - initialMinute, - DateFormat.is24HourFormat(context)); - } - // We don't have a default case, because we don't need one; prefTimePickerStyle - // will ALWAYS match one of numpadStyle or gridStyle. As such, the dialog returned - // from here will NEVER be null. - return dialog; - } - - private TimePickerHelper() {} -} diff --git a/app/src/main/java/com/philliphsu/clock2/edittimer/EditTimerActivity.java b/app/src/main/java/com/philliphsu/clock2/edittimer/EditTimerActivity.java index 084af8c..51c6b24 100644 --- a/app/src/main/java/com/philliphsu/clock2/edittimer/EditTimerActivity.java +++ b/app/src/main/java/com/philliphsu/clock2/edittimer/EditTimerActivity.java @@ -2,6 +2,7 @@ package com.philliphsu.clock2.edittimer; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.IdRes; import android.support.design.widget.FloatingActionButton; import android.support.v7.widget.GridLayout; import android.text.InputType; @@ -15,6 +16,7 @@ import com.philliphsu.clock2.AddLabelDialog; import com.philliphsu.clock2.AddLabelDialogController; import com.philliphsu.clock2.BaseActivity; import com.philliphsu.clock2.R; +import com.philliphsu.clock2.util.FragmentTagUtils; import butterknife.Bind; import butterknife.OnClick; @@ -50,7 +52,7 @@ public class EditTimerActivity extends BaseActivity implements AddLabelDialog.On protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAddLabelDialogController = new AddLabelDialogController(getSupportFragmentManager(), this); - mAddLabelDialogController.tryRestoreCallback(); + mAddLabelDialogController.tryRestoreCallback(makeTag(R.id.label)); } @Override @@ -154,7 +156,7 @@ public class EditTimerActivity extends BaseActivity implements AddLabelDialog.On @OnClick(R.id.label) void openEditLabelDialog() { - mAddLabelDialogController.show(mLabel.getText()); + mAddLabelDialogController.show(mLabel.getText(), makeTag(R.id.label)); } @OnClick(R.id.fab) @@ -179,4 +181,8 @@ public class EditTimerActivity extends BaseActivity implements AddLabelDialog.On private EditText getFocusedField() { return (EditText) mEditFieldsLayout.findFocus(); } + + private static String makeTag(@IdRes int viewId) { + return FragmentTagUtils.makeTag(EditTimerActivity.class, viewId); + } } diff --git a/app/src/main/java/com/philliphsu/clock2/timers/TimerViewHolder.java b/app/src/main/java/com/philliphsu/clock2/timers/TimerViewHolder.java index 6096977..3390e5c 100644 --- a/app/src/main/java/com/philliphsu/clock2/timers/TimerViewHolder.java +++ b/app/src/main/java/com/philliphsu/clock2/timers/TimerViewHolder.java @@ -2,6 +2,7 @@ package com.philliphsu.clock2.timers; import android.animation.ObjectAnimator; import android.graphics.drawable.Drawable; +import android.support.annotation.IdRes; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.PopupMenu; @@ -20,6 +21,7 @@ import com.philliphsu.clock2.BaseViewHolder; import com.philliphsu.clock2.OnListItemInteractionListener; import com.philliphsu.clock2.R; import com.philliphsu.clock2.Timer; +import com.philliphsu.clock2.util.FragmentTagUtils; import com.philliphsu.clock2.util.ProgressBarUtils; import butterknife.Bind; @@ -30,7 +32,6 @@ import butterknife.OnClick; */ public class TimerViewHolder extends BaseViewHolder { private static final String TAG = "TimerViewHolder"; - private static final String TAG_ADD_LABEL_DIALOG = "add_label_dialog"; private final AsyncTimersTableUpdateHandler mAsyncTimersTableUpdateHandler; private TimerController mController; @@ -67,7 +68,7 @@ public class TimerViewHolder extends BaseViewHolder { mController.updateLabel(label); } }); - mAddLabelDialogController.tryRestoreCallback(); + mAddLabelDialogController.tryRestoreCallback(makeTag(R.id.label)); // The item layout is inflated in the super ctor, so we can safely reference our views. mPopupMenu = new PopupMenu(getContext(), mMenuButton); @@ -115,7 +116,7 @@ public class TimerViewHolder extends BaseViewHolder { @OnClick(R.id.label) void openLabelEditor() { - mAddLabelDialogController.show(mLabel.getText()); + mAddLabelDialogController.show(mLabel.getText(), makeTag(R.id.label)); } @OnClick(R.id.menu) @@ -195,4 +196,8 @@ public class TimerViewHolder extends BaseViewHolder { } mSeekBar.getThumb().mutate().setAlpha(timeRemaining <= 0 ? 0 : 255); } + + private String makeTag(@IdRes int viewId) { + return FragmentTagUtils.makeTag(TimerViewHolder.class, viewId, getItemId()); + } } diff --git a/app/src/main/java/com/philliphsu/clock2/util/FragmentTagUtils.java b/app/src/main/java/com/philliphsu/clock2/util/FragmentTagUtils.java new file mode 100644 index 0000000..75cb8f8 --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/util/FragmentTagUtils.java @@ -0,0 +1,25 @@ +package com.philliphsu.clock2.util; + +import android.support.annotation.IdRes; + +/** + * Created by Phillip Hsu on 9/7/2016. + */ +public final class FragmentTagUtils { + + /** + * For general use. + */ + public static String makeTag(Class cls, @IdRes int viewId) { + return cls.getName() + ":" + viewId; + } + + /** + * A version suitable for our ViewHolders. + */ + public static String makeTag(Class cls, @IdRes int viewId, long itemId) { + return makeTag(cls, viewId) + ":" + itemId; + } + + private FragmentTagUtils() {} +}