Skip to content

Commit

Permalink
Add instance status column. Implements #572 (#600)
Browse files Browse the repository at this point in the history
This commit adds an instance status column which indicates which instance of a task is the next one to complete. This allows to filter out the instances which come after the next one.
  • Loading branch information
dmfs authored Dec 29, 2017
1 parent 125f3e5 commit d0ff43e
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,31 @@ public interface InstanceColumns
*/
String INSTANCE_ORIGINAL_TIME = "instance_original_time";

/**
* A flag indicating the completion status of an instance. This is one of {@link #INSTANCE_STATUS_CLOSED}, {@link #INSTANCE_STATUS_NEXT} or {@link
* #INSTANCE_STATUS_UPCOMING}.
* <p>
* Value: Integer
* <p>
* read-only
*/
String INSTANCE_STATUS = "instance_status";

/**
* Status of an instance which is completed or cancelled.
*/
int INSTANCE_STATUS_CLOSED = -1;

/**
* Status of the next instance to complete.
*/
int INSTANCE_STATUS_NEXT = 0;

/**
* Status of all instances after the next one.
*/
int INSTANCE_STATUS_UPCOMING = 1;

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.dmfs.opentaskspal.tables.TasksTable;
import org.dmfs.opentaskspal.tasklists.NameData;
import org.dmfs.opentaskspal.tasks.OriginalInstanceSyncIdData;
import org.dmfs.opentaskspal.tasks.StatusData;
import org.dmfs.opentaskspal.tasks.SyncIdData;
import org.dmfs.opentaskspal.tasks.TimeData;
import org.dmfs.opentaskspal.tasks.TitleData;
Expand Down Expand Up @@ -151,7 +152,8 @@ public void testSingleInsert()
new IsNull(Instances.INSTANCE_START_SORTING),
new IsNull(Instances.INSTANCE_DUE_SORTING),
new IsNull(Instances.INSTANCE_DURATION),
new IsNull(Tasks.TZ)
new IsNull(Tasks.TZ),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}
Expand Down Expand Up @@ -190,7 +192,8 @@ public void testMultipleInserts()
new IsNull(Instances.INSTANCE_START_SORTING),
new IsNull(Instances.INSTANCE_DUE_SORTING),
new IsNull(Instances.INSTANCE_DURATION),
new IsNull(Tasks.TZ)
new IsNull(Tasks.TZ),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
)),
new AssertRelated<>(new InstanceTable(mAuthority), Instances.TASK_ID, task2, new AllOf(
new IsNull(Instances.INSTANCE_START),
Expand All @@ -199,7 +202,8 @@ public void testMultipleInserts()
new IsNull(Instances.INSTANCE_START_SORTING),
new IsNull(Instances.INSTANCE_DUE_SORTING),
new IsNull(Instances.INSTANCE_DURATION),
new IsNull(Tasks.TZ)
new IsNull(Tasks.TZ),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
)),
new AssertRelated<>(new InstanceTable(mAuthority), Instances.TASK_ID, task3, new AllOf(
new IsNull(Instances.INSTANCE_START),
Expand All @@ -208,7 +212,8 @@ public void testMultipleInserts()
new IsNull(Instances.INSTANCE_START_SORTING),
new IsNull(Instances.INSTANCE_DUE_SORTING),
new IsNull(Instances.INSTANCE_DURATION),
new IsNull(Tasks.TZ)
new IsNull(Tasks.TZ),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}
Expand Down Expand Up @@ -239,7 +244,41 @@ public void testInsertTaskWithStartAndDue()
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, due.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DURATION, due.getTimestamp() - start.getTimestamp()),
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID())
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID()),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}


