mirror of https://github.com/tasks/tasks
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.
1449 lines
53 KiB
Java
1449 lines
53 KiB
Java
/*
|
|
* ASTRID: Android's Simple Task Recording Dashboard
|
|
*
|
|
* Copyright (c) 2009 Tim Su
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
package com.todoroo.astrid.activity;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Calendar;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
|
|
import android.app.AlertDialog;
|
|
import android.app.TabActivity;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.ContentValues;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.DialogInterface.OnCancelListener;
|
|
import android.content.DialogInterface.OnDismissListener;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.res.Resources;
|
|
import android.graphics.Color;
|
|
import android.os.Bundle;
|
|
import android.speech.RecognizerIntent;
|
|
import android.text.format.DateUtils;
|
|
import android.util.Log;
|
|
import android.view.LayoutInflater;
|
|
import android.view.Menu;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.view.ViewGroup.LayoutParams;
|
|
import android.widget.AdapterView;
|
|
import android.widget.AdapterView.OnItemSelectedListener;
|
|
import android.widget.ArrayAdapter;
|
|
import android.widget.Button;
|
|
import android.widget.CheckBox;
|
|
import android.widget.CompoundButton;
|
|
import android.widget.EditText;
|
|
import android.widget.ImageButton;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.RemoteViews;
|
|
import android.widget.Spinner;
|
|
import android.widget.TabHost;
|
|
import android.widget.TextView;
|
|
import android.widget.TimePicker;
|
|
import android.widget.Toast;
|
|
import android.widget.ToggleButton;
|
|
|
|
import com.timsu.astrid.R;
|
|
import com.todoroo.andlib.data.Property.StringProperty;
|
|
import com.todoroo.andlib.service.Autowired;
|
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
|
import com.todoroo.andlib.service.ExceptionService;
|
|
import com.todoroo.andlib.utility.AndroidUtilities;
|
|
import com.todoroo.andlib.utility.DateUtilities;
|
|
import com.todoroo.astrid.alarms.AlarmControlSet;
|
|
import com.todoroo.astrid.api.AstridApiConstants;
|
|
import com.todoroo.astrid.dao.Database;
|
|
import com.todoroo.astrid.data.Task;
|
|
import com.todoroo.astrid.gcal.GCalControlSet;
|
|
import com.todoroo.astrid.opencrx.OpencrxControlSet;
|
|
import com.todoroo.astrid.opencrx.OpencrxCoreUtils;
|
|
import com.todoroo.astrid.producteev.ProducteevControlSet;
|
|
import com.todoroo.astrid.producteev.ProducteevUtilities;
|
|
import com.todoroo.astrid.reminders.Notifications;
|
|
import com.todoroo.astrid.repeats.RepeatControlSet;
|
|
import com.todoroo.astrid.service.AddOnService;
|
|
import com.todoroo.astrid.service.MetadataService;
|
|
import com.todoroo.astrid.service.StartupService;
|
|
import com.todoroo.astrid.service.StatisticsService;
|
|
import com.todoroo.astrid.service.TaskService;
|
|
import com.todoroo.astrid.tags.TagsControlSet;
|
|
import com.todoroo.astrid.timers.TimerControlSet;
|
|
import com.todoroo.astrid.ui.CalendarDialog;
|
|
import com.todoroo.astrid.ui.DeadlineTimePickerDialog;
|
|
import com.todoroo.astrid.ui.DeadlineTimePickerDialog.OnDeadlineTimeSetListener;
|
|
import com.todoroo.astrid.voice.VoiceInputAssistant;
|
|
|
|
/**
|
|
* This activity is responsible for creating new tasks and editing existing
|
|
* ones. It saves a task when it is paused (screen rotated, back button
|
|
* pressed) as long as the task has a title.
|
|
*
|
|
* @author timsu
|
|
*
|
|
*/
|
|
public final class TaskEditActivity extends TabActivity {
|
|
|
|
// --- bundle tokens
|
|
|
|
/**
|
|
* Task ID
|
|
*/
|
|
public static final String TOKEN_ID = "id"; //$NON-NLS-1$
|
|
|
|
/**
|
|
* Content Values to set
|
|
*/
|
|
public static final String TOKEN_VALUES = "v"; //$NON-NLS-1$
|
|
|
|
/**
|
|
* Task in progress (during orientation change)
|
|
*/
|
|
private static final String TASK_IN_PROGRESS = "task_in_progress"; //$NON-NLS-1$
|
|
|
|
// --- request codes
|
|
|
|
@SuppressWarnings("unused")
|
|
private static final int REQUEST_CODE_OPERATION = 0;
|
|
|
|
// --- menu codes
|
|
|
|
private static final int MENU_SAVE_ID = Menu.FIRST;
|
|
private static final int MENU_DISCARD_ID = Menu.FIRST + 1;
|
|
private static final int MENU_DELETE_ID = Menu.FIRST + 2;
|
|
|
|
// --- result codes
|
|
|
|
public static final int RESULT_CODE_SAVED = RESULT_FIRST_USER;
|
|
public static final int RESULT_CODE_DISCARDED = RESULT_FIRST_USER + 1;
|
|
public static final int RESULT_CODE_DELETED = RESULT_FIRST_USER + 2;
|
|
|
|
// --- services
|
|
|
|
@Autowired
|
|
private ExceptionService exceptionService;
|
|
|
|
@Autowired
|
|
private Database database;
|
|
|
|
@Autowired
|
|
private TaskService taskService;
|
|
|
|
@Autowired
|
|
private MetadataService metadataService;
|
|
|
|
@Autowired
|
|
private AddOnService addOnService;
|
|
|
|
// --- UI components
|
|
|
|
private ImageButton voiceAddNoteButton;
|
|
|
|
private EditTextControlSet notesControlSet = null;
|
|
private EditText title;
|
|
|
|
private final List<TaskEditControlSet> controls =
|
|
Collections.synchronizedList(new ArrayList<TaskEditControlSet>());
|
|
|
|
// --- other instance variables
|
|
|
|
/** true if editing started with a new task */
|
|
boolean isNewTask = false;
|
|
|
|
/** task model */
|
|
private Task model = null;
|
|
|
|
/** whether task should be saved when this activity exits */
|
|
private boolean shouldSaveState = true;
|
|
|
|
/** edit control receiver */
|
|
private final ControlReceiver controlReceiver = new ControlReceiver();
|
|
|
|
/** voice assistant for notes-creation */
|
|
private VoiceInputAssistant voiceNoteAssistant = null;
|
|
|
|
private EditText notesEditText;
|
|
|
|
private boolean cancelled = false;
|
|
|
|
/* ======================================================================
|
|
* ======================================================= initialization
|
|
* ====================================================================== */
|
|
|
|
public TaskEditActivity() {
|
|
DependencyInjectionService.getInstance().inject(this);
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
new StartupService().onStartupApplication(this);
|
|
|
|
setUpUIComponents();
|
|
|
|
// disable keyboard until user requests it
|
|
AndroidUtilities.suppressVirtualKeyboard(title);
|
|
|
|
// if we were editing a task already, restore it
|
|
if(savedInstanceState != null && savedInstanceState.containsKey(TASK_IN_PROGRESS)) {
|
|
Task task = savedInstanceState.getParcelable(TASK_IN_PROGRESS);
|
|
if(task != null) {
|
|
model = task;
|
|
}
|
|
}
|
|
|
|
setResult(RESULT_OK);
|
|
}
|
|
|
|
/* ======================================================================
|
|
* ==================================================== UI initialization
|
|
* ====================================================================== */
|
|
|
|
/** Initialize UI components */
|
|
private void setUpUIComponents() {
|
|
Resources r = getResources();
|
|
|
|
// set up tab host
|
|
TabHost tabHost = getTabHost();
|
|
tabHost.setPadding(0, 4, 0, 0);
|
|
LayoutInflater.from(this).inflate(R.layout.task_edit_activity,
|
|
tabHost.getTabContentView(), true);
|
|
tabHost.addTab(tabHost.newTabSpec(r.getString(R.string.TEA_tab_basic)).
|
|
setIndicator(r.getString(R.string.TEA_tab_basic),
|
|
r.getDrawable(R.drawable.tab_edit)).setContent(
|
|
R.id.tab_basic));
|
|
tabHost.addTab(tabHost.newTabSpec(r.getString(R.string.TEA_tab_extra)).
|
|
setIndicator(r.getString(R.string.TEA_tab_extra),
|
|
r.getDrawable(R.drawable.tab_advanced)).setContent(
|
|
R.id.tab_extra));
|
|
tabHost.addTab(tabHost.newTabSpec(r.getString(R.string.TEA_tab_addons)).
|
|
setIndicator(r.getString(R.string.TEA_tab_addons),
|
|
r.getDrawable(R.drawable.tab_addons)).setContent(
|
|
R.id.tab_addons));
|
|
getTabWidget().setBackgroundColor(Color.BLACK);
|
|
|
|
// populate control set
|
|
title = (EditText) findViewById(R.id.title);
|
|
controls.add(new EditTextControlSet(Task.TITLE, R.id.title));
|
|
controls.add(new ImportanceControlSet(R.id.importance_container));
|
|
controls.add(new UrgencyControlSet(R.id.urgency));
|
|
notesEditText = (EditText) findViewById(R.id.notes);
|
|
|
|
// prepare and set listener for voice-button
|
|
if(addOnService.hasPowerPack()) {
|
|
voiceAddNoteButton = (ImageButton) findViewById(R.id.voiceAddNoteButton);
|
|
voiceAddNoteButton.setVisibility(View.VISIBLE);
|
|
int prompt = R.string.voice_edit_note_prompt;
|
|
voiceNoteAssistant = new VoiceInputAssistant(this, voiceAddNoteButton,
|
|
notesEditText);
|
|
voiceNoteAssistant.setAppend(true);
|
|
voiceNoteAssistant.setLanguageModel(RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
|
|
voiceNoteAssistant.configureMicrophoneButton(prompt);
|
|
}
|
|
|
|
new Thread() {
|
|
@Override
|
|
public void run() {
|
|
AndroidUtilities.sleepDeep(500L);
|
|
|
|
runOnUiThread(new Runnable() {
|
|
public void run() {
|
|
// internal add-ins
|
|
controls.add(new TagsControlSet(TaskEditActivity.this, R.id.tags_container));
|
|
|
|
LinearLayout extrasAddons = (LinearLayout) findViewById(R.id.tab_extra_addons);
|
|
controls.add(new RepeatControlSet(TaskEditActivity.this, extrasAddons));
|
|
controls.add(new GCalControlSet(TaskEditActivity.this, extrasAddons));
|
|
|
|
LinearLayout addonsAddons = (LinearLayout) findViewById(R.id.tab_addons_addons);
|
|
|
|
try {
|
|
if(ProducteevUtilities.INSTANCE.isLoggedIn()) {
|
|
controls.add(new ProducteevControlSet(TaskEditActivity.this, addonsAddons));
|
|
notesEditText.setHint(R.string.producteev_TEA_notes);
|
|
((TextView)findViewById(R.id.notes_label)).setHint(R.string.producteev_TEA_notes);
|
|
}
|
|
} catch (Exception e) {
|
|
Log.e("astrid-error", "loading-control-set", e); //$NON-NLS-1$ //$NON-NLS-2$
|
|
}
|
|
|
|
try {
|
|
if(OpencrxCoreUtils.INSTANCE.isLoggedIn()) {
|
|
controls.add(new OpencrxControlSet(TaskEditActivity.this, addonsAddons));
|
|
notesEditText.setHint(R.string.opencrx_TEA_notes);
|
|
((TextView)findViewById(R.id.notes_label)).setHint(R.string.opencrx_TEA_notes);
|
|
}
|
|
} catch (Exception e) {
|
|
Log.e("astrid-error", "loading-control-set", e); //$NON-NLS-1$ //$NON-NLS-2$
|
|
}
|
|
|
|
controls.add(new TimerControlSet(TaskEditActivity.this, addonsAddons));
|
|
controls.add(new AlarmControlSet(TaskEditActivity.this, addonsAddons));
|
|
|
|
if(!addOnService.hasPowerPack()) {
|
|
// show add-on help if necessary
|
|
View addonsEmpty = findViewById(R.id.addons_empty);
|
|
addonsEmpty.setVisibility(View.VISIBLE);
|
|
addonsAddons.removeView(addonsEmpty);
|
|
addonsAddons.addView(addonsEmpty);
|
|
((Button)findViewById(R.id.addons_button)).setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
Intent addOnActivity = new Intent(TaskEditActivity.this, AddOnActivity.class);
|
|
addOnActivity.putExtra(AddOnActivity.TOKEN_START_WITH_AVAILABLE, true);
|
|
startActivity(addOnActivity);
|
|
}
|
|
});
|
|
}
|
|
|
|
controls.add(new ReminderControlSet(R.id.reminder_due,
|
|
R.id.reminder_overdue, R.id.reminder_alarm));
|
|
controls.add(new RandomReminderControlSet(R.id.reminder_random,
|
|
R.id.reminder_random_interval));
|
|
controls.add(new HideUntilControlSet(R.id.hideUntil));
|
|
|
|
// re-read all
|
|
synchronized(controls) {
|
|
for(TaskEditControlSet controlSet : controls)
|
|
controlSet.readFromTask(model);
|
|
}
|
|
}
|
|
});
|
|
|
|
notesControlSet = new EditTextControlSet(Task.NOTES, R.id.notes);
|
|
controls.add(notesControlSet);
|
|
|
|
// set up listeners
|
|
setUpListeners();
|
|
}
|
|
}.start();
|
|
|
|
}
|
|
|
|
/** Set up button listeners */
|
|
private void setUpListeners() {
|
|
final View.OnClickListener mSaveListener = new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
saveButtonClick();
|
|
}
|
|
};
|
|
final View.OnClickListener mDiscardListener = new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
discardButtonClick();
|
|
}
|
|
};
|
|
|
|
// set up save, cancel, and delete buttons
|
|
try {
|
|
ImageButton saveButtonGeneral = (ImageButton) findViewById(R.id.save_basic);
|
|
saveButtonGeneral.setOnClickListener(mSaveListener);
|
|
ImageButton saveButtonDates = (ImageButton) findViewById(R.id.save_extra);
|
|
saveButtonDates.setOnClickListener(mSaveListener);
|
|
ImageButton saveButtonNotify = (ImageButton) findViewById(R.id.save_addons);
|
|
saveButtonNotify.setOnClickListener(mSaveListener);
|
|
|
|
ImageButton discardButtonGeneral = (ImageButton) findViewById(R.id.discard_basic);
|
|
discardButtonGeneral.setOnClickListener(mDiscardListener);
|
|
ImageButton discardButtonDates = (ImageButton) findViewById(R.id.discard_extra);
|
|
discardButtonDates.setOnClickListener(mDiscardListener);
|
|
ImageButton discardButtonNotify = (ImageButton) findViewById(R.id.discard_addons);
|
|
discardButtonNotify.setOnClickListener(mDiscardListener);
|
|
} catch (Exception e) {
|
|
// error loading the proper activity
|
|
}
|
|
}
|
|
|
|
/* ======================================================================
|
|
* =============================================== model reading / saving
|
|
* ====================================================================== */
|
|
|
|
/**
|
|
* Loads action item from the given intent
|
|
* @param intent
|
|
*/
|
|
@SuppressWarnings("nls")
|
|
protected void loadItem(Intent intent) {
|
|
if(model != null) {
|
|
// came from bundle
|
|
isNewTask = (model.getValue(Task.TITLE).length() == 0);
|
|
return;
|
|
}
|
|
|
|
long idParam = intent.getLongExtra(TOKEN_ID, -1L);
|
|
|
|
database.openForReading();
|
|
if(idParam > -1L) {
|
|
model = taskService.fetchById(idParam, Task.PROPERTIES);
|
|
}
|
|
|
|
// not found by id or was never passed an id
|
|
if(model == null) {
|
|
String valuesAsString = intent.getStringExtra(TOKEN_VALUES);
|
|
ContentValues values = null;
|
|
try {
|
|
if(valuesAsString != null)
|
|
values = AndroidUtilities.contentValuesFromSerializedString(valuesAsString);
|
|
} catch (Exception e) {
|
|
// oops, can't serialize
|
|
}
|
|
model = TaskListActivity.createWithValues(values, null, taskService, metadataService);
|
|
}
|
|
|
|
if(model.getValue(Task.TITLE).length() == 0) {
|
|
StatisticsService.reportEvent("create-task");
|
|
isNewTask = true;
|
|
|
|
// set deletion date until task gets a title
|
|
model.setValue(Task.DELETION_DATE, DateUtilities.now());
|
|
} else {
|
|
StatisticsService.reportEvent("edit-task");
|
|
}
|
|
|
|
if(model == null) {
|
|
exceptionService.reportError("task-edit-no-task",
|
|
new NullPointerException("model"));
|
|
finish();
|
|
return;
|
|
}
|
|
|
|
// clear notification
|
|
Notifications.cancelNotifications(model.getId());
|
|
}
|
|
|
|
/** Populate UI component values from the model */
|
|
private void populateFields() {
|
|
Resources r = getResources();
|
|
loadItem(getIntent());
|
|
|
|
if(isNewTask)
|
|
setTitle(R.string.TEA_view_titleNew);
|
|
else
|
|
setTitle(r.getString(R.string.TEA_view_title, model.getValue(Task.TITLE)));
|
|
|
|
synchronized(controls) {
|
|
for(TaskEditControlSet controlSet : controls)
|
|
controlSet.readFromTask(model);
|
|
}
|
|
}
|
|
|
|
/** Save task model from values in UI components */
|
|
private void save() {
|
|
StringBuilder toast = new StringBuilder();
|
|
synchronized(controls) {
|
|
for(TaskEditControlSet controlSet : controls) {
|
|
String toastText = controlSet.writeToModel(model);
|
|
if(toastText != null)
|
|
toast.append('\n').append(toastText);
|
|
}
|
|
}
|
|
|
|
if(title.getText().length() > 0)
|
|
model.setValue(Task.DELETION_DATE, 0L);
|
|
|
|
if(taskService.save(model) && title.getText().length() > 0)
|
|
showSaveToast(toast.toString());
|
|
}
|
|
|
|
@Override
|
|
public void finish() {
|
|
super.finish();
|
|
|
|
// abandon editing and delete the newly created task if
|
|
// no title was entered
|
|
|
|
if(title.getText().length() == 0 && isNewTask && model.isSaved()) {
|
|
taskService.delete(model);
|
|
}
|
|
}
|
|
|
|
/* ======================================================================
|
|
* ================================================ edit control handling
|
|
* ====================================================================== */
|
|
|
|
/**
|
|
* Receiver which receives intents to add items to the filter list
|
|
*
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
protected class ControlReceiver extends BroadcastReceiver {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
try {
|
|
Bundle extras = intent.getExtras();
|
|
RemoteViews view = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE);
|
|
|
|
// add a separator
|
|
View separator = new View(TaskEditActivity.this);
|
|
separator.setPadding(5, 5, 5, 5);
|
|
separator.setBackgroundResource(android.R.drawable.divider_horizontal_dark);
|
|
|
|
LinearLayout dest = (LinearLayout)findViewById(R.id.tab_addons_addons);
|
|
dest.addView(separator);
|
|
view.apply(TaskEditActivity.this, dest);
|
|
|
|
} catch (Exception e) {
|
|
exceptionService.reportError("receive-detail-" + //$NON-NLS-1$
|
|
intent.getStringExtra(AstridApiConstants.EXTRAS_ADDON), e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ======================================================================
|
|
* ======================================================= event handlers
|
|
* ====================================================================== */
|
|
|
|
protected void saveButtonClick() {
|
|
setResult(RESULT_OK);
|
|
finish();
|
|
}
|
|
|
|
/**
|
|
* Displays a Toast reporting that the selected task has been saved and, if
|
|
* it has a due date, that is due in 'x' amount of time, to 1 time-unit of
|
|
* precision
|
|
* @param additionalMessage
|
|
*/
|
|
private void showSaveToast(String additionalMessage) {
|
|
int stringResource;
|
|
|
|
long due = model.getValue(Task.DUE_DATE);
|
|
String toastMessage;
|
|
if (due != 0) {
|
|
stringResource = R.string.TEA_onTaskSave_due;
|
|
CharSequence formattedDate =
|
|
DateUtils.getRelativeTimeSpanString(due);
|
|
toastMessage = getString(stringResource, formattedDate);
|
|
} else {
|
|
toastMessage = getString(R.string.TEA_onTaskSave_notDue);
|
|
}
|
|
|
|
int length = additionalMessage.length() == 0 ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG;
|
|
Toast.makeText(this,
|
|
toastMessage + additionalMessage,
|
|
length).show();
|
|
}
|
|
|
|
protected void discardButtonClick() {
|
|
shouldSaveState = false;
|
|
|
|
// abandon editing in this case
|
|
if(title.getText().length() == 0) {
|
|
if(isNewTask)
|
|
taskService.delete(model);
|
|
}
|
|
|
|
showCancelToast();
|
|
setResult(RESULT_CANCELED);
|
|
finish();
|
|
}
|
|
|
|
/**
|
|
* Show toast for task edit canceling
|
|
*/
|
|
private void showCancelToast() {
|
|
Toast.makeText(this, R.string.TEA_onTaskCancel,
|
|
Toast.LENGTH_SHORT).show();
|
|
}
|
|
|
|
protected void deleteButtonClick() {
|
|
new AlertDialog.Builder(this)
|
|
.setTitle(R.string.DLG_confirm_title)
|
|
.setMessage(R.string.DLG_delete_this_task_question)
|
|
.setIcon(android.R.drawable.ic_dialog_alert)
|
|
.setPositiveButton(android.R.string.ok,
|
|
new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
taskService.delete(model);
|
|
shouldSaveState = false;
|
|
showDeleteToast();
|
|
setResult(RESULT_CANCELED);
|
|
finish();
|
|
}
|
|
})
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
.show();
|
|
}
|
|
|
|
/**
|
|
* Show toast for task edit deleting
|
|
*/
|
|
private void showDeleteToast() {
|
|
Toast.makeText(this, R.string.TEA_onTaskDelete,
|
|
Toast.LENGTH_SHORT).show();
|
|
}
|
|
|
|
@Override
|
|
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
|
switch(item.getItemId()) {
|
|
case MENU_SAVE_ID:
|
|
saveButtonClick();
|
|
return true;
|
|
case MENU_DISCARD_ID:
|
|
discardButtonClick();
|
|
return true;
|
|
case MENU_DELETE_ID:
|
|
deleteButtonClick();
|
|
return true;
|
|
}
|
|
|
|
return super.onMenuItemSelected(featureId, item);
|
|
}
|
|
|
|
@Override
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
super.onCreateOptionsMenu(menu);
|
|
MenuItem item;
|
|
|
|
item = menu.add(Menu.NONE, MENU_SAVE_ID, 0, R.string.TEA_menu_save);
|
|
item.setIcon(android.R.drawable.ic_menu_save);
|
|
|
|
item = menu.add(Menu.NONE, MENU_DISCARD_ID, 0, R.string.TEA_menu_discard);
|
|
item.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
|
|
|
|
item = menu.add(Menu.NONE, MENU_DELETE_ID, 0, R.string.TEA_menu_delete);
|
|
item.setIcon(android.R.drawable.ic_menu_delete);
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected void onPause() {
|
|
super.onPause();
|
|
unregisterReceiver(controlReceiver);
|
|
|
|
if(shouldSaveState)
|
|
save();
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
registerReceiver(controlReceiver,
|
|
new IntentFilter(AstridApiConstants.BROADCAST_SEND_EDIT_CONTROLS));
|
|
populateFields();
|
|
}
|
|
|
|
@Override
|
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
// handle the result of voice recognition, put it into the appropiate textfield
|
|
voiceNoteAssistant.handleActivityResult(requestCode, resultCode, data);
|
|
|
|
// write the voicenote into the model, or it will be deleted by onResume.populateFields
|
|
// (due to the activity-change)
|
|
notesControlSet.writeToModel(model);
|
|
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
}
|
|
|
|
@Override
|
|
protected void onSaveInstanceState(Bundle outState) {
|
|
super.onSaveInstanceState(outState);
|
|
|
|
// stick our task into the outState
|
|
outState.putParcelable(TASK_IN_PROGRESS, model);
|
|
}
|
|
|
|
@Override
|
|
protected void onRestoreInstanceState(Bundle inState) {
|
|
super.onRestoreInstanceState(inState);
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
super.onStart();
|
|
StatisticsService.sessionStart(this);
|
|
}
|
|
|
|
@Override
|
|
protected void onStop() {
|
|
super.onStop();
|
|
StatisticsService.sessionStop(this);
|
|
}
|
|
|
|
/* ======================================================================
|
|
* ========================================== UI component helper classes
|
|
* ====================================================================== */
|
|
|
|
// --- interface
|
|
|
|
/**
|
|
* Interface for working with controls that alter task data
|
|
*/
|
|
public interface TaskEditControlSet {
|
|
/**
|
|
* Read data from model to update the control set
|
|
*/
|
|
public void readFromTask(Task task);
|
|
|
|
/**
|
|
* Write data from control set to model
|
|
* @return text appended to the toast
|
|
*/
|
|
public String writeToModel(Task task);
|
|
}
|
|
|
|
// --- EditTextControlSet
|
|
|
|
/**
|
|
* Control set for mapping a Property to an EditText
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
public class EditTextControlSet implements TaskEditControlSet {
|
|
private final EditText editText;
|
|
private final StringProperty property;
|
|
|
|
public EditTextControlSet(StringProperty property, int editText) {
|
|
this.property = property;
|
|
this.editText = (EditText)findViewById(editText);
|
|
}
|
|
|
|
@Override
|
|
public void readFromTask(Task task) {
|
|
editText.setText(task.getValue(property));
|
|
}
|
|
|
|
@Override
|
|
public String writeToModel(Task task) {
|
|
task.setValue(property, editText.getText().toString());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// --- ImportanceControlSet
|
|
|
|
/**
|
|
* Control Set for setting task importance
|
|
*
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
public class ImportanceControlSet implements TaskEditControlSet {
|
|
private final List<CompoundButton> buttons = new LinkedList<CompoundButton>();
|
|
private final int[] colors = Task.getImportanceColors(getResources());
|
|
|
|
public ImportanceControlSet(int containerId) {
|
|
LinearLayout layout = (LinearLayout)findViewById(containerId);
|
|
|
|
int min = Task.IMPORTANCE_MOST;
|
|
int max = Task.IMPORTANCE_LEAST;
|
|
if(ProducteevUtilities.INSTANCE.isLoggedIn() || OpencrxCoreUtils.INSTANCE.isLoggedIn())
|
|
max = 5;
|
|
|
|
for(int i = min; i <= max; i++) {
|
|
final ToggleButton button = new ToggleButton(TaskEditActivity.this);
|
|
button.setLayoutParams(new LinearLayout.LayoutParams(
|
|
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1));
|
|
|
|
StringBuilder label = new StringBuilder();
|
|
if(ProducteevUtilities.INSTANCE.isLoggedIn() || OpencrxCoreUtils.INSTANCE.isLoggedIn())
|
|
label.append(5 - i).append("\n\u2605"); //$NON-NLS-1$
|
|
else {
|
|
for(int j = Task.IMPORTANCE_LEAST; j >= i; j--)
|
|
label.append('!');
|
|
}
|
|
|
|
button.setTextColor(colors[i]);
|
|
button.setTextOff(label);
|
|
button.setTextOn(label);
|
|
|
|
button.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
setImportance((Integer)button.getTag());
|
|
}
|
|
});
|
|
button.setTag(i);
|
|
|
|
buttons.add(button);
|
|
layout.addView(button);
|
|
}
|
|
}
|
|
|
|
public void setImportance(Integer i) {
|
|
for(CompoundButton b : buttons) {
|
|
if(b.getTag() == i) {
|
|
b.setTextSize(24);
|
|
b.setChecked(true);
|
|
b.setBackgroundResource(R.drawable.btn_selected);
|
|
} else {
|
|
b.setTextSize(16);
|
|
b.setChecked(false);
|
|
b.setBackgroundResource(android.R.drawable.btn_default);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Integer getImportance() {
|
|
for(CompoundButton b : buttons)
|
|
if(b.isChecked())
|
|
return (Integer) b.getTag();
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void readFromTask(Task task) {
|
|
setImportance(task.getValue(Task.IMPORTANCE));
|
|
}
|
|
|
|
@Override
|
|
public String writeToModel(Task task) {
|
|
if(getImportance() != null)
|
|
task.setValue(Task.IMPORTANCE, getImportance());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// --- UrgencyControlSet
|
|
|
|
private class UrgencyControlSet implements TaskEditControlSet,
|
|
OnItemSelectedListener, OnDeadlineTimeSetListener,
|
|
OnCancelListener {
|
|
|
|
private static final int SPECIFIC_DATE = -1;
|
|
private static final int EXISTING_TIME_UNSET = -2;
|
|
|
|
private final Spinner spinner;
|
|
private ArrayAdapter<UrgencyValue> urgencyAdapter;
|
|
private int previousSetting = Task.URGENCY_NONE;
|
|
|
|
private long existingDate = EXISTING_TIME_UNSET;
|
|
private int existingDateHour = EXISTING_TIME_UNSET;
|
|
private int existingDateMinutes = EXISTING_TIME_UNSET;
|
|
|
|
/**
|
|
* Container class for urgencies
|
|
*
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
private class UrgencyValue {
|
|
public String label;
|
|
public int setting;
|
|
public long dueDate;
|
|
|
|
public UrgencyValue(String label, int setting) {
|
|
this.label = label;
|
|
this.setting = setting;
|
|
dueDate = model.createDueDate(setting, 0);
|
|
}
|
|
|
|
public UrgencyValue(String label, int setting, long dueDate) {
|
|
this.label = label;
|
|
this.setting = setting;
|
|
this.dueDate = dueDate;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return label;
|
|
}
|
|
}
|
|
|
|
public UrgencyControlSet(int urgency) {
|
|
this.spinner = (Spinner)findViewById(urgency);
|
|
this.spinner.setOnItemSelectedListener(this);
|
|
}
|
|
|
|
/**
|
|
* set up urgency adapter and picks the right selected item
|
|
* @param dueDate
|
|
*/
|
|
private void createUrgencyList(long dueDate) {
|
|
// set up base urgency list
|
|
String[] labels = getResources().getStringArray(R.array.TEA_urgency);
|
|
UrgencyValue[] urgencyValues = new UrgencyValue[labels.length];
|
|
urgencyValues[0] = new UrgencyValue(labels[0],
|
|
Task.URGENCY_SPECIFIC_DAY_TIME, SPECIFIC_DATE);
|
|
urgencyValues[1] = new UrgencyValue(labels[1],
|
|
Task.URGENCY_TODAY);
|
|
urgencyValues[2] = new UrgencyValue(labels[2],
|
|
Task.URGENCY_TOMORROW);
|
|
String dayAfterTomorrow = DateUtils.getDayOfWeekString(
|
|
new Date(DateUtilities.now() + 2 * DateUtilities.ONE_DAY).getDay() +
|
|
Calendar.SUNDAY, DateUtils.LENGTH_LONG);
|
|
urgencyValues[3] = new UrgencyValue(dayAfterTomorrow,
|
|
Task.URGENCY_DAY_AFTER);
|
|
urgencyValues[4] = new UrgencyValue(labels[4],
|
|
Task.URGENCY_NEXT_WEEK);
|
|
urgencyValues[5] = new UrgencyValue(labels[5],
|
|
Task.URGENCY_NONE);
|
|
|
|
// search for setting
|
|
int selection = -1;
|
|
for(int i = 0; i < urgencyValues.length; i++)
|
|
if(urgencyValues[i].dueDate == dueDate) {
|
|
selection = i;
|
|
if(dueDate > 0)
|
|
existingDate = dueDate;
|
|
break;
|
|
}
|
|
|
|
if(selection == -1) {
|
|
UrgencyValue[] updated = new UrgencyValue[labels.length + 1];
|
|
for(int i = 0; i < labels.length; i++)
|
|
updated[i+1] = urgencyValues[i];
|
|
if(Task.hasDueTime(dueDate)) {
|
|
Date dueDateAsDate = new Date(dueDate);
|
|
updated[0] = new UrgencyValue(DateUtilities.getDateStringWithTime(TaskEditActivity.this, dueDateAsDate),
|
|
Task.URGENCY_SPECIFIC_DAY_TIME, dueDate);
|
|
existingDate = dueDate;
|
|
existingDateHour = dueDateAsDate.getHours();
|
|
existingDateMinutes = dueDateAsDate.getMinutes();
|
|
} else {
|
|
updated[0] = new UrgencyValue(DateUtilities.getDateString(TaskEditActivity.this, new Date(dueDate)),
|
|
Task.URGENCY_SPECIFIC_DAY, dueDate);
|
|
existingDate = dueDate;
|
|
existingDateHour = SPECIFIC_DATE;
|
|
}
|
|
selection = 0;
|
|
urgencyValues = updated;
|
|
}
|
|
|
|
urgencyAdapter = new ArrayAdapter<UrgencyValue>(
|
|
TaskEditActivity.this, android.R.layout.simple_spinner_item,
|
|
urgencyValues);
|
|
urgencyAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
this.spinner.setAdapter(urgencyAdapter);
|
|
this.spinner.setSelection(selection);
|
|
}
|
|
|
|
// --- listening for events
|
|
|
|
@Override
|
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
// if specific date or date & time selected, show dialog
|
|
// ... at conclusion of dialog, update our list
|
|
UrgencyValue item = urgencyAdapter.getItem(position);
|
|
if(item.dueDate == SPECIFIC_DATE) {
|
|
customSetting = item.setting;
|
|
customDate = new Date(existingDate == EXISTING_TIME_UNSET ? DateUtilities.now() : existingDate);
|
|
customDate.setSeconds(0);
|
|
/***** Calendar Dialog Changes -- Start *****/
|
|
final CalendarDialog calendarDialog = new CalendarDialog(TaskEditActivity.this, customDate);
|
|
calendarDialog.show();
|
|
calendarDialog.setOnDismissListener(new OnDismissListener() {
|
|
@Override
|
|
public void onDismiss(DialogInterface arg0) {
|
|
if (!cancelled) {
|
|
setDate(calendarDialog);
|
|
}
|
|
cancelled = false;
|
|
}
|
|
});
|
|
|
|
calendarDialog.setOnCancelListener(new OnCancelListener() {
|
|
@Override
|
|
public void onCancel(DialogInterface arg0) {
|
|
cancelled = true;
|
|
}
|
|
});
|
|
/***** Calendar Dialog Changes -- End *****/
|
|
|
|
spinner.setSelection(previousSetting);
|
|
} else {
|
|
previousSetting = position;
|
|
model.setValue(Task.DUE_DATE, item.dueDate);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onNothingSelected(AdapterView<?> arg0) {
|
|
// ignore
|
|
}
|
|
|
|
Date customDate;
|
|
int customSetting;
|
|
|
|
private void setDate(CalendarDialog calendarDialog) {
|
|
customDate = calendarDialog.getCalendarDate();
|
|
customDate.setMinutes(0);
|
|
|
|
if(customSetting != Task.URGENCY_SPECIFIC_DAY_TIME) {
|
|
customDateFinished();
|
|
return;
|
|
}
|
|
|
|
boolean specificTime = existingDateHour != SPECIFIC_DATE;
|
|
if(existingDateHour < 0) {
|
|
existingDateHour = customDate.getHours();
|
|
existingDateMinutes= customDate.getMinutes();
|
|
}
|
|
|
|
DeadlineTimePickerDialog timePicker = new DeadlineTimePickerDialog(TaskEditActivity.this, this,
|
|
existingDateHour, existingDateMinutes,
|
|
DateUtilities.is24HourFormat(TaskEditActivity.this),
|
|
specificTime);
|
|
|
|
timePicker.setOnCancelListener(this);
|
|
timePicker.show();
|
|
}
|
|
|
|
public void onTimeSet(TimePicker view, boolean hasTime, int hourOfDay, int minute) {
|
|
if(!hasTime)
|
|
customSetting = Task.URGENCY_SPECIFIC_DAY;
|
|
else {
|
|
customDate.setHours(hourOfDay);
|
|
customDate.setMinutes(minute);
|
|
existingDateHour = hourOfDay;
|
|
existingDateMinutes = minute;
|
|
}
|
|
customDateFinished();
|
|
}
|
|
|
|
@Override
|
|
public void onCancel(DialogInterface dialog) {
|
|
// user canceled, restore previous choice
|
|
spinner.setSelection(previousSetting);
|
|
}
|
|
|
|
private void customDateFinished() {
|
|
long time = model.createDueDate(customSetting, customDate.getTime());
|
|
model.setValue(Task.DUE_DATE, time);
|
|
createUrgencyList(time);
|
|
}
|
|
|
|
// --- setting up values
|
|
|
|
@Override
|
|
public void readFromTask(Task task) {
|
|
long dueDate = task.getValue(Task.DUE_DATE);
|
|
createUrgencyList(dueDate);
|
|
}
|
|
|
|
@Override
|
|
public String writeToModel(Task task) {
|
|
UrgencyValue item = urgencyAdapter.getItem(spinner.getSelectedItemPosition());
|
|
if(item.dueDate != SPECIFIC_DATE) // user canceled specific date
|
|
task.setValue(Task.DUE_DATE, item.dueDate);
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Control set for specifying when a task should be hidden
|
|
*
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
private class HideUntilControlSet implements TaskEditControlSet,
|
|
OnItemSelectedListener, OnCancelListener,
|
|
OnDeadlineTimeSetListener {
|
|
|
|
private static final int SPECIFIC_DATE = -1;
|
|
private static final int EXISTING_TIME_UNSET = -2;
|
|
|
|
private final Spinner spinner;
|
|
private int previousSetting = Task.HIDE_UNTIL_NONE;
|
|
|
|
private long existingDate = EXISTING_TIME_UNSET;
|
|
private int existingDateHour = EXISTING_TIME_UNSET;
|
|
private int existingDateMinutes = EXISTING_TIME_UNSET;
|
|
|
|
public HideUntilControlSet(int hideUntil) {
|
|
this.spinner = (Spinner) findViewById(hideUntil);
|
|
this.spinner.setOnItemSelectedListener(this);
|
|
}
|
|
|
|
private ArrayAdapter<HideUntilValue> adapter;
|
|
|
|
/**
|
|
* Container class for urgencies
|
|
*
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
private class HideUntilValue {
|
|
public String label;
|
|
public int setting;
|
|
public long date;
|
|
|
|
public HideUntilValue(String label, int setting) {
|
|
this(label, setting, 0);
|
|
}
|
|
|
|
public HideUntilValue(String label, int setting, long date) {
|
|
this.label = label;
|
|
this.setting = setting;
|
|
this.date = date;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return label;
|
|
}
|
|
}
|
|
|
|
private HideUntilValue[] createHideUntilList(long specificDate) {
|
|
// set up base values
|
|
String[] labels = getResources().getStringArray(R.array.TEA_hideUntil);
|
|
HideUntilValue[] values = new HideUntilValue[labels.length];
|
|
values[0] = new HideUntilValue(labels[0], Task.HIDE_UNTIL_NONE);
|
|
values[1] = new HideUntilValue(labels[1], Task.HIDE_UNTIL_DUE);
|
|
values[2] = new HideUntilValue(labels[2], Task.HIDE_UNTIL_DAY_BEFORE);
|
|
values[3] = new HideUntilValue(labels[3], Task.HIDE_UNTIL_WEEK_BEFORE);
|
|
values[4] = new HideUntilValue(labels[4], Task.HIDE_UNTIL_SPECIFIC_DAY, -1);
|
|
|
|
if(specificDate > 0) {
|
|
HideUntilValue[] updated = new HideUntilValue[values.length + 1];
|
|
for(int i = 0; i < values.length; i++)
|
|
updated[i+1] = values[i];
|
|
Date hideUntilAsDate = new Date(specificDate);
|
|
if(hideUntilAsDate.getHours() == 0 && hideUntilAsDate.getMinutes() == 0 && hideUntilAsDate.getSeconds() == 0) {
|
|
updated[0] = new HideUntilValue(DateUtilities.getDateString(TaskEditActivity.this, new Date(specificDate)),
|
|
Task.HIDE_UNTIL_SPECIFIC_DAY, specificDate);
|
|
existingDate = specificDate;
|
|
existingDateHour = SPECIFIC_DATE;
|
|
} else {
|
|
updated[0] = new HideUntilValue(DateUtilities.getDateStringWithTime(TaskEditActivity.this, new Date(specificDate)),
|
|
Task.HIDE_UNTIL_SPECIFIC_DAY_TIME, specificDate);
|
|
existingDate = specificDate;
|
|
existingDateHour = hideUntilAsDate.getHours();
|
|
existingDateMinutes = hideUntilAsDate.getMinutes();
|
|
}
|
|
values = updated;
|
|
}
|
|
|
|
return values;
|
|
}
|
|
|
|
// --- listening for events
|
|
|
|
@Override
|
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
// if specific date selected, show dialog
|
|
// ... at conclusion of dialog, update our list
|
|
HideUntilValue item = adapter.getItem(position);
|
|
if(item.date == SPECIFIC_DATE) {
|
|
customDate = new Date(existingDate == EXISTING_TIME_UNSET ? DateUtilities.now() : existingDate);
|
|
customDate.setSeconds(0);
|
|
|
|
/***** Calendar Dialog Changes -- Start *****/
|
|
final CalendarDialog calendarDialog = new CalendarDialog(TaskEditActivity.this, customDate);
|
|
calendarDialog.show();
|
|
calendarDialog.setOnDismissListener(new OnDismissListener() {
|
|
@Override
|
|
public void onDismiss(DialogInterface arg0) {
|
|
if (!cancelled) {
|
|
setDate(calendarDialog);
|
|
}
|
|
cancelled = false;
|
|
}
|
|
});
|
|
|
|
calendarDialog.setOnCancelListener(new OnCancelListener() {
|
|
@Override
|
|
public void onCancel(DialogInterface arg0) {
|
|
cancelled = true;
|
|
}
|
|
});
|
|
/***** Calendar Dialog Changes -- End *****/
|
|
/*DatePickerDialog datePicker = new DatePickerDialog(TaskEditActivity.this,
|
|
this, 1900 + customDate.getYear(), customDate.getMonth(), customDate.getDate());
|
|
datePicker.setOnCancelListener(this);
|
|
datePicker.show();*/
|
|
|
|
spinner.setSelection(previousSetting);
|
|
} else {
|
|
previousSetting = position;
|
|
model.setValue(Task.HIDE_UNTIL, item.date);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onNothingSelected(AdapterView<?> arg0) {
|
|
// ignore
|
|
}
|
|
|
|
Date customDate;
|
|
|
|
private void setDate(CalendarDialog calendarDialog) {
|
|
customDate = calendarDialog.getCalendarDate();
|
|
|
|
boolean specificTime = existingDateHour != SPECIFIC_DATE;
|
|
if(existingDateHour < 0) {
|
|
existingDateHour = customDate.getHours();
|
|
existingDateMinutes= customDate.getMinutes();
|
|
}
|
|
|
|
DeadlineTimePickerDialog timePicker = new DeadlineTimePickerDialog(TaskEditActivity.this, this,
|
|
existingDateHour, existingDateMinutes,
|
|
DateUtilities.is24HourFormat(TaskEditActivity.this),
|
|
specificTime);
|
|
|
|
timePicker.setOnCancelListener(this);
|
|
timePicker.show();
|
|
}
|
|
|
|
/*public void onDateSet(DatePicker view, int year, int month, int monthDay) {
|
|
customDate.setYear(year - 1900);
|
|
customDate.setMonth(month);
|
|
customDate.setDate(monthDay);
|
|
|
|
boolean specificTime = existingDateHour != SPECIFIC_DATE;
|
|
if(existingDateHour < 0) {
|
|
existingDateHour = customDate.getHours();
|
|
existingDateMinutes= customDate.getMinutes();
|
|
}
|
|
|
|
DeadlineTimePickerDialog timePicker = new DeadlineTimePickerDialog(TaskEditActivity.this, this,
|
|
existingDateHour, existingDateMinutes,
|
|
DateUtilities.is24HourFormat(TaskEditActivity.this),
|
|
specificTime);
|
|
|
|
timePicker.setOnCancelListener(this);
|
|
timePicker.show();
|
|
}*/
|
|
|
|
public void onTimeSet(TimePicker view, boolean hasTime, int hourOfDay, int minute) {
|
|
if(!hasTime) {
|
|
customDate.setHours(0);
|
|
customDate.setMinutes(0);
|
|
customDate.setSeconds(0);
|
|
} else {
|
|
customDate.setHours(hourOfDay);
|
|
customDate.setMinutes(minute);
|
|
existingDateHour = hourOfDay;
|
|
existingDateMinutes = minute;
|
|
}
|
|
customDateFinished();
|
|
}
|
|
|
|
@Override
|
|
public void onCancel(DialogInterface dialog) {
|
|
// user canceled, restore previous choice
|
|
spinner.setSelection(previousSetting);
|
|
}
|
|
|
|
private void customDateFinished() {
|
|
HideUntilValue[] list = createHideUntilList(customDate.getTime());
|
|
adapter = new ArrayAdapter<HideUntilValue>(
|
|
TaskEditActivity.this, android.R.layout.simple_spinner_item,
|
|
list);
|
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
spinner.setAdapter(adapter);
|
|
spinner.setSelection(0);
|
|
}
|
|
|
|
// --- setting up values
|
|
|
|
@Override
|
|
public void readFromTask(Task task) {
|
|
long date = task.getValue(Task.HIDE_UNTIL);
|
|
|
|
Date dueDay = new Date(task.getValue(Task.DUE_DATE)/1000L*1000L);
|
|
dueDay.setHours(0);
|
|
dueDay.setMinutes(0);
|
|
dueDay.setSeconds(0);
|
|
|
|
int selection = 0;
|
|
if(date == 0) {
|
|
selection = 0;
|
|
date = 0;
|
|
} else if(date == dueDay.getTime()) {
|
|
selection = 1;
|
|
date = 0;
|
|
} else if(date + DateUtilities.ONE_DAY == dueDay.getTime()) {
|
|
selection = 2;
|
|
date = 0;
|
|
} else if(date + DateUtilities.ONE_WEEK == dueDay.getTime()) {
|
|
selection = 3;
|
|
date = 0;
|
|
}
|
|
|
|
HideUntilValue[] list = createHideUntilList(date);
|
|
adapter = new ArrayAdapter<HideUntilValue>(
|
|
TaskEditActivity.this, android.R.layout.simple_spinner_item, list);
|
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
spinner.setAdapter(adapter);
|
|
|
|
spinner.setSelection(selection);
|
|
}
|
|
|
|
@Override
|
|
public String writeToModel(Task task) {
|
|
if(adapter == null || spinner == null)
|
|
return null;
|
|
HideUntilValue item = adapter.getItem(spinner.getSelectedItemPosition());
|
|
if(item == null)
|
|
return null;
|
|
long value = task.createHideUntil(item.setting, item.date);
|
|
task.setValue(Task.HIDE_UNTIL, value);
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Control set dealing with reminder settings
|
|
*
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
public class ReminderControlSet implements TaskEditControlSet {
|
|
private final CheckBox during, after;
|
|
private final Spinner mode;
|
|
|
|
public ReminderControlSet(int duringId, int afterId, int modeId) {
|
|
during = (CheckBox)findViewById(duringId);
|
|
after = (CheckBox)findViewById(afterId);
|
|
mode = (Spinner)findViewById(modeId);
|
|
|
|
String[] list = new String[] {
|
|
getString(R.string.TEA_reminder_mode_once),
|
|
getString(R.string.TEA_reminder_mode_five),
|
|
getString(R.string.TEA_reminder_mode_nonstop),
|
|
};
|
|
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
|
|
TaskEditActivity.this, android.R.layout.simple_spinner_item, list);
|
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
runOnUiThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
mode.setAdapter(adapter);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void setValue(int flags) {
|
|
during.setChecked((flags & Task.NOTIFY_AT_DEADLINE) > 0);
|
|
after.setChecked((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);
|
|
}
|
|
|
|
public int getValue() {
|
|
int value = 0;
|
|
if(during.isChecked())
|
|
value |= Task.NOTIFY_AT_DEADLINE;
|
|
if(after.isChecked())
|
|
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;
|
|
}
|
|
|
|
@Override
|
|
public void readFromTask(Task task) {
|
|
setValue(task.getValue(Task.REMINDER_FLAGS));
|
|
}
|
|
|
|
@Override
|
|
public String writeToModel(Task task) {
|
|
task.setValue(Task.REMINDER_FLAGS, getValue());
|
|
// clear snooze if task is being edited
|
|
task.setValue(Task.REMINDER_SNOOZE, 0L);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Control set dealing with random reminder settings
|
|
*
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
public class RandomReminderControlSet implements TaskEditControlSet {
|
|
/** default interval for spinner if date is unselected */
|
|
private final long DEFAULT_INTERVAL = DateUtilities.ONE_WEEK * 2;
|
|
|
|
private final CheckBox settingCheckbox;
|
|
private final Spinner periodSpinner;
|
|
|
|
private boolean periodSpinnerInitialized = false;
|
|
private final int[] hours;
|
|
|
|
public RandomReminderControlSet(int settingCheckboxId, int periodButtonId) {
|
|
settingCheckbox = (CheckBox)findViewById(settingCheckboxId);
|
|
periodSpinner = (Spinner)findViewById(periodButtonId);
|
|
periodSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
|
|
@Override
|
|
public void onItemSelected(AdapterView<?> arg0, View arg1,
|
|
int arg2, long arg3) {
|
|
if(periodSpinnerInitialized)
|
|
settingCheckbox.setChecked(true);
|
|
periodSpinnerInitialized = true;
|
|
}
|
|
|
|
@Override
|
|
public void onNothingSelected(AdapterView<?> arg0) {
|
|
// ignore
|
|
}
|
|
});
|
|
|
|
// create adapter
|
|
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
|
|
TaskEditActivity.this, android.R.layout.simple_spinner_item,
|
|
getResources().getStringArray(R.array.TEA_reminder_random));
|
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
periodSpinner.setAdapter(adapter);
|
|
|
|
// create hour array
|
|
String[] hourStrings = getResources().getStringArray(R.array.TEA_reminder_random_hours);
|
|
hours = new int[hourStrings.length];
|
|
for(int i = 0; i < hours.length; i++)
|
|
hours[i] = Integer.parseInt(hourStrings[i]);
|
|
}
|
|
|
|
@Override
|
|
public void readFromTask(Task task) {
|
|
long time = task.getValue(Task.REMINDER_PERIOD);
|
|
|
|
boolean enabled = time > 0;
|
|
if(time <= 0) {
|
|
time = DEFAULT_INTERVAL;
|
|
}
|
|
|
|
int i;
|
|
for(i = 0; i < hours.length - 1; i++)
|
|
if(hours[i] * DateUtilities.ONE_HOUR >= time)
|
|
break;
|
|
periodSpinner.setSelection(i);
|
|
settingCheckbox.setChecked(enabled);
|
|
}
|
|
|
|
@Override
|
|
public String writeToModel(Task task) {
|
|
if(settingCheckbox.isChecked()) {
|
|
int hourValue = hours[periodSpinner.getSelectedItemPosition()];
|
|
task.setValue(Task.REMINDER_PERIOD, hourValue * DateUtilities.ONE_HOUR);
|
|
} else
|
|
task.setValue(Task.REMINDER_PERIOD, 0L);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
}
|