Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit d0ff43ee authored by Marten Gajda's avatar Marten Gajda Committed by GitHub
Browse files

Add instance status column. Implements #572 (#600)

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.
parent 125f3e59
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -1043,6 +1043,31 @@ public final class TaskContract
         */
        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;

    }


+56 −11
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import org.dmfs.opentaskspal.tables.TaskListsTable;
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;
@@ -151,7 +152,8 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
@@ -190,7 +192,8 @@ public class TaskProviderTest
                        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),
@@ -199,7 +202,8 @@ public class TaskProviderTest
                        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),
@@ -208,7 +212,8 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
@@ -239,7 +244,41 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
@@ -274,7 +313,8 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
@@ -309,7 +349,8 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
@@ -340,7 +381,8 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
@@ -372,7 +414,8 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
@@ -408,7 +451,8 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
@@ -448,7 +492,8 @@ public class TaskProviderTest
                        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)
                ))
        ));
    }
+9 −2
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ public class TaskDatabaseHelper extends SQLiteOpenHelper
    /**
     * The database version.
     */
    private static final int DATABASE_VERSION = 17;
    private static final int DATABASE_VERSION = 18;


    /**
@@ -237,7 +237,8 @@ public class TaskDatabaseHelper extends SQLiteOpenHelper
                    + 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.
@@ -767,6 +768,12 @@ public class TaskDatabaseHelper extends SQLiteOpenHelper
            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);

+3 −2
Original line number Diff line number Diff line
@@ -29,10 +29,10 @@ import org.dmfs.provider.tasks.TaskDatabaseHelper;
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;
@@ -99,7 +99,8 @@ public final class Instantiating implements EntityProcessor<TaskAdapter>

        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;
+44 −0
Original line number Diff line number Diff line
/*
 * 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;
        });
    }
}
Loading