/**
* Create task with start and due, check datetime and INSTANCE_STATUS values after updating the status.
*/
@Test
public void testInsertTaskWithStartAndDueUpdateStatus()
{
RowSnapshot<TaskLists> taskList = new VirtualRowSnapshot<>(new LocalTaskListsTable(mAuthority));
RowSnapshot<Tasks> task = new VirtualRowSnapshot<>(new TaskListScoped(taskList, new TasksTable(mAuthority)));

DateTime start = DateTime.now();
DateTime due = start.addDuration(new Duration(1, 1, 0));

assertThat(new Seq<>(
new Put<>(taskList, new EmptyRowData<>()),
new Put<>(task, new TimeData(start, due)),
// update the status of the new task
new Put<>(task, new StatusData(Tasks.STATUS_COMPLETED))
), resultsIn(mClient,
new Assert<>(task, new TimeData(start, due)),
new AssertRelated<>(new InstanceTable(mAuthority), Instances.TASK_ID, task, new AllOf(
new EqArg(Instances.INSTANCE_START, start.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Instances.INSTANCE_DUE, due.getTimestamp()),
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, due.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DURATION, due.getTimestamp() - start.getTimestamp()),
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID()),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_CLOSED)
))
));
}
Expand Down Expand Up @@ -274,7 +313,8 @@ public void testInsertTaskWithStartAndDueMovedForward()
new EqArg(Instances.INSTANCE_START_SORTING, startNew.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, dueNew.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DURATION, dueNew.getTimestamp() - startNew.getTimestamp()),
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID())
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID()),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}
Expand Down Expand Up @@ -309,7 +349,8 @@ public void testInsertTaskWithStartAndDueMovedBackwards()
new EqArg(Instances.INSTANCE_START_SORTING, startNew.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, dueNew.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DURATION, dueNew.getTimestamp() - startNew.getTimestamp()),
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID())
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID()),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}
Expand Down Expand Up @@ -340,7 +381,8 @@ public void testInsertTaskWithStartAndDueAddedAfterwards()
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, due.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DURATION, due.getTimestamp() - start.getTimestamp()),
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID())
new EqArg(Tasks.TZ, start.isAllDay() ? "UTC" : start.getTimeZone().getID()),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}
Expand Down Expand Up @@ -372,7 +414,8 @@ public void testInsertWithStartAndDuration()
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, start.addDuration(duration).shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Tasks.TZ, "UTC")
new EqArg(Tasks.TZ, "UTC"),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}
Expand Down Expand Up @@ -408,7 +451,8 @@ public void testInsertWithStartAndDurationChangeTimeZone()
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, start.addDuration(duration).shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Tasks.TZ, "America/New_York")
new EqArg(Tasks.TZ, "America/New_York"),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}
Expand Down Expand Up @@ -448,7 +492,8 @@ public void testUpdateDue() throws Exception
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, due2.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Tasks.TZ, "UTC")
new EqArg(Tasks.TZ, "UTC"),
new EqArg(Instances.INSTANCE_STATUS, Instances.INSTANCE_STATUS_NEXT)
))
));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public interface OnDatabaseOperationListener
/**
* The database version.
*/
private static final int DATABASE_VERSION = 17;
private static final int DATABASE_VERSION = 18;


/**
Expand Down Expand Up @@ -237,7 +237,8 @@ public interface CategoriesMapping
+ TaskContract.Instances.INSTANCE_START_SORTING + " INTEGER, "
+ TaskContract.Instances.INSTANCE_DUE_SORTING + " INTEGER, "
+ TaskContract.Instances.INSTANCE_DURATION + " INTEGER, "
+ TaskContract.Instances.INSTANCE_ORIGINAL_TIME + " INTEGER DEFAULT 0);";
+ TaskContract.Instances.INSTANCE_ORIGINAL_TIME + " INTEGER DEFAULT 0, "
+ TaskContract.Instances.INSTANCE_STATUS + " INTEGER DEFAULT " + TaskContract.Instances.INSTANCE_STATUS_NEXT + ");";

/**
* SQL command to create a trigger to clean up data of removed tasks.
Expand Down Expand Up @@ -767,6 +768,12 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
db.execSQL(createIndexString(Tables.INSTANCES, false, TaskContract.Instances.INSTANCE_ORIGINAL_TIME));
}

if (oldVersion < 18)
{
db.execSQL(
"alter table " + Tables.INSTANCES + " add column " + TaskContract.Instances.INSTANCE_STATUS + " integer default " + TaskContract.Instances.INSTANCE_STATUS_NEXT + ";");
}

// upgrade FTS
FTSDatabaseHelper.onUpgrade(db, oldVersion, newVersion);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
import org.dmfs.provider.tasks.model.TaskAdapter;
import org.dmfs.provider.tasks.model.adapters.BooleanFieldAdapter;
import org.dmfs.provider.tasks.processors.EntityProcessor;
import org.dmfs.provider.tasks.processors.tasks.instancedata.TaskRelated;
import org.dmfs.provider.tasks.utils.InstanceValuesIterable;
import org.dmfs.provider.tasks.utils.Limited;
import org.dmfs.provider.tasks.utils.Range;
import org.dmfs.provider.tasks.processors.tasks.instancedata.TaskRelated;
import org.dmfs.tasks.contract.TaskContract;

import java.util.Locale;
Expand Down Expand Up @@ -99,7 +99,8 @@ public TaskAdapter update(SQLiteDatabase db, TaskAdapter task, boolean isSyncAda

TaskAdapter result = mDelegate.update(db, task, isSyncAdapter);

if (!result.isUpdated(TaskAdapter.DTSTART) && !result.isUpdated(TaskAdapter.DUE) && !result.isUpdated(TaskAdapter.DURATION) && !updateRequested)
if (!result.isUpdated(TaskAdapter.DTSTART) && !result.isUpdated(TaskAdapter.DUE) && !result.isUpdated(TaskAdapter.DURATION)
&& !result.isUpdated(TaskAdapter.STATUS) && !updateRequested)
{
// date values didn't change and update not requested -> no need to update the instances table
return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2017 dmfs GmbH
*
* 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.
*/

