Skip to content

Commit

Permalink
Add RowData to create recurring tasks. Implements #460
Browse files Browse the repository at this point in the history
This certainly needs to be revisited, but it should be ok for now when it's mostly required to write unit tests.
  • Loading branch information
dmfs committed Dec 30, 2017
1 parent d0ff43e commit 3645289
Show file tree
Hide file tree
Showing 7 changed files with 432 additions and 0 deletions.
1 change: 1 addition & 0 deletions opentaskspal/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dependencies {
exclude module: 'jems'
}
implementation 'org.dmfs:rfc5545-datetime:' + RFC5545_DATETIME_VERSION
implementation 'org.dmfs:lib-recur:' + LIB_RECUR_VERSION
implementation 'org.dmfs:jems:' + JEMS_VERSION
implementation 'com.github.dmfs.bolts:color-bolts:' + BOLTS_VERSION

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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 android.text.TextUtils;

import org.dmfs.android.contentpal.RowData;
import org.dmfs.android.contentpal.TransactionContext;
import org.dmfs.jems.iterable.decorators.Mapped;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.contract.TaskContract;


/**
* {@link RowData} for tasks with EXDATEs
* <p>
* TODO: how to make sure this is only ever used with tasks having a start and/or due date?
*
* @author Marten Gajda
*/
public final class ExDatesTaskData implements RowData<TaskContract.Tasks>
{
private final Iterable<DateTime> mExDates;


public ExDatesTaskData(@NonNull Iterable<DateTime> exdates)
{
mExDates = exdates;
}


@NonNull
@Override
public ContentProviderOperation.Builder updatedBuilder(@NonNull TransactionContext transactionContext, @NonNull ContentProviderOperation.Builder builder)
{
String value = TextUtils.join(",",
new Mapped<>(DateTime::toString, new Mapped<>(dt -> dt.isFloating() ? dt : dt.shiftTimeZone(DateTime.UTC), mExDates)));
return builder.withValue(TaskContract.Tasks.EXDATE, value.isEmpty() ? null : value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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 android.text.TextUtils;

import org.dmfs.android.contentpal.RowData;
import org.dmfs.android.contentpal.TransactionContext;
import org.dmfs.jems.iterable.decorators.Mapped;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.contract.TaskContract;


/**
* {@link RowData} for tasks with RDATEs.
* <p>
* TODO: how to make sure this is only ever used with tasks having a start and/or due date?
*
* @author Marten Gajda
*/
public final class RDatesTaskData implements RowData<TaskContract.Tasks>
{
private final Iterable<DateTime> mRDates;


public RDatesTaskData(@NonNull Iterable<DateTime> rdates)
{
mRDates = rdates;
}


@NonNull
@Override
public ContentProviderOperation.Builder updatedBuilder(@NonNull TransactionContext transactionContext, @NonNull ContentProviderOperation.Builder builder)
{
String value = TextUtils.join(",",
new Mapped<>(DateTime::toString, new Mapped<>(dt -> dt.isFloating() ? dt : dt.shiftTimeZone(DateTime.UTC), mRDates)));
return builder.withValue(TaskContract.Tasks.RDATE, value.isEmpty() ? null : value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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.rfc5545.recur.RecurrenceRule;
import org.dmfs.tasks.contract.TaskContract;


/**
* {@link RowData} for tasks with a recurrence rule.
* <p>
* TODO: how to make sure this is only ever used with tasks having a start and/or due date?
*
* @author Marten Gajda
*/
public final class RRuleTaskData implements RowData<TaskContract.Tasks>
{
private final RecurrenceRule mRule;


public RRuleTaskData(@NonNull RecurrenceRule rule)
{
mRule = rule;
}


@NonNull
@Override
public ContentProviderOperation.Builder updatedBuilder(@NonNull TransactionContext transactionContext, @NonNull ContentProviderOperation.Builder builder)
{
return builder.withValue(TaskContract.Tasks.RRULE, mRule.toString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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 org.dmfs.iterables.SingletonIterable;
import org.dmfs.iterables.elementary.Seq;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.contract.TaskContract;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import static org.dmfs.android.contentpal.testing.contentoperationbuilder.WithValues.withValuesOnly;
import static org.dmfs.android.contentpal.testing.contentvalues.Containing.containing;
import static org.dmfs.android.contentpal.testing.contentvalues.NullValue.withNullValue;
import static org.dmfs.android.contentpal.testing.rowdata.RowDataMatcher.builds;
import static org.dmfs.iterables.EmptyIterable.instance;
import static org.junit.Assert.assertThat;


/**
* @author Marten Gajda
*/
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class ExDatesTaskDataTest
{
@Test
public void testEmpty() throws Exception
{
assertThat(new ExDatesTaskData(instance()),
builds(
withValuesOnly(
withNullValue(TaskContract.Tasks.EXDATE))));
}


@Test
public void testSingle() throws Exception
{
assertThat(new ExDatesTaskData(new SingletonIterable<>(DateTime.parse("Europe/Berlin", "20171212T123456"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.EXDATE, "20171212T113456Z"))));
}


@Test
public void testSingleFloating() throws Exception
{
assertThat(new ExDatesTaskData(new SingletonIterable<>(DateTime.parse("20171212T123456"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.EXDATE, "20171212T123456"))));
}


@Test
public void testSingleAllDay() throws Exception
{
assertThat(new ExDatesTaskData(new SingletonIterable<>(DateTime.parse("20171212"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.EXDATE, "20171212"))));
}


@Test
public void testMulti1() throws Exception
{
assertThat(new ExDatesTaskData(
new Seq<>(
DateTime.parse("Europe/Berlin", "20171212T123456"),
DateTime.parse("UTC", "20171213T123456"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.EXDATE, "20171212T113456Z,20171213T123456Z"))));
}


@Test
public void testMulti2() throws Exception
{
assertThat(new ExDatesTaskData(
new Seq<>(
DateTime.parse("Europe/Berlin", "20171212T123456"),
DateTime.parse("UTC", "20171213T123456"),
DateTime.parse("America/New_York", "20171214T123456"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.EXDATE, "20171212T113456Z,20171213T123456Z,20171214T173456Z"))));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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 org.dmfs.iterables.SingletonIterable;
import org.dmfs.iterables.elementary.Seq;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.contract.TaskContract;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import static org.dmfs.android.contentpal.testing.contentoperationbuilder.WithValues.withValuesOnly;
import static org.dmfs.android.contentpal.testing.contentvalues.Containing.containing;
import static org.dmfs.android.contentpal.testing.contentvalues.NullValue.withNullValue;
import static org.dmfs.android.contentpal.testing.rowdata.RowDataMatcher.builds;
import static org.dmfs.iterables.EmptyIterable.instance;
import static org.junit.Assert.assertThat;


/**
* @author Marten Gajda
*/
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class RDatesTaskDataTest
{
@Test
public void testEmpty() throws Exception
{
assertThat(new RDatesTaskData(instance()),
builds(
withValuesOnly(
withNullValue(TaskContract.Tasks.RDATE))));
}


@Test
public void testSingle() throws Exception
{
assertThat(new RDatesTaskData(new SingletonIterable<>(DateTime.parse("Europe/Berlin", "20171212T123456"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.RDATE, "20171212T113456Z"))));
}


@Test
public void testSingleFloating() throws Exception
{
assertThat(new RDatesTaskData(new SingletonIterable<>(DateTime.parse("20171212T123456"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.RDATE, "20171212T123456"))));
}


@Test
public void testSingleAllDay() throws Exception
{
assertThat(new RDatesTaskData(new SingletonIterable<>(DateTime.parse("20171212"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.RDATE, "20171212"))));
}


@Test
public void testMulti1() throws Exception
{
assertThat(new RDatesTaskData(
new Seq<>(
DateTime.parse("Europe/Berlin", "20171212T123456"),
DateTime.parse("UTC", "20171213T123456"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.RDATE, "20171212T113456Z,20171213T123456Z"))));
}


@Test
public void testMulti2() throws Exception
{
assertThat(new RDatesTaskData(
new Seq<>(
DateTime.parse("Europe/Berlin", "20171212T123456"),
DateTime.parse("UTC", "20171213T123456"),
DateTime.parse("America/New_York", "20171214T123456"))),
builds(
withValuesOnly(
containing(TaskContract.Tasks.RDATE, "20171212T113456Z,20171213T123456Z,20171214T173456Z"))));
}

}
Loading

0 comments on commit 3645289

Please sign in to comment.