Rename CalDAV lists, sync CalDAV colors

pull/935/head
Alex Baker 5 years ago
parent 13d5df230b
commit 3e94a8c069

@ -127,7 +127,7 @@ public abstract class BaseCaldavCalendarSettingsActivity extends BaseListSetting
showProgressIndicator();
updateNameAndColor(caldavAccount, caldavCalendar, name, selectedColor);
} else if (iconChanged()) {
updateAccount();
updateCalendar();
} else {
finish();
}
@ -197,7 +197,7 @@ public abstract class BaseCaldavCalendarSettingsActivity extends BaseListSetting
finish();
}
protected void updateAccount() {
protected void updateCalendar() {
caldavCalendar.setName(getNewName());
caldavCalendar.setColor(selectedColor);
caldavCalendar.setIcon(selectedIcon);

@ -1,7 +1,6 @@
package org.tasks.caldav;
import android.os.Bundle;
import android.view.View;
import androidx.lifecycle.ViewModelProviders;
import javax.inject.Inject;
import org.tasks.R;
@ -15,6 +14,7 @@ public class CaldavCalendarSettingsActivity extends BaseCaldavCalendarSettingsAc
private CreateCalendarViewModel createCalendarViewModel;
private DeleteCalendarViewModel deleteCalendarViewModel;
private UpdateCalendarViewModel updateCalendarViewModel;
@Override
protected int getLayout() {
@ -25,15 +25,13 @@ public class CaldavCalendarSettingsActivity extends BaseCaldavCalendarSettingsAc
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!isNew()) {
nameLayout.setVisibility(View.GONE);
}
createCalendarViewModel = ViewModelProviders.of(this).get(CreateCalendarViewModel.class);
deleteCalendarViewModel = ViewModelProviders.of(this).get(DeleteCalendarViewModel.class);
updateCalendarViewModel = ViewModelProviders.of(this).get(UpdateCalendarViewModel.class);
createCalendarViewModel.observe(this, this::createSuccessful, this::requestFailed);
deleteCalendarViewModel.observe(this, this::onDeleted, this::requestFailed);
updateCalendarViewModel.observe(this, ignored -> updateCalendar(), this::requestFailed);
}
@Override
@ -43,13 +41,13 @@ public class CaldavCalendarSettingsActivity extends BaseCaldavCalendarSettingsAc
@Override
protected void createCalendar(CaldavAccount caldavAccount, String name, int color) {
createCalendarViewModel.createCalendar(client, caldavAccount, name);
createCalendarViewModel.createCalendar(client, caldavAccount, name, color);
}
@Override
protected void updateNameAndColor(
CaldavAccount account, CaldavCalendar calendar, String name, int color) {
updateAccount();
updateCalendarViewModel.updateCalendar(client, account, calendar, name, color);
}
@Override

@ -16,6 +16,7 @@ import at.bitfire.dav4jvm.Response.HrefRelation;
import at.bitfire.dav4jvm.XmlUtils;
import at.bitfire.dav4jvm.exception.DavException;
import at.bitfire.dav4jvm.exception.HttpException;
import at.bitfire.dav4jvm.property.CalendarColor;
import at.bitfire.dav4jvm.property.CalendarHomeSet;
import at.bitfire.dav4jvm.property.CurrentUserPrincipal;
import at.bitfire.dav4jvm.property.DisplayName;
@ -207,6 +208,7 @@ public class CaldavClient {
DisplayName.NAME,
SupportedCalendarComponentSet.NAME,
GetCTag.NAME,
CalendarColor.NAME,
SyncToken.NAME
},
responses);
@ -234,16 +236,57 @@ public class CaldavClient {
new DavResource(httpClient, httpUrl).delete(null, response -> null);
}
String makeCollection(String displayName)
String makeCollection(String displayName, int color)
throws IOException, XmlPullParserException, HttpException {
DavResource davResource =
new DavResource(httpClient, httpUrl.resolve(UUIDHelper.newUUID() + "/"));
String mkcolString = getMkcolString(displayName);
String mkcolString = getMkcolString(displayName, color);
davResource.mkCol(mkcolString, response -> null);
return davResource.getLocation().toString();
}
private String getMkcolString(String displayName) throws IOException, XmlPullParserException {
String updateCollection(String displayName, int color)
throws IOException, XmlPullParserException, HttpException {
PatchableDavResource davResource = new PatchableDavResource(httpClient, httpUrl);
davResource.propPatch(getPropPatchString(displayName, color), response -> null);
return davResource.getLocation().toString();
}
private String getPropPatchString(String displayName, int color)
throws IOException, XmlPullParserException {
XmlPullParserFactory xmlPullParserFactory = XmlPullParserFactory.newInstance();
XmlSerializer xml = xmlPullParserFactory.newSerializer();
StringWriter stringWriter = new StringWriter();
xml.setOutput(stringWriter);
xml.startDocument("UTF-8", null);
xml.setPrefix("", NS_WEBDAV);
xml.setPrefix("CAL", NS_CALDAV);
xml.setPrefix("CARD", NS_CARDDAV);
xml.startTag(NS_WEBDAV, "propertyupdate");
xml.startTag(XmlUtils.NS_WEBDAV, "set");
xml.startTag(XmlUtils.NS_WEBDAV, "prop");
setDisplayName(xml, displayName);
if (color != 0) {
setColor(xml, color);
}
xml.endTag(XmlUtils.NS_WEBDAV, "prop");
xml.endTag(XmlUtils.NS_WEBDAV, "set");
if (color == 0) {
xml.startTag(XmlUtils.NS_WEBDAV, "remove");
xml.startTag(XmlUtils.NS_WEBDAV, "prop");
xml.startTag(XmlUtils.NS_APPLE_ICAL, "calendar-color");
xml.endTag(XmlUtils.NS_APPLE_ICAL, "calendar-color");
xml.endTag(XmlUtils.NS_WEBDAV, "prop");
xml.endTag(XmlUtils.NS_WEBDAV, "remove");
}
xml.endTag(XmlUtils.NS_WEBDAV, "propertyupdate");
xml.endDocument();
xml.flush();
return stringWriter.toString();
}
private String getMkcolString(String displayName, int color) throws IOException, XmlPullParserException {
XmlPullParserFactory xmlPullParserFactory = XmlPullParserFactory.newInstance();
XmlSerializer xml = xmlPullParserFactory.newSerializer();
StringWriter stringWriter = new StringWriter();
@ -261,9 +304,10 @@ public class CaldavClient {
xml.startTag(XmlUtils.NS_CALDAV, "calendar");
xml.endTag(XmlUtils.NS_CALDAV, "calendar");
xml.endTag(XmlUtils.NS_WEBDAV, "resourcetype");
xml.startTag(XmlUtils.NS_WEBDAV, "displayname");
xml.text(displayName);
xml.endTag(XmlUtils.NS_WEBDAV, "displayname");
setDisplayName(xml, displayName);
if (color != 0) {
setColor(xml, color);
}
xml.startTag(XmlUtils.NS_CALDAV, "supported-calendar-component-set");
xml.startTag(XmlUtils.NS_CALDAV, "comp");
xml.attribute(null, "name", "VTODO");
@ -277,6 +321,18 @@ public class CaldavClient {
return stringWriter.toString();
}
private void setDisplayName(XmlSerializer xml, String name) throws IOException {
xml.startTag(XmlUtils.NS_WEBDAV, "displayname");
xml.text(name);
xml.endTag(XmlUtils.NS_WEBDAV, "displayname");
}
private void setColor(XmlSerializer xml, int color) throws IOException {
xml.startTag(XmlUtils.NS_APPLE_ICAL, "calendar-color");
xml.text(String.format("#%06X%02X", color & 0xFFFFFF, color >>> 24));
xml.endTag(XmlUtils.NS_APPLE_ICAL, "calendar-color");
}
OkHttpClient getHttpClient() {
return httpClient;
}

@ -20,6 +20,7 @@ import at.bitfire.dav4jvm.exception.DavException;
import at.bitfire.dav4jvm.exception.HttpException;
import at.bitfire.dav4jvm.exception.ServiceUnavailableException;
import at.bitfire.dav4jvm.exception.UnauthorizedException;
import at.bitfire.dav4jvm.property.CalendarColor;
import at.bitfire.dav4jvm.property.CalendarData;
import at.bitfire.dav4jvm.property.DisplayName;
import at.bitfire.dav4jvm.property.GetCTag;
@ -155,13 +156,22 @@ public class CaldavSynchronizer {
String url = resource.getHref().toString();
CaldavCalendar calendar = caldavDao.getCalendarByUrl(account.getUuid(), url);
String remoteName = resource.get(DisplayName.class).getDisplayName();
CalendarColor calendarColor = resource.get(CalendarColor.class);
int color = calendarColor == null ? 0 : calendarColor.getColor();
if (calendar == null) {
calendar = new CaldavCalendar();
calendar.setName(resource.get(DisplayName.class).getDisplayName());
calendar.setName(remoteName);
calendar.setAccount(account.getUuid());
calendar.setUrl(url);
calendar.setUuid(UUIDHelper.newUUID());
calendar.setColor(color);
caldavDao.insert(calendar);
} else if (!calendar.getName().equals(remoteName) || calendar.getColor() != color) {
calendar.setColor(color);
calendar.setName(remoteName);
caldavDao.update(calendar);
localBroadcastManager.broadcastRefreshList();
}
sync(calendar, resource, caldavClient.getHttpClient());
}
@ -183,14 +193,6 @@ public class CaldavSynchronizer {
HttpUrl httpUrl = resource.getHref();
pushLocalChanges(caldavCalendar, httpClient, httpUrl);
String remoteName = resource.get(DisplayName.class).getDisplayName();
if (!caldavCalendar.getName().equals(remoteName)) {
Timber.d("%s -> %s", caldavCalendar.getName(), remoteName);
caldavCalendar.setName(remoteName);
caldavDao.update(caldavCalendar);
localBroadcastManager.broadcastRefreshList();
}
SyncToken syncToken = resource.get(SyncToken.class);
GetCTag ctag = resource.get(GetCTag.class);
@Nullable String remoteCtag = null;

@ -5,7 +5,7 @@ import org.tasks.ui.CompletableViewModel;
@SuppressWarnings("WeakerAccess")
public class CreateCalendarViewModel extends CompletableViewModel<String> {
void createCalendar(CaldavClient client, CaldavAccount account, String name) {
run(() -> client.forAccount(account).makeCollection(name));
void createCalendar(CaldavClient client, CaldavAccount account, String name, int color) {
run(() -> client.forAccount(account).makeCollection(name, color));
}
}

@ -0,0 +1,76 @@
package org.tasks.caldav
import at.bitfire.dav4jvm.DavResource
import at.bitfire.dav4jvm.DavResource.Companion.MAX_REDIRECTS
import at.bitfire.dav4jvm.exception.*
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import java.io.IOException
import java.net.HttpURLConnection
import java.util.logging.Logger
class PatchableDavResource : DavResource {
constructor(client: OkHttpClient, url: HttpUrl, log: Logger) : super(client, url, log)
constructor(client: OkHttpClient, url: HttpUrl) : super(client, url)
/**
* Sends a PROPPATCH request to this resource. Follows up to [MAX_REDIRECTS] redirects.
*
* @throws IOException on I/O error
* @throws HttpException on HTTP error
*/
@Throws(IOException::class, HttpException::class)
fun propPatch(xmlBody: String?, callback: (response: Response) -> Unit) {
val rqBody = if (xmlBody != null) RequestBody.create(MIME_XML, xmlBody) else null
followRedirects {
httpClient.newCall(Request.Builder()
.method("PROPPATCH", rqBody)
.url(location)
.build()).execute()
}.use { response ->
checkStatus(response)
callback(response)
}
}
/**
* Checks the status from an HTTP response and throws an exception in case of an error.
*
* @throws HttpException in case of an HTTP error
*/
private fun checkStatus(response: Response) =
checkStatus(response.code(), response.message(), response)
/**
* Checks the status from an HTTP response and throws an exception in case of an error.
*
* @throws HttpException (with XML error names, if available) in case of an HTTP error
*/
private fun checkStatus(code: Int, message: String?, response: Response?) {
if (code / 100 == 2)
// everything OK
return
throw when (code) {
HttpURLConnection.HTTP_UNAUTHORIZED ->
if (response != null) UnauthorizedException(response) else UnauthorizedException(message)
HttpURLConnection.HTTP_FORBIDDEN ->
if (response != null) ForbiddenException(response) else ForbiddenException(message)
HttpURLConnection.HTTP_NOT_FOUND ->
if (response != null) NotFoundException(response) else NotFoundException(message)
HttpURLConnection.HTTP_CONFLICT ->
if (response != null) ConflictException(response) else ConflictException(message)
HttpURLConnection.HTTP_PRECON_FAILED ->
if (response != null) PreconditionFailedException(response) else PreconditionFailedException(message)
HttpURLConnection.HTTP_UNAVAILABLE ->
if (response != null) ServiceUnavailableException(response) else ServiceUnavailableException(message)
else ->
if (response != null) HttpException(response) else HttpException(code, message)
}
}
}

@ -0,0 +1,13 @@
package org.tasks.caldav;
import org.tasks.data.CaldavAccount;
import org.tasks.data.CaldavCalendar;
import org.tasks.ui.CompletableViewModel;
@SuppressWarnings("WeakerAccess")
public class UpdateCalendarViewModel extends CompletableViewModel<String> {
void updateCalendar(
CaldavClient client, CaldavAccount account, CaldavCalendar calendar, String name, int color) {
run(() -> client.forCalendar(account, calendar).updateCollection(name, color));
}
}

@ -25,7 +25,7 @@ public class EteSyncCalendarSettingsActivity extends BaseCaldavCalendarSettingsA
createCalendarViewModel.observe(this, this::createSuccessful, this::requestFailed);
deleteCalendarViewModel.observe(this, this::onDeleted, this::requestFailed);
updateCalendarViewModel.observe(this, uid -> updateAccount(), this::requestFailed);
updateCalendarViewModel.observe(this, uid -> updateCalendar(), this::requestFailed);
}
@Override

Loading…
Cancel
Save