mirror of https://github.com/tasks/tasks
Merge branch 'master' into dev
Conflicts: astrid/src/com/todoroo/astrid/adapter/TaskAdapter.javapull/14/head
commit
44e0f00b38
@ -0,0 +1,42 @@
|
||||
package com.todoroo.andlib.widget;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.gesture.Gesture;
|
||||
import android.gesture.GestureLibraries;
|
||||
import android.gesture.GestureLibrary;
|
||||
import android.gesture.GestureOverlayView;
|
||||
import android.gesture.Prediction;
|
||||
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
|
||||
|
||||
import com.todoroo.andlib.widget.GestureService.GestureInterface;
|
||||
|
||||
public class Api4GestureDetector implements OnGesturePerformedListener {
|
||||
private final GestureLibrary mLibrary;
|
||||
private final GestureInterface listener;
|
||||
|
||||
public Api4GestureDetector(Activity activity, int view, int gestureLibrary, GestureInterface listener) {
|
||||
this.listener = listener;
|
||||
mLibrary = GestureLibraries.fromRawResource(activity, gestureLibrary);
|
||||
|
||||
if(mLibrary.load()) {
|
||||
GestureOverlayView gestures = (GestureOverlayView) activity.findViewById(view);
|
||||
gestures.addOnGesturePerformedListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
|
||||
ArrayList<Prediction> predictions = mLibrary.recognize(gesture);
|
||||
|
||||
// We want at least one prediction
|
||||
if (predictions.size() > 0) {
|
||||
Prediction prediction = predictions.get(0);
|
||||
// We want at least some confidence in the result
|
||||
if (prediction.score > 1.0) {
|
||||
listener.gesturePerformed(prediction.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.todoroo.andlib.widget;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* All API versions-friendly gesture detector. On SDK < 4, nothing happens
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class GestureService {
|
||||
|
||||
public interface GestureInterface {
|
||||
public void gesturePerformed(String gesture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register gesture detector. If android SDK version is not correct,
|
||||
* a {@link VerifyError} will be throw. Catch this explicitly.
|
||||
*
|
||||
* @param activity
|
||||
* @param view
|
||||
* @param gestureLibrary
|
||||
* @param listener
|
||||
* @throws VerifyError
|
||||
*/
|
||||
public static void registerGestureDetector(Activity activity, int view,
|
||||
int gestureLibrary, GestureInterface listener) throws VerifyError {
|
||||
if(AndroidUtilities.getSdkVersion() > 3)
|
||||
new Api4GestureDetector(activity, view, gestureLibrary, listener);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,111 +1,34 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.alarms;
|
||||
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractModel;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Property.IntegerProperty;
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.andlib.data.Property.StringProperty;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
|
||||
/**
|
||||
* Data Model which represents an alarm
|
||||
* Metadata entry for a task alarm
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class Alarm extends AbstractModel {
|
||||
|
||||
// --- table
|
||||
|
||||
public static final Table TABLE = new Table("alarm", Alarm.class);
|
||||
public class Alarm {
|
||||
|
||||
// --- properties
|
||||
/** metadata key */
|
||||
public static final String METADATA_KEY = "alarm"; //$NON-NLS-1$
|
||||
|
||||
/** ID */
|
||||
public static final LongProperty ID = new LongProperty(
|
||||
TABLE, ID_PROPERTY_NAME);
|
||||
/** time of alarm */
|
||||
public static final LongProperty TIME = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE1.name);
|
||||
|
||||
/** Associated Task */
|
||||
public static final LongProperty TASK = new LongProperty(
|
||||
TABLE, "task");
|
||||
|
||||
/** Alarm Time */
|
||||
public static final LongProperty TIME = new LongProperty(
|
||||
TABLE, "time");
|
||||
|
||||
/** Alarm Type (see constants) */
|
||||
public static final IntegerProperty TYPE = new IntegerProperty(
|
||||
TABLE, "type");
|
||||
|
||||
/** Alarm Ringtone */
|
||||
public static final StringProperty RINGTONE = new StringProperty(
|
||||
TABLE, "ringtone");
|
||||
|
||||
/** List of all properties for this model */
|
||||
public static final Property<?>[] PROPERTIES = generateProperties(Alarm.class);
|
||||
/** alarm type */
|
||||
public static final IntegerProperty TYPE = new IntegerProperty(Metadata.TABLE,
|
||||
Metadata.VALUE2.name);
|
||||
|
||||
// --- constants
|
||||
|
||||
/** this alarm was already triggered */
|
||||
public static final int TYPE_TRIGGERED = 0;
|
||||
|
||||
/** this alarm is single-shot */
|
||||
public static final int TYPE_SINGLE = 1;
|
||||
|
||||
/** this alarm repeats itself until turned off */
|
||||
public static final int TYPE_REPEATING = 2;
|
||||
|
||||
// --- defaults
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
static {
|
||||
defaultValues.put(TYPE.name, TYPE_SINGLE);
|
||||
defaultValues.put(RINGTONE.name, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public Alarm() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Alarm(TodorooCursor<Alarm> cursor) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
public void readFromCursor(TodorooCursor<Alarm> cursor) {
|
||||
super.readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return getIdHelper(ID);
|
||||
};
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
private static final Creator<Task> CREATOR = new ModelCreator<Task>(Task.class);
|
||||
|
||||
@Override
|
||||
protected Creator<? extends AbstractModel> getCreator() {
|
||||
return CREATOR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
package com.todoroo.astrid.alarms;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.widget.DateControlSet;
|
||||
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
|
||||
/**
|
||||
* Control set to manage adding and removing tags
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public final class AlarmControlSet implements TaskEditControlSet {
|
||||
|
||||
// --- instance variables
|
||||
|
||||
private final LinearLayout alertsContainer;
|
||||
private final Activity activity;
|
||||
|
||||
public AlarmControlSet(Activity activity, ViewGroup parent) {
|
||||
View v = LayoutInflater.from(activity).inflate(R.layout.alarm_control, parent, true);
|
||||
|
||||
this.activity = activity;
|
||||
this.alertsContainer = (LinearLayout) v.findViewById(R.id.alert_container);
|
||||
v.findViewById(R.id.alarms_add).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
addAlarm(new Date());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromTask(Task task) {
|
||||
alertsContainer.removeAllViews();
|
||||
TodorooCursor<Metadata> cursor = AlarmService.getInstance().getAlarms(task.getId());
|
||||
try {
|
||||
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
|
||||
addAlarm(new Date(cursor.get(Alarm.TIME)));
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToModel(Task task) {
|
||||
LinkedHashSet<Long> alarms = new LinkedHashSet<Long>();
|
||||
for(int i = 0; i < alertsContainer.getChildCount(); i++) {
|
||||
DateControlSet set = (DateControlSet) alertsContainer.getChildAt(i).getTag();
|
||||
if(set == null)
|
||||
continue;
|
||||
Date date = set.getDate();
|
||||
if(date != null)
|
||||
alarms.add(set.getDate().getTime());
|
||||
}
|
||||
AlarmService.getInstance().synchronizeAlarms(task.getId(), alarms);
|
||||
}
|
||||
|
||||
private boolean addAlarm(Date alert) {
|
||||
final View alertItem = LayoutInflater.from(activity).inflate(R.layout.alarm_edit_row, null);
|
||||
alertsContainer.addView(alertItem);
|
||||
|
||||
DateControlSet dcs = new DateControlSet(activity, (Button)alertItem.findViewById(R.id.date),
|
||||
(Button)alertItem.findViewById(R.id.time));
|
||||
dcs.setDate(alert);
|
||||
alertItem.setTag(dcs);
|
||||
|
||||
ImageButton reminderRemoveButton;
|
||||
reminderRemoveButton = (ImageButton)alertItem.findViewById(R.id.button1);
|
||||
reminderRemoveButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
alertsContainer.removeView(alertItem);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.alarms;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.api.DetailExposer;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
|
||||
/**
|
||||
* Exposes Task Detail for tags, i.e. "Tags: frogs, animals"
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class AlarmDetailExposer extends BroadcastReceiver implements DetailExposer {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// get tags associated with this task
|
||||
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
|
||||
if(taskId == -1)
|
||||
return;
|
||||
|
||||
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
|
||||
String taskDetail = getTaskDetails(context, taskId, extended);
|
||||
if(taskDetail == null)
|
||||
return;
|
||||
|
||||
// transmit
|
||||
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, AlarmService.IDENTIFIER);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
|
||||
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTaskDetails(Context context, long id, boolean extended) {
|
||||
if(extended)
|
||||
return null;
|
||||
|
||||
TodorooCursor<Metadata> cursor = AlarmService.getInstance().getAlarms(id);
|
||||
long nextTime = -1;
|
||||
try {
|
||||
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
long time = cursor.get(Alarm.TIME);
|
||||
if(time > DateUtilities.now()) {
|
||||
nextTime = time;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nextTime == -1)
|
||||
return null;
|
||||
CharSequence durationString = DateUtils.getRelativeDateTimeString(context,
|
||||
nextTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS,
|
||||
DateUtils.FORMAT_ABBREV_ALL);
|
||||
return context.getString(R.string.alarm_ADE_detail, durationString);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginIdentifier() {
|
||||
return AlarmService.IDENTIFIER;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.todoroo.astrid.alarms;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
|
||||
public class AlarmTaskRepeatListener extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
|
||||
if(taskId == -1)
|
||||
return;
|
||||
|
||||
long oldDueDate = intent.getLongExtra(AstridApiConstants.EXTRAS_OLD_DUE_DATE, 0);
|
||||
if(oldDueDate == 0)
|
||||
oldDueDate = DateUtilities.now();
|
||||
long newDueDate = intent.getLongExtra(AstridApiConstants.EXTRAS_NEW_DUE_DATE, -1);
|
||||
if(newDueDate <= 0 || newDueDate <= oldDueDate)
|
||||
return;
|
||||
|
||||
TodorooCursor<Metadata> cursor = AlarmService.getInstance().getAlarms(taskId);
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return;
|
||||
|
||||
Metadata metadata = new Metadata();
|
||||
LinkedHashSet<Long> alarms = new LinkedHashSet<Long>(cursor.getCount());
|
||||
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
metadata.readFromCursor(cursor);
|
||||
alarms.add(metadata.getValue(Alarm.TIME) + (newDueDate - oldDueDate));
|
||||
}
|
||||
AlarmService.getInstance().synchronizeAlarms(taskId, alarms);
|
||||
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<TextView android:id="@+id/alarms_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/alarm_ACS_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
|
||||
<LinearLayout android:id="@+id/alert_container"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</LinearLayout>
|
||||
|
||||
<Button android:id="@+id/alarms_add"
|
||||
android:text="@string/alarm_ACS_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</merge>
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button android:id="@+id/date"
|
||||
android:layout_weight="0.7"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<Button android:id="@+id/time"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<ImageButton android:id="@+id/button1"
|
||||
style="?android:attr/buttonStyleInset"
|
||||
android:src="@android:drawable/ic_delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginTop="2dip"
|
||||
android:layout_marginRight="2dip"
|
||||
android:layout_marginBottom="2dip"
|
||||
android:gravity="center_vertical"
|
||||
/>
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/taskListParent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/background_gradient"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Header -->
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/edit_header">
|
||||
|
||||
<!-- Back Button -->
|
||||
<ImageView android:id="@+id/back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_previous"
|
||||
android:paddingLeft="5dip"
|
||||
android:paddingRight="8dip"/>
|
||||
|
||||
<!-- List Label -->
|
||||
<TextView android:id="@+id/listLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="100"
|
||||
android:singleLine="true"
|
||||
android:paddingTop="6dip"
|
||||
android:paddingRight="50dip"
|
||||
style="@style/TextAppearance.TLA_Header"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="100">
|
||||
|
||||
<!-- No Tasks label -->
|
||||
<TextView android:id="@android:id/empty"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:visibility="gone"
|
||||
android:text="@string/TLA_no_items"
|
||||
style="@style/TextAppearance.TLA_NoItems"/>
|
||||
|
||||
<!-- Task List -->
|
||||
<ListView android:id="@android:id/list"
|
||||
android:scrollbars="vertical"
|
||||
android:cacheColorHint="#00000000"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<!-- Footer -->
|
||||
<LinearLayout
|
||||
android:id="@+id/taskListFooter"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- Quick Add Button -->
|
||||
<ImageButton android:id="@+id/quickAddButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"
|
||||
android:src="@drawable/tango_add"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<!-- Quick Add Task -->
|
||||
<EditText android:id="@+id/quickAddText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="100"
|
||||
android:hint="@string/TLA_quick_add_hint"
|
||||
android:singleLine="true"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"/>
|
||||
|
||||
<!-- Extended Add Button -->
|
||||
<ImageButton android:id="@+id/extendedAddButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_edit"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
Binary file not shown.
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- Resources for built-in timers plug-in -->
|
||||
|
||||
<!-- Task Edit Activity: Container Label -->
|
||||
<string name="alarm_ACS_label">Alarms</string>
|
||||
|
||||
<!-- Task Edit Activity: Add New Alarn -->
|
||||
<string name="alarm_ACS_button">Add an Alarm</string>
|
||||
|
||||
<!-- Task Detail for Alarms (%s -> time)-->
|
||||
<string name="alarm_ADE_detail">Alarm %s</string>
|
||||
|
||||
<string-array name="reminders_alarm">
|
||||
<!-- reminders related to alarm -->
|
||||
<item>Alarm!</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.legacy;
|
||||
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractModel;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
|
||||
/**
|
||||
* Data Model which represents an alarm. This is a transitional class -
|
||||
* Alarms are moved over to metadata
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
@Deprecated
|
||||
public class TransitionalAlarm extends AbstractModel {
|
||||
|
||||
// --- table
|
||||
|
||||
public static final Table TABLE = new Table("alarm", TransitionalAlarm.class);
|
||||
|
||||
// --- properties
|
||||
|
||||
/** ID */
|
||||
public static final LongProperty ID = new LongProperty(
|
||||
TABLE, ID_PROPERTY_NAME);
|
||||
|
||||
/** Associated Task */
|
||||
public static final LongProperty TASK = new LongProperty(
|
||||
TABLE, "task");
|
||||
|
||||
/** Alarm Time */
|
||||
public static final LongProperty TIME = new LongProperty(
|
||||
TABLE, "time");
|
||||
|
||||
/** List of all properties for this model */
|
||||
public static final Property<?>[] PROPERTIES = generateProperties(TransitionalAlarm.class);
|
||||
|
||||
// --- constants
|
||||
|
||||
/** this alarm was already triggered */
|
||||
public static final int TYPE_TRIGGERED = 0;
|
||||
|
||||
/** this alarm is single-shot */
|
||||
public static final int TYPE_SINGLE = 1;
|
||||
|
||||
/** this alarm repeats itself until turned off */
|
||||
public static final int TYPE_REPEATING = 2;
|
||||
|
||||
// --- defaults
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
static {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public TransitionalAlarm() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TransitionalAlarm(TodorooCursor<TransitionalAlarm> cursor) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
public void readFromCursor(TodorooCursor<TransitionalAlarm> cursor) {
|
||||
super.readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return getIdHelper(ID);
|
||||
};
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
private static final Creator<Task> CREATOR = new ModelCreator<Task>(Task.class);
|
||||
|
||||
@Override
|
||||
protected Creator<? extends AbstractModel> getCreator() {
|
||||
return CREATOR;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,134 @@
|
||||
package com.todoroo.astrid.repeats;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.ical.values.Frequency;
|
||||
import com.google.ical.values.RRule;
|
||||
import com.google.ical.values.Weekday;
|
||||
import com.google.ical.values.WeekdayNum;
|
||||
import com.todoroo.andlib.test.TodorooTestCase;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
|
||||
public class AdvancedRepeatTests extends TodorooTestCase {
|
||||
|
||||
|
||||
public static void assertDatesEqual(long date, long other) {
|
||||
assertEquals("Expected: " + new Date(date) + ", Actual: " + new Date(other),
|
||||
date, other);
|
||||
}
|
||||
|
||||
public void testDailyWithDaysOfWeek() throws ParseException {
|
||||
RRule rrule = new RRule();
|
||||
rrule.setInterval(1);
|
||||
rrule.setFreq(Frequency.DAILY);
|
||||
rrule.setByDay(Collections.singletonList(new WeekdayNum(0, Weekday.FR)));
|
||||
|
||||
Task task = new Task();
|
||||
long thursday = task.createDueDate(Task.URGENCY_SPECIFIC_DAY, new Date(113, 7, 1).getTime());
|
||||
task.setValue(Task.DUE_DATE, thursday);
|
||||
|
||||
// repeat once => due date should become friday
|
||||
long friday = thursday + DateUtilities.ONE_DAY;
|
||||
long nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertDatesEqual(friday, nextDueDate);
|
||||
|
||||
// repeat again => due date should be one week from friday
|
||||
long nextFriday = friday + DateUtilities.ONE_WEEK;
|
||||
task.setValue(Task.DUE_DATE, friday);
|
||||
nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertDatesEqual(nextFriday, nextDueDate);
|
||||
|
||||
// now try with thursday, and repeat every 2 days. expect next friday
|
||||
rrule.setInterval(2);
|
||||
task.setValue(Task.DUE_DATE, thursday);
|
||||
nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertDatesEqual(nextFriday, nextDueDate);
|
||||
|
||||
// again with friday, expect next friday
|
||||
task.setValue(Task.DUE_DATE, friday);
|
||||
nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertDatesEqual(nextFriday, nextDueDate);
|
||||
}
|
||||
|
||||
public void testMonthlyWithDaysOfWeek() throws ParseException {
|
||||
RRule rrule = new RRule();
|
||||
rrule.setInterval(1);
|
||||
rrule.setFreq(Frequency.MONTHLY);
|
||||
rrule.setByDay(Arrays.asList(new WeekdayNum[] {
|
||||
new WeekdayNum(0, Weekday.SU),
|
||||
new WeekdayNum(0, Weekday.MO),
|
||||
new WeekdayNum(0, Weekday.TU),
|
||||
new WeekdayNum(0, Weekday.WE),
|
||||
new WeekdayNum(0, Weekday.TH),
|
||||
new WeekdayNum(0, Weekday.FR),
|
||||
new WeekdayNum(0, Weekday.SA),
|
||||
}));
|
||||
|
||||
Task task = new Task();
|
||||
long thursday = task.createDueDate(Task.URGENCY_SPECIFIC_DAY, new Date(113, 7, 1).getTime());
|
||||
task.setValue(Task.DUE_DATE, thursday);
|
||||
|
||||
// repeat once => due date should become next month on the first
|
||||
long nextMonth = task.createDueDate(Task.URGENCY_SPECIFIC_DAY, new Date(113, 8, 1).getTime());
|
||||
long nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertDatesEqual(nextMonth, nextDueDate);
|
||||
|
||||
// only allow thursdays
|
||||
rrule.setByDay(Arrays.asList(new WeekdayNum[] {
|
||||
new WeekdayNum(0, Weekday.TH),
|
||||
}));
|
||||
long nextMonthOnThursday = task.createDueDate(Task.URGENCY_SPECIFIC_DAY, new Date(113, 8, 5).getTime());
|
||||
nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertDatesEqual(nextMonthOnThursday, nextDueDate);
|
||||
}
|
||||
|
||||
public void testDueDateInPast() throws ParseException {
|
||||
RRule rrule = new RRule();
|
||||
rrule.setInterval(1);
|
||||
rrule.setFreq(Frequency.DAILY);
|
||||
|
||||
Task task = new Task();
|
||||
|
||||
// repeat once => due date should become tomorrow
|
||||
long past = task.createDueDate(Task.URGENCY_SPECIFIC_DAY, new Date(110, 7, 1).getTime());
|
||||
task.setValue(Task.DUE_DATE, past);
|
||||
long today = task.createDueDate(Task.URGENCY_SPECIFIC_DAY, DateUtilities.now());
|
||||
long nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertDatesEqual(today, nextDueDate);
|
||||
|
||||
// test specific day & time
|
||||
long pastWithTime = task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, new Date(110, 7, 1, 10, 4).getTime());
|
||||
task.setValue(Task.DUE_DATE, pastWithTime);
|
||||
Date date = new Date(DateUtilities.now() / 1000L * 1000L);
|
||||
date.setHours(10);
|
||||
date.setMinutes(4);
|
||||
date.setSeconds(0);
|
||||
long todayWithTime = task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, date.getTime()) / 1000L * 1000L;
|
||||
if(todayWithTime < DateUtilities.now())
|
||||
todayWithTime += DateUtilities.ONE_DAY;
|
||||
nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertDatesEqual(todayWithTime, nextDueDate);
|
||||
}
|
||||
|
||||
public void testDueDateInPastRepeatMultiple() throws ParseException {
|
||||
RRule rrule = new RRule();
|
||||
rrule.setInterval(1);
|
||||
rrule.setFreq(Frequency.DAILY);
|
||||
Task task = new Task();
|
||||
|
||||
// repeat once => due date should become tomorrow
|
||||
long past = task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, new Date(110, 7, 1, 0, 0, 0).getTime());
|
||||
task.setValue(Task.DUE_DATE, past);
|
||||
long nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertTrue(nextDueDate > DateUtilities.now());
|
||||
task.setValue(Task.DUE_DATE, nextDueDate);
|
||||
long evenMoreNextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal());
|
||||
assertNotSame(nextDueDate, evenMoreNextDueDate);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue