Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions opentasks/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ android {

dependencies {
implementation project(':opentasks-provider')
implementation project(':opentaskspal')
implementation 'com.android.support:appcompat-v7:' + SUPPORT_LIBRARY_VERSION
implementation 'com.android.support:design:' + SUPPORT_LIBRARY_VERSION
implementation('org.dmfs:android-xml-magic:0.1.1') {
Expand Down
23 changes: 23 additions & 0 deletions opentasks/src/main/java/org/dmfs/tasks/model/ContentSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import android.os.Parcelable;
import android.util.Log;

import org.dmfs.opentaskspal.jems.procedure.Procedure;
import org.dmfs.tasks.utils.AsyncContentLoader;
import org.dmfs.tasks.utils.ContentValueMapper;
import org.dmfs.tasks.utils.OnContentLoadedListener;
Expand Down Expand Up @@ -523,6 +524,28 @@ public void finishBulkUpdate()
}


/**
* Execute a bulk update for this {@link ContentSet}.
* <p>
* Shortcut for using {@link #startBulkUpdate()} and {@link #finishBulkUpdate()}.
*
* @param body
* do the changes to {@link ContentSet} here
*/
public void bulkUpdate(Procedure<ContentSet> body)
{
startBulkUpdate();
try
{
body.process(this);
}
finally
{
finishBulkUpdate();
}
}


/**
* Remove the value with the given key from the ContentSet. This is actually replacing the value by <code>null</code>.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* 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.tasks.model.adapters;

import android.content.ContentValues;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import org.dmfs.opentaskspal.datetime.CombinedDateTime;
import org.dmfs.opentaskspal.datetime.general.OptionalTimeZone;
import org.dmfs.opentaskspal.datetimefields.DateTimeFields;
import org.dmfs.opentaskspal.datetimefields.adapters.DateTimeDateTimeFields;
import org.dmfs.opentaskspal.readdata.cursor.CursorCombinedDateTime;
import org.dmfs.opentaskspal.utils.binarybooleans.BinaryIntBoolean;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.model.ContentSet;
import org.dmfs.tasks.model.OnContentChangeListener;
import org.dmfs.tasks.model.datetime.ContentSetCombinedDateTime;
import org.dmfs.tasks.model.datetime.ContentSetDateTimeFields;


/**
* Knows how to load and store combined date-time values as {@link DateTime} from/to {@link Cursor}, {@link ContentSet}, {@link ContentValues}.
* <p>
* Combined date-time values are stored as three values: timestamp, time zone, all-day flag
*
* @author Gabor Keszthelyi
*/
public final class CombinedDateTimeFieldAdapter extends FieldAdapter<DateTime>
{
private final String mTimestampField;
private final String mTimeZoneField;
private final String mIsAllDayField;


public CombinedDateTimeFieldAdapter(@NonNull String timestampField,
@NonNull String timeZoneField,
@NonNull String isAllDayField)
{
mTimestampField = timestampField;
mTimeZoneField = timeZoneField;
mIsAllDayField = isAllDayField;
}


@Override
public DateTime get(@NonNull ContentSet values)
{
return new ContentSetCombinedDateTime(values, mTimestampField, mTimeZoneField, mIsAllDayField).value(null);
}


@Override
public DateTime get(@NonNull Cursor cursor)
{
return new CursorCombinedDateTime(cursor, mTimestampField, mTimeZoneField, mIsAllDayField).value(null);
}


/**
* Provides a default value for 'now' that respects the time zone and all-day values if they've been already selected
* (i.e. they are present in the provided {@link ContentSet}.
* <p>
* <li>If all-day flag is true, an all-day {@link DateTime} for today is returned.</li>
* <li>If time zone is provided, a {@link DateTime} for the current time instance with that time zone is returned</li>
* <li>If time zone is not provided, a floating {@link DateTime} for the current time instance is returned</li>
* <p>
* Note: it is up to the presentation layer to apply local time zone when needed
*/
@Override
public DateTime getDefault(@NonNull ContentSet values)
{
DateTimeFields fields = new ContentSetDateTimeFields(values, mTimestampField, mTimeZoneField, mIsAllDayField);
return new CombinedDateTime(System.currentTimeMillis(),
new OptionalTimeZone(fields.timeZoneId()),
new BinaryIntBoolean(fields.isAllDay())).value();
}


@Override
public void set(@NonNull ContentSet values, @Nullable DateTime dateTime)
{
values.bulkUpdate(contentSet ->
{
if (dateTime != null)
{
DateTimeFields dateTimeFields = new DateTimeDateTimeFields(dateTime);
values.put(mTimestampField, dateTimeFields.timestamp());
values.put(mTimeZoneField, dateTimeFields.timeZoneId());
values.put(mIsAllDayField, dateTimeFields.isAllDay());
}
else
{
// write timestamp only, other fields may still use all-day and timezone
values.put(mTimestampField, (Long) null);
}
});
}


@Override
public void set(@NonNull ContentValues values, @Nullable DateTime dateTime)
{
// TODO Remove semantic code duplication with the above
// Update<T> type with isNewValue(), isClear(), isNoChange(), T newValue() might help here
if (dateTime != null)
{
DateTimeFields dateTimeFields = new DateTimeDateTimeFields(dateTime);
values.put(mTimestampField, dateTimeFields.timestamp());
values.put(mTimeZoneField, dateTimeFields.timeZoneId());
values.put(mIsAllDayField, dateTimeFields.isAllDay());
}
else
{
// write timestamp only, other fields may still use all-day and timezone
values.put(mTimestampField, (Long) null);
}
}


@Override
public void registerListener(ContentSet values, OnContentChangeListener listener, boolean initalNotification)
{
values.addOnChangeListener(listener, mTimestampField, initalNotification);
values.addOnChangeListener(listener, mTimeZoneField, initalNotification);
values.addOnChangeListener(listener, mIsAllDayField, initalNotification);
}


@Override
public void unregisterListener(ContentSet values, OnContentChangeListener listener)
{
values.removeOnChangeListener(listener, mTimestampField);
values.removeOnChangeListener(listener, mTimeZoneField);
values.removeOnChangeListener(listener, mIsAllDayField);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* 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.tasks.model.adapters;

import android.content.ContentValues;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import org.dmfs.opentaskspal.datetime.general.OptionalDateTimeTimestamp;
import org.dmfs.opentaskspal.datetime.general.OptionalTimestampDateTime;
import org.dmfs.opentaskspal.readdata.cursor.LongCursorColumnValue;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.model.ContentSet;
import org.dmfs.tasks.model.OnContentChangeListener;


/**
* Knows how to load and store a {@link DateTime} value that doesn't use timezone and the all-day flag, just the timestamp.
*
* @author Gabor Keszthelyi
*/
public final class TimestampDateTimeFieldAdapter extends FieldAdapter<DateTime>
{
private final String mTimestampField;


public TimestampDateTimeFieldAdapter(@NonNull String timestampField)
{
mTimestampField = timestampField;
}


@Override
public DateTime get(@NonNull ContentSet values)
{
return new OptionalTimestampDateTime(values.getAsLong(mTimestampField)).value(null);
}


@Override
public DateTime get(@NonNull Cursor cursor)
{
return new OptionalTimestampDateTime(new LongCursorColumnValue(cursor, mTimestampField)).value(null);
}


@Override
public DateTime getDefault(@NonNull ContentSet values)
{
return DateTime.now();
}


@Override
public void set(@NonNull ContentSet values, @Nullable DateTime value)
{
values.bulkUpdate(contentSet -> contentSet.put(mTimestampField, new OptionalDateTimeTimestamp(value).value(null)));
}


@Override
public void set(@NonNull ContentValues values, @Nullable DateTime value)
{
values.put(mTimestampField, new OptionalDateTimeTimestamp(value).value(null));
}


@Override
public void registerListener(@NonNull ContentSet values, @NonNull OnContentChangeListener listener, boolean initialNotification)
{
values.addOnChangeListener(listener, mTimestampField, initialNotification);
}


@Override
public void unregisterListener(@NonNull ContentSet values, @NonNull OnContentChangeListener listener)
{
values.removeOnChangeListener(listener, mTimestampField);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2018 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.tasks.model.datetime;

import android.support.annotation.NonNull;

import org.dmfs.opentaskspal.datetime.OptionalCombinedDateTime;
import org.dmfs.optional.decorators.DelegatingOptional;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.model.ContentSet;


/**
* Combined date-time from a {@link ContentSet}.
*
* @author Gabor Keszthelyi
*/
public final class ContentSetCombinedDateTime extends DelegatingOptional<DateTime>
{
public ContentSetCombinedDateTime(@NonNull ContentSet contentSet,
@NonNull String timestampKey,
@NonNull String timeZoneKey,
@NonNull String isAllDayKey)
{
super(new OptionalCombinedDateTime(
new ContentSetDateTimeFields(contentSet, timestampKey, timeZoneKey, isAllDayKey)));
}
}
Loading