Open label dialog and time picker from ExpandedAlarmViewHolder

This commit is contained in:
Phillip Hsu 2016-09-02 19:27:41 -07:00
parent 5ec512d268
commit adb40beed8
6 changed files with 149 additions and 41 deletions

View File

@ -89,4 +89,8 @@ public class AddLabelDialog extends AppCompatDialogFragment {
});
return alert;
}
public void setOnLabelSetListener(OnLabelSetListener l) {
mOnLabelSetListener = l;
}
}

View File

@ -6,10 +6,8 @@ import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.content.Loader;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@ -19,8 +17,7 @@ import com.philliphsu.clock2.AsyncAlarmsTableUpdateHandler;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.RecyclerViewFragment;
import com.philliphsu.clock2.editalarm.BaseTimePickerDialog;
import com.philliphsu.clock2.editalarm.NumberGridTimePickerDialog;
import com.philliphsu.clock2.editalarm.NumpadTimePickerDialog;
import com.philliphsu.clock2.editalarm.TimePickerHelper;
import com.philliphsu.clock2.model.AlarmCursor;
import com.philliphsu.clock2.model.AlarmsListCursorLoader;
import com.philliphsu.clock2.util.AlarmController;
@ -34,7 +31,8 @@ public class AlarmsFragment extends RecyclerViewFragment<
implements ScrollHandler, // TODO: Move interface to base class
BaseTimePickerDialog.OnTimeSetListener {
private static final String TAG = "AlarmsFragment";
private static final String TAG_TIME_PICKER = "time_picker";
static final String TAG_TIME_PICKER = "time_picker";
// TODO: Delete these constants. We no longer use EditAlarmActivity.
// @Deprecated
@ -118,23 +116,7 @@ public class AlarmsFragment extends RecyclerViewFragment<
// 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 = null;
String numpadStyle = getString(R.string.number_pad);
String gridStyle = getString(R.string.grid_selector);
String prefTimePickerStyle = PreferenceManager.getDefaultSharedPreferences(getActivity()).getString(
// key for the preference value to retrieve
getString(R.string.key_time_picker_style),
// default value
numpadStyle);
if (prefTimePickerStyle.equals(numpadStyle)) {
dialog = NumpadTimePickerDialog.newInstance(this);
} else if (prefTimePickerStyle.equals(gridStyle)) {
dialog = NumberGridTimePickerDialog.newInstance(
this, // OnTimeSetListener
0, // Initial hour of day
0, // Initial minute
DateFormat.is24HourFormat(getActivity()));
}
BaseTimePickerDialog dialog = TimePickerHelper.newDialog(getActivity(), this);
// DISREGARD THE LINT WARNING ABOUT DIALOG BEING NULL.
dialog.show(getFragmentManager(), TAG_TIME_PICKER);
}

View File

