Java tutorial
/** * Copyright (c) 2012 Todoroo Inc * * See the file "LICENSE" for the full license governing this code. */ package com.todoroo.astrid.ui; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import com.google.common.primitives.Longs; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.alarms.AlarmFields; import com.todoroo.astrid.alarms.AlarmService; import com.todoroo.astrid.data.Task; import org.tasks.R; import org.tasks.activities.DateAndTimePickerActivity; import org.tasks.activities.TimePickerActivity; import org.tasks.injection.ForActivity; import org.tasks.injection.FragmentComponent; import org.tasks.location.Geofence; import org.tasks.location.GeofenceService; import org.tasks.location.PlacePicker; import org.tasks.preferences.Device; import org.tasks.preferences.FragmentPermissionRequestor; import org.tasks.preferences.PermissionRequestor; import org.tasks.preferences.Preferences; import org.tasks.ui.HiddenTopArrayAdapter; import org.tasks.ui.TaskEditControlFragment; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import butterknife.BindView; import butterknife.OnClick; import butterknife.OnItemSelected; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static com.todoroo.andlib.utility.DateUtilities.getLongDateStringWithTime; import static org.tasks.date.DateTimeUtils.newDateTime; /** * Control set dealing with reminder settings * * @author Tim Su <tim@todoroo.com> * */ public class ReminderControlSet extends TaskEditControlFragment { public static final int TAG = R.string.TEA_ctrl_reminders_pref; private static final int REQUEST_NEW_ALARM = 12152; private static final int REQUEST_LOCATION_REMINDER = 12153; private static final String EXTRA_TASK_ID = "extra_task_id"; private static final String EXTRA_FLAGS = "extra_flags"; private static final String EXTRA_RANDOM_REMINDER = "extra_random_reminder"; private static final String EXTRA_ALARMS = "extra_alarms"; private static final String EXTRA_GEOFENCES = "extra_geofences"; @Inject AlarmService alarmService; @Inject GeofenceService geofenceService; @Inject FragmentPermissionRequestor permissionRequestor; @Inject Device device; @Inject Preferences preferences; @Inject @ForActivity Context context; @BindView(R.id.alert_container) LinearLayout alertContainer; @BindView(R.id.reminder_alarm) Spinner mode; @BindView(R.id.alarms_add_spinner) Spinner addSpinner; private long taskId; private int flags; private long randomReminder; private int ringMode; private RandomReminderControlSet randomControlSet; private boolean whenDue; private boolean whenOverdue; private final List<String> spinnerOptions = new ArrayList<>(); private ArrayAdapter<String> remindAdapter; private final Set<Long> alarms = new LinkedHashSet<>(); private final Set<Geofence> geofences = new LinkedHashSet<>(); @OnItemSelected(R.id.reminder_alarm) void ringModeSelected(int position) { ringMode = position; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = super.onCreateView(inflater, container, savedInstanceState); remindAdapter = new HiddenTopArrayAdapter(context, android.R.layout.simple_spinner_item, spinnerOptions); String[] modes = getResources().getStringArray(R.array.reminder_ring_modes); ArrayAdapter<String> modeAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, modes); modeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mode.setAdapter(modeAdapter); if (savedInstanceState != null) { taskId = savedInstanceState.getLong(EXTRA_TASK_ID); flags = savedInstanceState.getInt(EXTRA_FLAGS); randomReminder = savedInstanceState.getLong(EXTRA_RANDOM_REMINDER); List<Geofence> geofences = new ArrayList<>(); List<Parcelable> geofenceArray = savedInstanceState.getParcelableArrayList(EXTRA_GEOFENCES); for (Parcelable geofence : geofenceArray) { geofences.add((Geofence) geofence); } setup(Longs.asList(savedInstanceState.getLongArray(EXTRA_ALARMS)), geofences); } else { setup(currentAlarms(), geofenceService.getGeofences(taskId)); } addSpinner.setAdapter(remindAdapter); return view; } private List<Long> currentAlarms() { final List<Long> alarms = new ArrayList<>(); alarmService.getAlarms(taskId, entry -> alarms.add(entry.getValue(AlarmFields.TIME))); return alarms; } @OnItemSelected(R.id.alarms_add_spinner) void addAlarm(int position) { String selected = spinnerOptions.get(position); if (selected.equals(getString(R.string.when_due))) { addDue(); } else if (selected.equals(getString(R.string.when_overdue))) { addOverdue(); } else if (selected.equals(getString(R.string.randomly))) { addRandomReminder(TimeUnit.DAYS.toMillis(14)); } else if (selected.equals(getString(R.string.pick_a_date_and_time))) { addNewAlarm(); } else if (selected.equals(getString(R.string.pick_a_location))) { if (permissionRequestor.requestFineLocation()) { pickLocation(); } } if (position != 0) { updateSpinner(); } } @OnClick(R.id.alarms_add) void addAlarm(View view) { if (spinnerOptions.size() == 2) { addNewAlarm(); } else { addSpinner.performClick(); } } @Override protected int getLayout() { return R.layout.control_set_reminders; } @Override public int getIcon() { return R.drawable.ic_notifications_24dp; } @Override public int controlId() { return TAG; } @Override public void initialize(boolean isNewTask, Task task) { taskId = task.getId(); flags = task.getReminderFlags(); randomReminder = task.getReminderPeriod(); } private void setup(List<Long> alarms, List<Geofence> geofences) { setValue(flags); alertContainer.removeAllViews(); if (whenDue) { addDue(); } if (whenOverdue) { addOverdue(); } if (randomReminder > 0) { addRandomReminder(randomReminder); } for (long timestamp : alarms) { addAlarmRow(timestamp); } for (Geofence geofence : geofences) { addGeolocationReminder(geofence); } updateSpinner(); } @Override public boolean hasChanges(Task original) { return getFlags() != original.getReminderFlags() || getRandomReminderPeriod() != original.getReminderPeriod() || !newHashSet(currentAlarms()).equals(alarms) || !newHashSet(geofenceService.getGeofences(taskId)).equals(geofences); } @Override public void apply(Task task) { task.setReminderFlags(getFlags()); task.setReminderPeriod(getRandomReminderPeriod()); if (alarmService.synchronizeAlarms(task.getId(), alarms)) { task.setModificationDate(DateUtilities.now()); } if (geofenceService.synchronizeGeofences(task.getId(), geofences)) { task.setModificationDate(DateUtilities.now()); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putLong(EXTRA_TASK_ID, taskId); outState.putInt(EXTRA_FLAGS, getFlags()); outState.putLong(EXTRA_RANDOM_REMINDER, getRandomReminderPeriod()); outState.putLongArray(EXTRA_ALARMS, Longs.toArray(alarms)); outState.putParcelableArrayList(EXTRA_GEOFENCES, newArrayList(geofences)); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_NEW_ALARM) { if (resultCode == Activity.RESULT_OK) { addAlarmRow(data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L)); } } else if (requestCode == REQUEST_LOCATION_REMINDER) { if (resultCode == Activity.RESULT_OK) { addGeolocationReminder(PlacePicker.getPlace(context, data, preferences)); } } else { super.onActivityResult(requestCode, resultCode, data); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == PermissionRequestor.REQUEST_LOCATION) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { pickLocation(); } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } private void addAlarmRow(final Long timestamp) { addAlarmRow(getLongDateStringWithTime(context, timestamp), v -> alarms.remove(timestamp)); alarms.add(timestamp); } private void pickLocation() { Intent intent = PlacePicker.getIntent(getActivity()); if (intent != null) { startActivityForResult(intent, REQUEST_LOCATION_REMINDER); } } private void addGeolocationReminder(final Geofence geofence) { addAlarmRow(geofence.getName(), v -> geofences.remove(geofence)); geofences.add(geofence); } private int getFlags() { 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 (ringMode == 2) { value |= Task.NOTIFY_MODE_NONSTOP; } else if (ringMode == 1) { value |= Task.NOTIFY_MODE_FIVE; } return value; } private long getRandomReminderPeriod() { return randomControlSet == null ? 0L : randomControlSet.getReminderPeriod(); } private void addNewAlarm() { Intent intent = new Intent(getActivity(), DateAndTimePickerActivity.class); intent.putExtra(DateAndTimePickerActivity.EXTRA_TIMESTAMP, newDateTime().startOfDay().getMillis()); startActivityForResult(intent, REQUEST_NEW_ALARM); } private View addAlarmRow(String text, final OnClickListener onRemove) { final View alertItem = getActivity().getLayoutInflater().inflate(R.layout.alarm_edit_row, null); alertContainer.addView(alertItem); addAlarmRow(alertItem, text, onRemove); return alertItem; } private void addAlarmRow(final View alertItem, String text, final View.OnClickListener onRemove) { TextView display = (TextView) alertItem.findViewById(R.id.alarm_string); display.setText(text); alertItem.findViewById(R.id.clear).setOnClickListener(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(getString(R.string.when_due)); } if (!whenOverdue) { spinnerOptions.add(getString(R.string.when_overdue)); } if (randomControlSet == null) { spinnerOptions.add(getString(R.string.randomly)); } if (device.supportsLocationServices()) { spinnerOptions.add(getString(R.string.pick_a_location)); } spinnerOptions.add(getString(R.string.pick_a_date_and_time)); remindAdapter.notifyDataSetChanged(); } private void addDue() { whenDue = true; addAlarmRow(getString(R.string.when_due), v -> whenDue = false); } private void addOverdue() { whenOverdue = true; addAlarmRow(getString(R.string.when_overdue), v -> whenOverdue = false); } private void addRandomReminder(long reminderPeriod) { View alarmRow = addAlarmRow(getString(R.string.randomly_once) + " ", v -> randomControlSet = null); randomControlSet = new RandomReminderControlSet(context, alarmRow, reminderPeriod); } 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 inject(FragmentComponent component) { component.inject(this); } }