You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tasks/src/main/java/com/todoroo/astrid/ui/ReminderControlSet.java

402 lines
14 KiB
Java

/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.ui;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import com.todoroo.andlib.data.Callback;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.TaskEditFragment;
import com.todoroo.astrid.alarms.AlarmFields;
import com.todoroo.astrid.alarms.AlarmService;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.helper.TaskEditControlSetBase;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.R;
import org.tasks.dialogs.DateAndTimePickerDialog;
import org.tasks.dialogs.LocationPickerDialog;
import org.tasks.location.Geofence;
import org.tasks.location.GeofenceService;
import org.tasks.location.OnLocationPickedHandler;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import static org.tasks.date.DateTimeUtils.newDateTime;
/**
* Control set dealing with reminder settings
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class ReminderControlSet extends TaskEditControlSetBase implements AdapterView.OnItemSelectedListener {
private static final Logger log = LoggerFactory.getLogger(ReminderControlSet.class);
private static final String FRAG_TAG_LOCATION_PICKER = "frag_tag_location_picker";
private Spinner mode;
private Spinner addSpinner;
private TextView modeDisplay;
private RandomReminderControlSet randomControlSet;
private LinearLayout alertContainer;
private boolean whenDue;
private boolean whenOverdue;
private AlarmService alarmService;
private GeofenceService geofenceService;
private TaskEditFragment taskEditFragment;
private List<String> spinnerOptions = new ArrayList<>();
private ArrayAdapter<String> remindAdapter;
public ReminderControlSet(AlarmService alarmService, GeofenceService geofenceService, TaskEditFragment taskEditFragment) {
super(taskEditFragment.getActivity(), R.layout.control_set_reminders);
this.alarmService = alarmService;
this.geofenceService = geofenceService;
this.taskEditFragment = taskEditFragment;
}
public int getValue() {
int value = 0;
if(whenDue) {
value |= Task.NOTIFY_AT_DEADLINE;
}
if(whenOverdue) {
value |= Task.NOTIFY_AFTER_DEADLINE;
}
value &= ~(Task.NOTIFY_MODE_FIVE | Task.NOTIFY_MODE_NONSTOP);
if(mode.getSelectedItemPosition() == 2) {
value |= Task.NOTIFY_MODE_NONSTOP;
} else if(mode.getSelectedItemPosition() == 1) {
value |= Task.NOTIFY_MODE_FIVE;
}
return value;
}
private void addNewAlarm() {
pickNewAlarm(newDateTime().withMillisOfDay(0), new DateAndTimePickerDialog.OnDateTimePicked() {
@Override
public void onDateTimePicked(DateTime dateTime) {
addAlarmRow(dateTime.getMillis());
}
});
}
private void pickNewAlarm(DateTime initial, DateAndTimePickerDialog.OnDateTimePicked onDateTimePicked) {
DateAndTimePickerDialog.dateAndTimePickerDialog(taskEditFragment.getFragmentManager(),
taskEditFragment.getActivity(), initial, onDateTimePicked, null);
}
private void addAlarmRow(final Long timestamp) {
final View alertItem = addAlarmRow(getDisplayString(timestamp), timestamp, null);
TextView display = (TextView) alertItem.findViewById(R.id.alarm_string);
display.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
pickNewAlarm(newDateTime(timestamp), new DateAndTimePickerDialog.OnDateTimePicked() {
@Override
public void onDateTimePicked(DateTime dateTime) {
long millis = dateTime.getMillis();
addAlarmRow(alertItem, getDisplayString(millis), millis, null);
}
});
}
});
}
public void addGeolocationReminder(final Geofence geofence) {
View alertItem = addAlarmRow(geofence.getName(), null, new OnClickListener() {
@Override
public void onClick(View v) {
}
});
alertItem.setTag(geofence);
}
private View addAlarmRow(String text, Long timestamp, final OnClickListener onRemove) {
final View alertItem = LayoutInflater.from(activity).inflate(R.layout.alarm_edit_row, null);
alertContainer.addView(alertItem);
addAlarmRow(alertItem, text, timestamp, onRemove);
return alertItem;
}
private void addAlarmRow(final View alertItem, String text, Long timestamp, final View.OnClickListener onRemove) {
alertItem.setTag(timestamp);
TextView display = (TextView) alertItem.findViewById(R.id.alarm_string);
display.setText(text);
alertItem.findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
alertContainer.removeView(alertItem);
if (onRemove != null) {
onRemove.onClick(v);
}
updateSpinner();
}
});
updateSpinner();
}
private void updateSpinner() {
addSpinner.setSelection(0);
spinnerOptions.clear();
spinnerOptions.add("");
if (!whenDue) {
spinnerOptions.add(taskEditFragment.getString(R.string.when_due));
}
if (!whenOverdue) {
spinnerOptions.add(taskEditFragment.getString(R.string.when_overdue));
}
if (randomControlSet == null) {
spinnerOptions.add(taskEditFragment.getString(R.string.randomly));
}
if (taskEditFragment.getResources().getBoolean(R.bool.location_enabled)) {
spinnerOptions.add(taskEditFragment.getString(R.string.pick_a_location));
}
spinnerOptions.add(taskEditFragment.getString(R.string.pick_a_date_and_time));
remindAdapter.notifyDataSetChanged();
}
@Override
protected void afterInflate() {
alertContainer = (LinearLayout) getView().findViewById(R.id.alert_container);
getView().findViewById(R.id.alarms_add).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (spinnerOptions.size() == 2) {
addNewAlarm();
} else {
addSpinner.performClick();
}
}
});
addSpinner = (Spinner) getView().findViewById(R.id.alarms_add_spinner);
addSpinner.setOnItemSelectedListener(ReminderControlSet.this);
remindAdapter = new ArrayAdapter<String>(activity, R.layout.simple_spinner_item, spinnerOptions) {
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View v;
// If this is the initial dummy entry, make it hidden
if (position == 0) {
TextView tv = new TextView(getContext());
tv.setHeight(0);
tv.setVisibility(View.GONE);
v = tv;
}
else {
// Pass convertView as null to prevent reuse of special case views
v = super.getDropDownView(position, null, parent);
}
// Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling
parent.setVerticalScrollBarEnabled(false);
return v;
}
};
addSpinner.setAdapter(remindAdapter);
remindAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
modeDisplay = (TextView) getView().findViewById(R.id.reminder_alarm_display);
mode = (Spinner) getView().findViewById(R.id.reminder_alarm);
modeDisplay.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mode.performClick();
}
});
String[] list = new String[] {
activity.getString(R.string.ring_once),
activity.getString(R.string.ring_five_times),
activity.getString(R.string.ring_nonstop),
};
final ArrayAdapter<String> modeAdapter = new ArrayAdapter<>(
activity, android.R.layout.simple_spinner_item, list);
modeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mode.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
modeDisplay.setText(modeAdapter.getItem(position));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
mode.setAdapter(modeAdapter);
}
});
}
@Override
protected void readFromTaskOnInitialize() {
setValue(model.getReminderFlags());
alertContainer.removeAllViews();
if (whenDue) {
addDue();
}
if (whenOverdue) {
addOverdue();
}
if (model.hasRandomReminder()) {
addRandomReminder();
}
alarmService.getAlarms(model.getId(), new Callback<Metadata>() {
@Override
public void apply(Metadata entry) {
addAlarmRow(entry.getValue(AlarmFields.TIME));
}
});
for (Geofence geofence : geofenceService.getGeofences(model.getId())) {
addGeolocationReminder(geofence);
}
updateSpinner();
}
private void addDue() {
whenDue = true;
addAlarmRow(taskEditFragment.getString(R.string.when_due), null, new OnClickListener() {
@Override
public void onClick(View v) {
whenDue = false;
}
});
}
private void addOverdue() {
whenOverdue = true;
addAlarmRow(taskEditFragment.getString(R.string.when_overdue), null, new OnClickListener() {
@Override
public void onClick(View v) {
whenOverdue = false;
}
});
}
private void addRandomReminder() {
View alarmRow = addAlarmRow(taskEditFragment.getString(R.string.randomly_once), null, new OnClickListener() {
@Override
public void onClick(View v) {
randomControlSet = null;
}
});
randomControlSet = new RandomReminderControlSet(activity, alarmRow);
randomControlSet.readFromTaskOnInitialize(model);
}
private void setValue(int flags) {
whenDue = (flags & Task.NOTIFY_AT_DEADLINE) > 0;
whenOverdue = (flags & Task.NOTIFY_AFTER_DEADLINE) > 0;
if((flags & Task.NOTIFY_MODE_NONSTOP) > 0) {
mode.setSelection(2);
} else if((flags & Task.NOTIFY_MODE_FIVE) > 0) {
mode.setSelection(1);
} else {
mode.setSelection(0);
}
}
@Override
protected void writeToModelAfterInitialized(Task task) {
task.setReminderFlags(getValue());
task.setReminderPeriod(randomControlSet == null ? 0L : randomControlSet.getReminderPeriod());
Set<Long> alarms = new LinkedHashSet<>();
Set<Geofence> geofences = new LinkedHashSet<>();
for(int i = 0; i < alertContainer.getChildCount(); i++) {
Object tag = alertContainer.getChildAt(i).getTag();
//noinspection StatementWithEmptyBody
if (tag == null) {
} else if (tag instanceof Long) {
alarms.add((Long) tag);
} else if (tag instanceof Geofence) {
geofences.add((Geofence) tag);
} else {
log.error("Unexpected tag: {}", tag);
}
}
if(alarmService.synchronizeAlarms(task.getId(), alarms)) {
task.setModificationDate(DateUtilities.now());
}
if (geofenceService.synchronizeGeofences(task.getId(), geofences)) {
task.setModificationDate(DateUtilities.now());
}
}
private String getDisplayString(long forDate) {
DateTime dateTime = newDateTime(forDate);
Date d = dateTime.toDate();
return (dateTime.getYear() == newDateTime().getYear()
? DateUtilities.getLongDateStringHideYear(d)
: DateUtilities.getLongDateString(d)) +
", " + DateUtilities.getTimeString(activity, d);
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
log.info("onItemSelected({}, {}, {}, {})", parent, view, position, id);
String selected = spinnerOptions.get(position);
if (selected.equals(taskEditFragment.getString(R.string.when_due))) {
addDue();
} else if(selected.equals(taskEditFragment.getString(R.string.when_overdue))) {
addOverdue();
} else if (selected.equals(taskEditFragment.getString(R.string.randomly))) {
addRandomReminder();
} else if (selected.equals(taskEditFragment.getString(R.string.pick_a_date_and_time))) {
addNewAlarm();
} else if (selected.equals(taskEditFragment.getString(R.string.pick_a_location))) {
new LocationPickerDialog(new OnLocationPickedHandler() {
@Override
public void onLocationPicked(Geofence geofence) {
addGeolocationReminder(geofence);
}
}).show(taskEditFragment.getChildFragmentManager(), FRAG_TAG_LOCATION_PICKER);
}
if (position != 0) {
updateSpinner();
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
@Override
public int getIcon() {
return R.attr.ic_action_bell;
}
}