Refactored Task Edit page into four tabs and added styling
- added sharing tab from edit people activity - changed due date picker into two buttons - refactored Task Edit Activity into multiple smaller files - new UI elements for save/cancel buttons, tabs, and other small partspull/14/head
After Width: | Height: | Size: 974 B |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 460 B |
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- Enabled states -->
|
||||||
|
|
||||||
|
<item android:state_checked="true" android:state_pressed="true"
|
||||||
|
android:state_enabled="true"
|
||||||
|
android:drawable="@android:drawable/checkbox_off_background" />
|
||||||
|
<item android:state_checked="false" android:state_pressed="true"
|
||||||
|
android:state_enabled="true"
|
||||||
|
android:drawable="@android:drawable/checkbox_on_background" />
|
||||||
|
|
||||||
|
<item android:state_checked="false"
|
||||||
|
android:state_enabled="true"
|
||||||
|
android:drawable="@android:drawable/checkbox_off_background" />
|
||||||
|
<item android:state_checked="true"
|
||||||
|
android:state_enabled="true"
|
||||||
|
android:drawable="@android:drawable/checkbox_on_background" />
|
||||||
|
|
||||||
|
</selector>
|
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/btn_dismiss_pressed" />
|
||||||
|
<item android:drawable="@drawable/btn_dismiss_normal" />
|
||||||
|
|
||||||
|
</selector>
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 997 B After Width: | Height: | Size: 983 B |
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/footer_greenbtn_pressed" />
|
||||||
|
<item android:drawable="@drawable/footer_greenbtn_normal" />
|
||||||
|
|
||||||
|
</selector>
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 849 B |
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/footer_redbtn_pressed" />
|
||||||
|
<item android:drawable="@drawable/footer_redbtn_normal" />
|
||||||
|
|
||||||
|
</selector>
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 876 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 650 B |
After Width: | Height: | Size: 290 B |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:startColor="#008d43"
|
||||||
|
android:endColor="#00522b"/>
|
||||||
|
</shape>
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.todoroo.astrid.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.data.Property.StringProperty;
|
||||||
|
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(Activity activity, StringProperty property, int editText) {
|
||||||
|
this.property = property;
|
||||||
|
this.editText = (EditText)activity.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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,251 @@
|
|||||||
|
package com.todoroo.astrid.ui;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
|
import android.content.DialogInterface.OnDismissListener;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TimePicker;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.andlib.utility.DateUtilities;
|
||||||
|
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
import com.todoroo.astrid.ui.DeadlineTimePickerDialog.OnDeadlineTimeSetListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control set for specifying when a task should be hidden
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public 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;
|
||||||
|
|
||||||
|
private final Activity activity;
|
||||||
|
private boolean cancelled = false;
|
||||||
|
|
||||||
|
public HideUntilControlSet(Activity activity, int hideUntil) {
|
||||||
|
this.activity = activity;
|
||||||
|
this.spinner = (Spinner) activity.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 = activity.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(activity, new Date(specificDate)),
|
||||||
|
Task.HIDE_UNTIL_SPECIFIC_DAY, specificDate);
|
||||||
|
existingDate = specificDate;
|
||||||
|
existingDateHour = SPECIFIC_DATE;
|
||||||
|
} else {
|
||||||
|
updated[0] = new HideUntilValue(DateUtilities.getDateStringWithTime(activity, 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);
|
||||||
|
|
||||||
|
final CalendarDialog calendarDialog = new CalendarDialog(activity, 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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
spinner.setSelection(previousSetting);
|
||||||
|
} else {
|
||||||
|
previousSetting = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(activity, this,
|
||||||
|
existingDateHour, existingDateMinutes,
|
||||||
|
DateUtilities.is24HourFormat(activity),
|
||||||
|
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>(
|
||||||
|
activity, 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>(
|
||||||
|
activity, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
package com.todoroo.astrid.ui;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
import com.todoroo.astrid.opencrx.OpencrxCoreUtils;
|
||||||
|
import com.todoroo.astrid.producteev.ProducteevUtilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public ImportanceControlSet(Activity activity, int containerId) {
|
||||||
|
LinearLayout layout = (LinearLayout)activity.findViewById(containerId);
|
||||||
|
colors = Task.getImportanceColors(activity.getResources());
|
||||||
|
|
||||||
|
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(activity);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.todoroo.astrid.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.andlib.utility.DateUtilities;
|
||||||
|
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(Activity activity, int settingCheckboxId, int periodButtonId) {
|
||||||
|
settingCheckbox = (CheckBox)activity.findViewById(settingCheckboxId);
|
||||||
|
periodSpinner = (Spinner)activity.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>(
|
||||||
|
activity, android.R.layout.simple_spinner_item,
|
||||||
|
activity.getResources().getStringArray(R.array.TEA_reminder_random));
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
periodSpinner.setAdapter(adapter);
|
||||||
|
|
||||||
|
// create hour array
|
||||||
|
String[] hourStrings = activity.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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package com.todoroo.astrid.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(Activity activity, int duringId, int afterId, int modeId) {
|
||||||
|
during = (CheckBox)activity.findViewById(duringId);
|
||||||
|
after = (CheckBox)activity.findViewById(afterId);
|
||||||
|
mode = (Spinner)activity.findViewById(modeId);
|
||||||
|
|
||||||
|
String[] list = new String[] {
|
||||||
|
activity.getString(R.string.TEA_reminder_mode_once),
|
||||||
|
activity.getString(R.string.TEA_reminder_mode_five),
|
||||||
|
activity.getString(R.string.TEA_reminder_mode_nonstop),
|
||||||
|
};
|
||||||
|
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
|
||||||
|
activity, android.R.layout.simple_spinner_item, list);
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
activity.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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,275 @@
|
|||||||
|
package com.todoroo.astrid.ui;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
|
import android.content.DialogInterface.OnDismissListener;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TimePicker;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.andlib.utility.DateUtilities;
|
||||||
|
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
import com.todoroo.astrid.ui.DeadlineTimePickerDialog.OnDeadlineTimeSetListener;
|
||||||
|
|
||||||
|
public class UrgencyControlSet implements TaskEditControlSet,
|
||||||
|
OnDeadlineTimeSetListener {
|
||||||
|
|
||||||
|
private static final int SPECIFIC_DATE = -1;
|
||||||
|
|
||||||
|
private final Button dateButton;
|
||||||
|
private final Button timeButton;
|
||||||
|
private ArrayAdapter<UrgencyValue> urgencyAdapter;
|
||||||
|
|
||||||
|
private final Activity activity;
|
||||||
|
|
||||||
|
private long dueDateValue = 0;
|
||||||
|
private long dueTimeValue = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = Task.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(Activity activity, int date, int time) {
|
||||||
|
this.activity = activity;
|
||||||
|
this.dateButton = (Button)activity.findViewById(date);
|
||||||
|
this.timeButton = (Button)activity.findViewById(time);
|
||||||
|
|
||||||
|
dateButton.setOnClickListener(dateButtonClick);
|
||||||
|
|
||||||
|
timeButton.setOnClickListener(timeButtonClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- events
|
||||||
|
|
||||||
|
View.OnClickListener dateButtonClick = new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
showUrgencySpinner(dueDateValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
View.OnClickListener timeButtonClick = new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
boolean hasTime = Task.hasDueTime(dueTimeValue);
|
||||||
|
int hour = 18, minute = 0;
|
||||||
|
if(hasTime) {
|
||||||
|
Date date = new Date(dueTimeValue);
|
||||||
|
hour = date.getHours();
|
||||||
|
minute = date.getMinutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeadlineTimePickerDialog timePicker = new DeadlineTimePickerDialog(activity,
|
||||||
|
UrgencyControlSet.this,
|
||||||
|
hour, minute,
|
||||||
|
DateUtilities.is24HourFormat(activity),
|
||||||
|
hasTime);
|
||||||
|
|
||||||
|
timePicker.show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set up urgency adapter and picks the right selected item
|
||||||
|
* @param dueDate
|
||||||
|
*/
|
||||||
|
private void showUrgencySpinner(long dueDate) {
|
||||||
|
// set up base urgency list
|
||||||
|
String[] labels = activity.getResources().getStringArray(R.array.TEA_urgency);
|
||||||
|
UrgencyValue[] urgencyValues = new UrgencyValue[labels.length];
|
||||||
|
urgencyValues[0] = new UrgencyValue(labels[0],
|
||||||
|
Task.URGENCY_NONE);
|
||||||
|
urgencyValues[1] = new UrgencyValue(labels[1],
|
||||||
|
Task.URGENCY_SPECIFIC_DAY_TIME, SPECIFIC_DATE);
|
||||||
|
urgencyValues[2] = new UrgencyValue(labels[2],
|
||||||
|
Task.URGENCY_TODAY);
|
||||||
|
urgencyValues[3] = new UrgencyValue(labels[3],
|
||||||
|
Task.URGENCY_TOMORROW);
|
||||||
|
String dayAfterTomorrow = DateUtils.getDayOfWeekString(
|
||||||
|
new Date(DateUtilities.now() + 2 * DateUtilities.ONE_DAY).getDay() +
|
||||||
|
Calendar.SUNDAY, DateUtils.LENGTH_LONG);
|
||||||
|
urgencyValues[4] = new UrgencyValue(dayAfterTomorrow,
|
||||||
|
Task.URGENCY_DAY_AFTER);
|
||||||
|
urgencyValues[5] = new UrgencyValue(labels[5],
|
||||||
|
Task.URGENCY_NEXT_WEEK);
|
||||||
|
urgencyValues[6] = new UrgencyValue(labels[6],
|
||||||
|
Task.URGENCY_IN_TWO_WEEKS);
|
||||||
|
urgencyValues[7] = new UrgencyValue(labels[7],
|
||||||
|
Task.URGENCY_NEXT_MONTH);
|
||||||
|
|
||||||
|
// search for setting
|
||||||
|
int selection = -1;
|
||||||
|
for(int i = 0; i < urgencyValues.length; i++)
|
||||||
|
if(urgencyValues[i].dueDate == dueDate) {
|
||||||
|
selection = i;
|
||||||
|
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(activity, dueDateAsDate),
|
||||||
|
Task.URGENCY_SPECIFIC_DAY_TIME, dueDate);
|
||||||
|
} else {
|
||||||
|
updated[0] = new UrgencyValue(DateUtilities.getDateString(activity, new Date(dueDate)),
|
||||||
|
Task.URGENCY_SPECIFIC_DAY, dueDate);
|
||||||
|
}
|
||||||
|
selection = 0;
|
||||||
|
urgencyValues = updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
urgencyAdapter = new ArrayAdapter<UrgencyValue>(
|
||||||
|
activity, android.R.layout.simple_dropdown_item_1line,
|
||||||
|
urgencyValues);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(activity)
|
||||||
|
.setTitle(R.string.TEA_urgency_label)
|
||||||
|
.setAdapter(urgencyAdapter, spinnerClickListener)
|
||||||
|
.setIcon(R.drawable.gl_date_blue)
|
||||||
|
.show().setOwnerActivity(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
DialogInterface.OnClickListener spinnerClickListener = new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int position) {
|
||||||
|
UrgencyValue item = urgencyAdapter.getItem(position);
|
||||||
|
if(item.dueDate == SPECIFIC_DATE) {
|
||||||
|
customSetting = item.setting;
|
||||||
|
Date date = new Date(dueDateValue == 0 ? DateUtilities.now() : dueDateValue);
|
||||||
|
date.setSeconds(0);
|
||||||
|
|
||||||
|
final CalendarDialog calendarDialog = new CalendarDialog(activity, date);
|
||||||
|
final AtomicBoolean cancelled = new AtomicBoolean(false);
|
||||||
|
calendarDialog.show();
|
||||||
|
calendarDialog.setOnDismissListener(new OnDismissListener() {
|
||||||
|
@Override
|
||||||
|
public void onDismiss(DialogInterface arg0) {
|
||||||
|
if (!cancelled.get())
|
||||||
|
setDateFromCalendar(calendarDialog);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
calendarDialog.setOnCancelListener(new OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface arg0) {
|
||||||
|
cancelled.set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dueDateValue = item.dueDate;
|
||||||
|
if(dueDateValue == 0)
|
||||||
|
dueTimeValue = 0;
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- date setting logic
|
||||||
|
|
||||||
|
int customSetting;
|
||||||
|
|
||||||
|
private void setDateFromCalendar(CalendarDialog calendarDialog) {
|
||||||
|
Date date = calendarDialog.getCalendarDate();
|
||||||
|
date.setMinutes(0);
|
||||||
|
dueDateValue = Task.createDueDate(customSetting, date.getTime());
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTimeSet(TimePicker view, boolean hasTime, int hourOfDay, int minute) {
|
||||||
|
if(!hasTime)
|
||||||
|
dueTimeValue = 0;
|
||||||
|
else {
|
||||||
|
Date date = new Date();
|
||||||
|
date.setHours(hourOfDay);
|
||||||
|
date.setMinutes(minute);
|
||||||
|
date.setSeconds(0);
|
||||||
|
dueTimeValue = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, date.getTime());
|
||||||
|
|
||||||
|
if(dueDateValue == 0)
|
||||||
|
dueDateValue = DateUtilities.now();
|
||||||
|
}
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateButtons() {
|
||||||
|
if(dueDateValue == 0) {
|
||||||
|
dateButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.gl_date, 0, 0, 0);
|
||||||
|
dateButton.setText(R.string.TEA_urgency_none);
|
||||||
|
} else {
|
||||||
|
dateButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.gl_date_blue, 0, 0, 0);
|
||||||
|
dateButton.setText(DateUtilities.getDateString(activity, new Date(dueDateValue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dueTimeValue == 0 || !Task.hasDueTime(dueTimeValue)) {
|
||||||
|
timeButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.gl_time, 0, 0, 0);
|
||||||
|
timeButton.setText(R.string.TEA_urgency_none);
|
||||||
|
} else {
|
||||||
|
timeButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.gl_time_blue, 0, 0, 0);
|
||||||
|
timeButton.setText(DateUtilities.getTimeString(activity, new Date(dueTimeValue)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- setting up values
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFromTask(Task task) {
|
||||||
|
dueTimeValue = dueDateValue = task.getValue(Task.DUE_DATE);
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String writeToModel(Task task) {
|
||||||
|
Date date = new Date(dueDateValue);
|
||||||
|
if(dueTimeValue > 0) {
|
||||||
|
Date time = new Date(dueTimeValue);
|
||||||
|
date.setHours(time.getHours());
|
||||||
|
date.setMinutes(time.getMinutes());
|
||||||
|
date.setSeconds(time.getSeconds());
|
||||||
|
} else {
|
||||||
|
date.setTime(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDateValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
task.setValue(Task.DUE_DATE, date.getTime());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|