package org.dmfs.provider.tasks.processors.tasks.instancedata;

import android.content.ContentValues;

import org.dmfs.jems.single.Single;
import org.dmfs.jems.single.decorators.DelegatingSingle;
import org.dmfs.tasks.contract.TaskContract;


/**
* A {@link Single} of the instance status {@link ContentValues} of an instance.
*
* @author Marten Gajda
*/
public final class Stated extends DelegatingSingle<ContentValues>
{

public Stated(boolean closed, Single<ContentValues> delegate)
{
super(() ->
{
ContentValues values = delegate.value();
values.put(TaskContract.Instances.INSTANCE_STATUS,
closed ? TaskContract.Instances.INSTANCE_STATUS_CLOSED : TaskContract.Instances.INSTANCE_STATUS_NEXT);
return values;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public ContentValues value()
values.putNull(TaskContract.Instances.INSTANCE_DUE);
values.putNull(TaskContract.Instances.INSTANCE_DUE_SORTING);
values.putNull(TaskContract.Instances.INSTANCE_DURATION);
values.put(TaskContract.Instances.INSTANCE_STATUS, TaskContract.Instances.INSTANCE_STATUS_NEXT);
values.put(TaskContract.Instances.INSTANCE_ORIGINAL_TIME, 0);
return values;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.dmfs.provider.tasks.processors.tasks.instancedata.Enduring;
import org.dmfs.provider.tasks.processors.tasks.instancedata.Overridden;
import org.dmfs.provider.tasks.processors.tasks.instancedata.StartDated;
import org.dmfs.provider.tasks.processors.tasks.instancedata.Stated;
import org.dmfs.provider.tasks.processors.tasks.instancedata.VanillaInstanceData;
import org.dmfs.rfc5545.DateTime;

Expand Down Expand Up @@ -62,7 +63,8 @@ public Iterator<Single<ContentValues>> iterator()
new NullSafe<>(mTaskAdapter.valueOf(TaskAdapter.DUE)),
new Zipped<>(start, new NullSafe<>(mTaskAdapter.valueOf(TaskAdapter.DURATION)), DateTime::addDuration)));

Single<ContentValues> baseData = new Enduring(new DueDated(effectiveDue, new StartDated(start, new VanillaInstanceData())));
Single<ContentValues> baseData = new Stated(mTaskAdapter.valueOf(TaskAdapter.IS_CLOSED),
new Enduring(new DueDated(effectiveDue, new StartDated(start, new VanillaInstanceData()))));

// TODO: implement support for recurrence, for now we only return the first instance
return new SingletonIterator<>(mTaskAdapter.isRecurring() ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ public void testValue() throws Exception
assertThat(values.get(TaskContract.Instances.INSTANCE_DUE), nullValue());
assertThat(values.get(TaskContract.Instances.INSTANCE_DUE_SORTING), nullValue());
assertThat(values.get(TaskContract.Instances.INSTANCE_DURATION), nullValue());
assertThat(values.get(TaskContract.Instances.INSTANCE_STATUS), is(TaskContract.Instances.INSTANCE_STATUS_NEXT));
assertThat(values.get(TaskContract.Instances.INSTANCE_ORIGINAL_TIME), is(0));
assertThat(values.size(), is(6));
assertThat(values.size(), is(7));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2017 dmfs GmbH
*
* 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.
*/

package org.dmfs.opentaskspal.tasks;

import android.content.ContentProviderOperation;
import android.support.annotation.NonNull;

import org.dmfs.android.contentpal.RowData;
import org.dmfs.android.contentpal.TransactionContext;
import org.dmfs.tasks.contract.TaskContract;


/**
* {@link RowData} for the status of a task.
*
* @author Marten Gajda
*/
public final class StatusData implements RowData<TaskContract.Tasks>
{
private final int mStatus;


public StatusData(int status)
{
mStatus = status;
}


@NonNull
@Override
public ContentProviderOperation.Builder updatedBuilder(@NonNull TransactionContext transactionContext, @NonNull ContentProviderOperation.Builder builder)
{
return builder.withValue(TaskContract.Tasks.STATUS, mStatus);
}
}

0 comments on commit d0ff43e

Please sign in to comment.