@ -4,7 +4,9 @@ import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
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;
@ -14,10 +16,14 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.philliphsu.clock2.AddLabelDialog;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.BaseViewHolder;
import com.philliphsu.clock2.OnListItemInteractionListener;
import com.philliphsu.clock2.R;
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;
@ -38,11 +44,20 @@ import static com.philliphsu.clock2.util.DateFormatUtils.formatTime;
*/
public abstract class BaseAlarmViewHolder extends BaseViewHolder<Alarm> {
private static final String TAG = "BaseAlarmViewHolder";
private static final String TAG_ADD_LABEL_DIALOG = "add_label_dialog";
private final AlarmController mAlarmController;
// TODO: Should we use VectorDrawable type?
private final Drawable mDismissNowDrawable;
private final Drawable mCancelSnoozeDrawable;
private final FragmentManager mFragmentManager;
// These should only be changed from the OnTimeSet callback.
// If we had initialized these in onBind(), they would be reset to their original values
// from the Alarm each time the ViewHolder binds.
// A value of -1 indicates that the Alarm's time has not been changed.
int mSelectedHourOfDay = -1;
int mSelectedMinute = -1;
@Bind(R.id.time) TextView mTime;
@Bind(R.id.on_off_switch) SwitchCompat mSwitch;
@ -58,6 +73,27 @@ public abstract class BaseAlarmViewHolder extends BaseViewHolder<Alarm> {
// Instead, we create and cache the Drawables once.
mDismissNowDrawable = ContextCompat.getDrawable(getContext(), R.drawable.ic_dismiss_alarm_24dp);
mCancelSnoozeDrawable = ContextCompat.getDrawable(getContext(), R.drawable.ic_cancel_snooze);
// TODO: This is bad! Use a Controller/Presenter instead...
// or simply pass in an instance of FragmentManager to the ctor.
AppCompatActivity act = (AppCompatActivity) getContext();
mFragmentManager = act.getSupportFragmentManager();
// 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());
}
AddLabelDialog labelDialog = (AddLabelDialog)
mFragmentManager.findFragmentByTag(TAG_ADD_LABEL_DIALOG);
if (labelDialog != null) {
Log.i(TAG, "Restoring add label callback");
labelDialog.setOnLabelSetListener(newOnLabelSetListener());
}
}
@Override
@ -149,7 +185,7 @@ public abstract class BaseAlarmViewHolder extends BaseViewHolder<Alarm> {
Alarm alarm = getAlarm();
alarm.setEnabled(checked);
if (alarm.isEnabled()) {
// TODO: On Moto X, upcoming notification doesn't post immediately
// TODO: On 21+, upcoming notification doesn't post immediately
mAlarmController.scheduleAlarm(alarm, true);
mAlarmController.save(alarm);
} else {
@ -162,7 +198,14 @@ public abstract class BaseAlarmViewHolder extends BaseViewHolder<Alarm> {
@OnClick(R.id.time)
void openTimePicker() {
Log.d(TAG, "Time clicked!");
BaseTimePickerDialog dialog = TimePickerHelper.newDialog(getContext(), newOnTimeSetListener());
dialog.show(mFragmentManager, AlarmsFragment.TAG_TIME_PICKER);
}
@OnClick(R.id.label)
void openLabelEditor() {
AddLabelDialog dialog = AddLabelDialog.newInstance(newOnLabelSetListener(), mLabel.getText());
dialog.show(mFragmentManager, TAG_ADD_LABEL_DIALOG);
}
private void bindTime(Alarm alarm) {
@ -217,4 +260,37 @@ public abstract class BaseAlarmViewHolder extends BaseViewHolder<Alarm> {
boolean visible = label.length() > 0;
bindLabel(visible, label);
}
private AddLabelDialog.OnLabelSetListener newOnLabelSetListener() {
// 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 AddLabelDialog.OnLabelSetListener() {
@Override
public void onLabelSet(String label) {
mLabel.setText(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) {
mSelectedHourOfDay = hourOfDay;
mSelectedMinute = minute;
}
};
}
}

View File

@ -93,4 +93,9 @@ public class CollapsedAlarmViewHolder extends BaseAlarmViewHolder {
setVisibility(mDays, visible);
mDays.setText(text);
}
@Override
void openLabelEditor() {
// DO NOT IMPLEMENT
}
}

View File

@ -7,7 +7,6 @@ import android.graphics.drawable.Drawable;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@ -15,7 +14,6 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ToggleButton;
import com.philliphsu.clock2.AddLabelDialog;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.DaysOfWeek;
import com.philliphsu.clock2.OnListItemInteractionListener;
@ -27,6 +25,9 @@ import butterknife.Bind;
import butterknife.OnCheckedChanged;
import butterknife.OnClick;
import static com.philliphsu.clock2.DaysOfWeek.SATURDAY;
import static com.philliphsu.clock2.DaysOfWeek.SUNDAY;
/**
* Created by Phillip Hsu on 7/31/2016.
*/
@ -64,8 +65,14 @@ public class ExpandedAlarmViewHolder extends BaseAlarmViewHolder {
.ringtone(""/*TODO*/)
.vibrates(mVibrate.isChecked())
.build();
Log.d(TAG, "New alarm: " + newAlarm);
oldAlarm.copyMutableFieldsTo(newAlarm);
// ----------------------------------------------
// TOneverDO: precede copyMutableFieldsTo()
newAlarm.setEnabled(mSwitch.isChecked());
for (int i = SUNDAY; i <= SATURDAY; i++) {
newAlarm.setRecurring(i, isRecurringDay(i));
}
// ----------------------------------------------
listener.onListItemUpdate(newAlarm, getAdapterPosition());
}
});
@ -130,20 +137,6 @@ public class ExpandedAlarmViewHolder extends BaseAlarmViewHolder {
((Activity) getContext()).startActivityForResult(intent, AlarmsFragment.REQUEST_PICK_RINGTONE);
}
@OnClick(R.id.label) // The label view is in our superclass, but we can reference it.
void openLabelEditor() {
AddLabelDialog dialog = AddLabelDialog.newInstance(new AddLabelDialog.OnLabelSetListener() {
@Override
public void onLabelSet(String label) {
mLabel.setText(label);
// TODO: persist change. Use TimerController and its update()
}
}, mLabel.getText());
// TODO: This is bad! Use a Controller instead!
AppCompatActivity act = (AppCompatActivity) getContext();
dialog.show(act.getSupportFragmentManager(), "TAG");
}
///////////////////////////////////////////////////////////////////////////////////////////
// We didn't have to write code like this in EditAlarmActivity, because we never committed
// any changes until the user explicitly clicked save. We have to do this here now because
@ -204,4 +197,11 @@ public class ExpandedAlarmViewHolder extends BaseAlarmViewHolder {
RingtoneManager.getActualDefaultRingtoneUri(getContext(), RingtoneManager.TYPE_ALARM)
: Uri.parse(ringtone);
}
private boolean isRecurringDay(int weekDay) {
// What position in the week is this day located at?
int pos = DaysOfWeek.getInstance(getContext()).positionOf(weekDay);
// Return the state of this day according to its button
return mDays[pos].isChecked();
}
}

View File

@ -0,0 +1,41 @@
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) {
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, // OnTimeSetListener
0, // Initial hour of day
0, // Initial minute
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() {}
}