mirror of
https://github.com/etesync/android
synced 2025-01-22 13:40:55 +00:00
Create/delete calendars
This commit is contained in:
parent
212cd8ddb0
commit
19bfe5c5f2
@ -68,6 +68,7 @@ dependencies {
|
||||
compile 'com.android.support:design:23.+'
|
||||
compile 'com.android.support:preference-v7:23.+'
|
||||
|
||||
compile 'com.github.yukuku:ambilwarna:2.0.1'
|
||||
compile project(':MemorizingTrustManager')
|
||||
|
||||
androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.1.2'
|
||||
|
@ -131,6 +131,8 @@
|
||||
<activity android:name=".ui.AccountSettingsActivity"/>
|
||||
<activity android:name=".ui.CreateAddressBookActivity"
|
||||
android:label="@string/create_address_book_title"/>
|
||||
<activity android:name=".ui.CreateCalendarActivity"
|
||||
android:label="@string/create_calendar_title"/>
|
||||
<activity
|
||||
android:name=".ui.DebugInfoActivity"
|
||||
android:exported="true"
|
||||
|
@ -28,4 +28,11 @@ public class DavUtils {
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
public static String ARGBtoCalDAVColor(int colorWithAlpha) {
|
||||
byte alpha = (byte)(colorWithAlpha >> 24);
|
||||
int color = colorWithAlpha & 0xFFFFFF;
|
||||
return String.format("#%06X%02X", color, alpha);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class DavService {
|
||||
service.accountName = values.getAsString(ServiceDB.Services.ACCOUNT_NAME);
|
||||
service.service = values.getAsString(ServiceDB.Services.SERVICE);
|
||||
service.principal = values.getAsString(ServiceDB.Services.PRINCIPAL);
|
||||
//service.lastRefresh = values.getAsLong(ServiceDB.Services.LAST_REFRESH);
|
||||
//FIXME service.lastRefresh = values.getAsLong(ServiceDB.Services.LAST_REFRESH);
|
||||
return service;
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,9 @@ public class CalendarsSyncAdapterService extends Service {
|
||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||
Constants.log.info("Starting calendar sync (" + authority + ")");
|
||||
|
||||
// required for ical4j and dav4android (ServiceLoader)
|
||||
Thread.currentThread().setContextClassLoader(getContext().getClassLoader());
|
||||
|
||||
try {
|
||||
updateLocalCalendars(provider, account);
|
||||
|
||||
|
@ -62,6 +62,9 @@ public class ContactsSyncAdapterService extends Service {
|
||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||
Constants.log.info("Starting address book sync (" + authority + ")");
|
||||
|
||||
// required for dav4android (ServiceLoader)
|
||||
Thread.currentThread().setContextClassLoader(getContext().getClassLoader());
|
||||
|
||||
long service = getService(account);
|
||||
CollectionInfo remote = remoteAddressBook(service);
|
||||
|
||||
|
@ -107,9 +107,6 @@ abstract public class SyncManager {
|
||||
this.authority = authority;
|
||||
this.syncResult = syncResult;
|
||||
|
||||
// required for ical4j and dav4android (ServiceLoader)
|
||||
Thread.currentThread().setContextClassLoader(context.getClassLoader());
|
||||
|
||||
// get account settings and log to file (if requested)
|
||||
settings = new AccountSettings(context, account);
|
||||
try {
|
||||
@ -423,7 +420,7 @@ abstract public class SyncManager {
|
||||
syncResult.stats.numDeletes++;
|
||||
} else {
|
||||
// contact is still on server, check whether it has been updated remotely
|
||||
GetETag getETag = (GetETag) remote.properties.get(GetETag.NAME);
|
||||
GetETag getETag = (GetETag)remote.properties.get(GetETag.NAME);
|
||||
if (getETag == null || getETag.eTag == null)
|
||||
throw new DavException("Server didn't provide ETag");
|
||||
String localETag = localResources.get(localName).getETag(),
|
||||
|
@ -65,6 +65,9 @@ public class TasksSyncAdapterService extends Service {
|
||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient providerClient, SyncResult syncResult) {
|
||||
Constants.log.info("Starting task sync (" + authority + ")");
|
||||
|
||||
// required for ical4j and dav4android (ServiceLoader)
|
||||
Thread.currentThread().setContextClassLoader(getContext().getClassLoader());
|
||||
|
||||
try {
|
||||
@Cleanup TaskProvider provider = TaskProvider.acquire(getContext().getContentResolver(), TaskProvider.ProviderName.OpenTasks);
|
||||
if (provider == null)
|
||||
|
@ -28,6 +28,7 @@ import android.content.ServiceConnection;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
@ -56,6 +57,8 @@ import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -93,13 +96,18 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
||||
|
||||
setContentView(R.layout.activity_account);
|
||||
|
||||
Drawable icMenu = Build.VERSION.SDK_INT >= 21 ? getDrawable(R.drawable.ic_menu_light) :
|
||||
getResources().getDrawable(R.drawable.ic_menu_light);
|
||||
|
||||
// CardDAV toolbar
|
||||
tbCardDAV = (Toolbar)findViewById(R.id.carddav_menu);
|
||||
tbCardDAV.setOverflowIcon(icMenu);
|
||||
tbCardDAV.inflateMenu(R.menu.carddav_actions);
|
||||
tbCardDAV.setOnMenuItemClickListener(this);
|
||||
|
||||
// CalDAV toolbar
|
||||
tbCalDAV = (Toolbar)findViewById(R.id.caldav_menu);
|
||||
tbCalDAV.setOverflowIcon(icMenu);
|
||||
tbCalDAV.inflateMenu(R.menu.caldav_actions);
|
||||
tbCalDAV.setOnMenuItemClickListener(this);
|
||||
|
||||
@ -165,6 +173,11 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
||||
intent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, accountInfo.caldav.id);
|
||||
startService(intent);
|
||||
break;
|
||||
case R.id.create_calendar:
|
||||
intent = new Intent(this, CreateCalendarActivity.class);
|
||||
intent.putExtra(CreateCalendarActivity.EXTRA_ACCOUNT, account);
|
||||
startActivity(intent);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -231,14 +244,14 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
||||
final ArrayAdapter<CollectionInfo> adapter = (ArrayAdapter)list.getAdapter();
|
||||
final CollectionInfo info = adapter.getItem(position);
|
||||
|
||||
PopupMenu popup = new PopupMenu(AccountActivity.this, view, Gravity.CENTER);
|
||||
PopupMenu popup = new PopupMenu(AccountActivity.this, view);
|
||||
popup.inflate(R.menu.account_collection_operations);
|
||||
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.delete_collection:
|
||||
DeleteCollectionFragment.newInstance(account, info).show(getSupportFragmentManager(), null);
|
||||
DeleteCollectionFragment.ConfirmDeleteCollectionFragment.newInstance(account, info).show(getSupportFragmentManager(), null);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@ -331,7 +344,6 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
||||
davService = (DavService.InfoBinder)service;
|
||||
davService.addRefreshingStatusListener(this, false);
|
||||
|
||||
SQLiteDatabase db;
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
@ -442,10 +454,12 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
||||
CheckBox checked = (CheckBox)v.findViewById(R.id.checked);
|
||||
checked.setChecked(info.selected);
|
||||
|
||||
View vColor = v.findViewById(R.id.color);
|
||||
if (info.color != null) {
|
||||
View vColor = v.findViewById(R.id.color);
|
||||
vColor.setVisibility(View.VISIBLE);
|
||||
vColor.setBackgroundColor(info.color);
|
||||
}
|
||||
} else
|
||||
vColor.setVisibility(View.GONE);
|
||||
|
||||
TextView tv = (TextView)v.findViewById(R.id.title);
|
||||
tv.setText(TextUtils.isEmpty(info.displayName) ? info.url : info.displayName);
|
||||
@ -462,10 +476,10 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
||||
tv.setVisibility(info.readOnly ? View.VISIBLE : View.GONE);
|
||||
|
||||
tv = (TextView)v.findViewById(R.id.events);
|
||||
tv.setVisibility(info.supportsVEVENT ? View.VISIBLE : View.GONE);
|
||||
tv.setVisibility(BooleanUtils.isTrue(info.supportsVEVENT) ? View.VISIBLE : View.GONE);
|
||||
|
||||
tv = (TextView)v.findViewById(R.id.tasks);
|
||||
tv.setVisibility(info.supportsVTODO ? View.VISIBLE : View.GONE);
|
||||
tv.setVisibility(BooleanUtils.isTrue(info.supportsVTODO) ? View.VISIBLE : View.GONE);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
@ -9,20 +9,25 @@
|
||||
package at.bitfire.davdroid.ui;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.EditText;
|
||||
import android.widget.SimpleAdapter;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
@ -78,7 +83,7 @@ public class CreateAddressBookActivity extends AppCompatActivity implements Load
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, AccountActivity.class);
|
||||
intent.putExtra(AccountActivity.EXTRA_ACCOUNT_NAME, account.name);
|
||||
startActivity(intent);
|
||||
NavUtils.navigateUpTo(this, intent);
|
||||
break;
|
||||
case R.id.create_address_book:
|
||||
createAddressBook();
|
||||
@ -92,71 +97,158 @@ public class CreateAddressBookActivity extends AppCompatActivity implements Load
|
||||
protected void createAddressBook() {
|
||||
Spinner spnrHomeSets = (Spinner)findViewById(R.id.homeset);
|
||||
HashMap<String, String> homeSet = (HashMap<String, String>)spnrHomeSets.getSelectedItem();
|
||||
|
||||
HttpUrl urlHomeSet = HttpUrl.parse(homeSet.get(ServiceDB.HomeSets.URL));
|
||||
|
||||
CollectionInfo info = new CollectionInfo();
|
||||
info.url = urlHomeSet.resolve("myAddrBook.vcf").toString();
|
||||
info.displayName = "myAddrBook";
|
||||
boolean ok = true;
|
||||
|
||||
new AddressBookCreator().execute( info);
|
||||
String displayName = ((EditText)findViewById(R.id.title)).getText().toString();
|
||||
if (!TextUtils.isEmpty(displayName))
|
||||
info.displayName = displayName;
|
||||
|
||||
EditText editPathSegment = (EditText)findViewById(R.id.path_segment);
|
||||
String pathSegment = editPathSegment.getText().toString();
|
||||
if (TextUtils.isEmpty(pathSegment)) { // TODO further validations
|
||||
editPathSegment.setError("MUST NOT BE EMPTY");
|
||||
ok = false;
|
||||
} else
|
||||
info.url = urlHomeSet.resolve(pathSegment).toString();
|
||||
|
||||
String description = ((EditText)findViewById(R.id.description)).getText().toString();
|
||||
if (!TextUtils.isEmpty(description))
|
||||
info.description = description;
|
||||
|
||||
if (ok)
|
||||
CreatingAddressBookFragment.newInstance(account, info).show(getSupportFragmentManager(), null);
|
||||
}
|
||||
|
||||
|
||||
// AsyncTask for creating the address book
|
||||
public static class CreatingAddressBookFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Exception> {
|
||||
protected static final String
|
||||
ARGS_ACCOUNT = "account",
|
||||
ARGS_COLLECTION_INFO = "collectionInfo";
|
||||
|
||||
class AddressBookCreator extends AsyncTask<CollectionInfo, Void, Exception> {
|
||||
@Override
|
||||
protected void onPostExecute(Exception e) {
|
||||
String msg = (e == null) ? "Created!" : e.getLocalizedMessage();
|
||||
Toast.makeText(CreateAddressBookActivity.this, msg, Toast.LENGTH_LONG).show();
|
||||
public static CreatingAddressBookFragment newInstance(Account account, CollectionInfo info) {
|
||||
CreatingAddressBookFragment frag = new CreatingAddressBookFragment();
|
||||
Bundle args = new Bundle(2);
|
||||
args.putParcelable(ARGS_ACCOUNT, account);
|
||||
args.putSerializable(ARGS_COLLECTION_INFO, info);
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Exception doInBackground(CollectionInfo[] infoArray) {
|
||||
AccountSettings accountSettings = new AccountSettings(CreateAddressBookActivity.this, account);
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
CollectionInfo info = infoArray[0];
|
||||
OkHttpClient client = HttpClient.create(CreateAddressBookActivity.this);
|
||||
client = HttpClient.addAuthentication(client, accountSettings.username(), accountSettings.password(), accountSettings.preemptiveAuth());
|
||||
getLoaderManager().initLoader(0, getArguments(), this);
|
||||
}
|
||||
|
||||
DavResource addressBook = new DavResource(null, client, HttpUrl.parse(info.url));
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Dialog dialog = new ProgressDialog.Builder(getActivity())
|
||||
.setTitle(R.string.create_address_book_creating)
|
||||
.setMessage(R.string.please_wait)
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
XmlSerializer serializer = XmlUtils.newSerializer();
|
||||
serializer.setOutput(writer);
|
||||
serializer.startDocument("UTF-8", null);
|
||||
serializer.setPrefix("", XmlUtils.NS_WEBDAV);
|
||||
serializer.setPrefix("CARD", XmlUtils.NS_CARDDAV);
|
||||
@Override
|
||||
public Loader<Exception> onCreateLoader(int id, Bundle args) {
|
||||
Account account = (Account)args.getParcelable(ARGS_ACCOUNT);
|
||||
CollectionInfo info = (CollectionInfo)args.getSerializable(ARGS_COLLECTION_INFO);
|
||||
return new AddressBookCreator(getActivity(), account, info);
|
||||
}
|
||||
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "mkcol");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "set");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "prop");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "resourcetype");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "collection");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "collection");
|
||||
serializer.startTag(XmlUtils.NS_CARDDAV, "addressbook");
|
||||
serializer.endTag(XmlUtils.NS_CARDDAV, "addressbook");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "resourcetype");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "displayname");
|
||||
serializer.text(info.displayName);
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "displayname");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "prop");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "set");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "mkcol");
|
||||
serializer.endDocument();
|
||||
} catch (IOException e) {
|
||||
Constants.log.error("Couldn't assemble MKCOL request", e);
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Exception> loader, Exception exception) {
|
||||
dismissAllowingStateLoss();
|
||||
|
||||
if (exception == null)
|
||||
getActivity().finish();
|
||||
else
|
||||
Toast.makeText(getActivity(), exception.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Exception> loader) {
|
||||
}
|
||||
|
||||
protected static class AddressBookCreator extends AsyncTaskLoader<Exception> {
|
||||
final Account account;
|
||||
final CollectionInfo info;
|
||||
final ServiceDB.OpenHelper dbHelper;
|
||||
|
||||
public AddressBookCreator(Context context, Account account, CollectionInfo collectionInfo) {
|
||||
super(context);
|
||||
this.account = account;
|
||||
info = collectionInfo;
|
||||
dbHelper = new ServiceDB.OpenHelper(context);
|
||||
}
|
||||
|
||||
String error = null;
|
||||
try {
|
||||
addressBook.mkCol(writer.toString());
|
||||
} catch (IOException|HttpException e) {
|
||||
return e;
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception loadInBackground() {
|
||||
OkHttpClient client = HttpClient.create(getContext());
|
||||
client = HttpClient.addAuthentication(client, new AccountSettings(getContext(), account));
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
XmlSerializer serializer = XmlUtils.newSerializer();
|
||||
serializer.setOutput(writer);
|
||||
serializer.startDocument("UTF-8", null);
|
||||
serializer.setPrefix("", XmlUtils.NS_WEBDAV);
|
||||
serializer.setPrefix("CARD", XmlUtils.NS_CARDDAV);
|
||||
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "mkcol");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "set");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "prop");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "resourcetype");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "collection");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "collection");
|
||||
serializer.startTag(XmlUtils.NS_CARDDAV, "addressbook");
|
||||
serializer.endTag(XmlUtils.NS_CARDDAV, "addressbook");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "resourcetype");
|
||||
if (info.displayName != null) {
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "displayname");
|
||||
serializer.text(info.displayName);
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "displayname");
|
||||
}
|
||||
if (info.description != null) {
|
||||
serializer.startTag(XmlUtils.NS_CARDDAV, "addressbook-description");
|
||||
serializer.text(info.description);
|
||||
serializer.endTag(XmlUtils.NS_CARDDAV, "addressbook-description");
|
||||
}
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "prop");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "set");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "mkcol");
|
||||
serializer.endDocument();
|
||||
} catch (IOException e) {
|
||||
Constants.log.error("Couldn't assemble MKCOL request", e);
|
||||
}
|
||||
|
||||
DavResource addressBook = new DavResource(null, client, HttpUrl.parse(info.url));
|
||||
try {
|
||||
addressBook.mkCol(writer.toString());
|
||||
|
||||
// TODO
|
||||
/*SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||
db.insert(ServiceDB.Collections._TABLE, null, info.toDB());*/
|
||||
|
||||
// TODO add to database
|
||||
} catch (IOException|HttpException e) {
|
||||
return e;
|
||||
} finally {
|
||||
dbHelper.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,12 +286,11 @@ public class CreateAddressBookActivity extends AppCompatActivity implements Load
|
||||
|
||||
private static class AccountLoader extends AsyncTaskLoader<AccountInfo> {
|
||||
private final Account account;
|
||||
ServiceDB.OpenHelper dbHelper;
|
||||
private final ServiceDB.OpenHelper dbHelper;
|
||||
|
||||
public AccountLoader(Context context, Account account) {
|
||||
super(context);
|
||||
this.account = account;
|
||||
|
||||
dbHelper = new ServiceDB.OpenHelper(context);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the GNU Public License v3.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
package at.bitfire.davdroid.ui;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.AppCompatCheckBox;
|
||||
import android.support.v7.widget.AppCompatRadioButton;
|
||||
import android.support.v7.widget.AppCompatSpinner;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.webkit.URLUtil;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.fortuna.ical4j.data.CalendarBuilder;
|
||||
import net.fortuna.ical4j.model.Calendar;
|
||||
import net.fortuna.ical4j.model.TimeZoneRegistry;
|
||||
import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
|
||||
import net.fortuna.ical4j.util.TimeZones;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.model.CollectionInfo;
|
||||
import at.bitfire.davdroid.model.ServiceDB;
|
||||
import at.bitfire.ical4android.DateUtils;
|
||||
import lombok.Cleanup;
|
||||
import okhttp3.HttpUrl;
|
||||
import yuku.ambilwarna.AmbilWarnaDialog;
|
||||
import yuku.ambilwarna.AmbilWarnaSquare;
|
||||
|
||||
public class CreateCalendarActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<CreateCalendarActivity.AccountInfo> {
|
||||
public static final String EXTRA_ACCOUNT = "account";
|
||||
|
||||
protected Account account;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
account = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
setContentView(R.layout.activity_create_calendar);
|
||||
final View colorSquare = findViewById(R.id.color);
|
||||
colorSquare.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
new AmbilWarnaDialog(CreateCalendarActivity.this, ((ColorDrawable)colorSquare.getBackground()).getColor(), true, new AmbilWarnaDialog.OnAmbilWarnaListener() {
|
||||
@Override
|
||||
public void onCancel(AmbilWarnaDialog dialog) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOk(AmbilWarnaDialog dialog, int color) {
|
||||
colorSquare.setBackgroundColor(color);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
});
|
||||
|
||||
getSupportLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.activity_create_calendar, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onCreateCalendar(MenuItem item) {
|
||||
boolean ok = true;
|
||||
CollectionInfo info = new CollectionInfo();
|
||||
|
||||
AppCompatSpinner spinner = (AppCompatSpinner)findViewById(R.id.home_set);
|
||||
String homeSet = (String)spinner.getSelectedItem();
|
||||
|
||||
EditText edit = (EditText)findViewById(R.id.display_name);
|
||||
info.displayName = edit.getText().toString();
|
||||
if (TextUtils.isEmpty(info.displayName)) {
|
||||
edit.setError("Enter a calendar title.");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
edit = (EditText)findViewById(R.id.description);
|
||||
info.description = StringUtils.trimToNull(edit.getText().toString());
|
||||
|
||||
View view = findViewById(R.id.color);
|
||||
info.color = ((ColorDrawable)view.getBackground()).getColor();
|
||||
|
||||
spinner = (AppCompatSpinner)findViewById(R.id.time_zone);
|
||||
net.fortuna.ical4j.model.TimeZone tz = DateUtils.tzRegistry.getTimeZone((String)spinner.getSelectedItem());
|
||||
if (tz != null) {
|
||||
Calendar cal = new Calendar();
|
||||
cal.getComponents().add(tz.getVTimeZone());
|
||||
info.timeZone = cal.toString();
|
||||
}
|
||||
|
||||
RadioGroup typeGroup = (RadioGroup)findViewById(R.id.type);
|
||||
switch (typeGroup.getCheckedRadioButtonId()) {
|
||||
case R.id.type_events:
|
||||
info.supportsVEVENT = true;
|
||||
break;
|
||||
case R.id.type_tasks:
|
||||
info.supportsVTODO = true;
|
||||
break;
|
||||
case R.id.type_events_and_tasks:
|
||||
info.supportsVEVENT = true;
|
||||
info.supportsVTODO = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
info.type = CollectionInfo.Type.CALENDAR;
|
||||
info.url = HttpUrl.parse(homeSet).resolve(UUID.randomUUID().toString() + "/").toString();
|
||||
CreateCollectionFragment.newInstance(account, info).show(getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Loader<AccountInfo> onCreateLoader(int id, Bundle args) {
|
||||
return new AccountInfoLoader(this, account);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<AccountInfo> loader, AccountInfo info) {
|
||||
AppCompatSpinner spinner = (AppCompatSpinner)findViewById(R.id.time_zone);
|
||||
String[] timeZones = TimeZone.getAvailableIDs();
|
||||
spinner.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, timeZones));
|
||||
// select system time zone
|
||||
String defaultTimeZone = TimeZone.getDefault().getID();
|
||||
for (int i = 0; i < timeZones.length; i++)
|
||||
if (timeZones[i].equals(defaultTimeZone)) {
|
||||
spinner.setSelection(i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (info != null) {
|
||||
spinner = (AppCompatSpinner)findViewById(R.id.home_set);
|
||||
spinner.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, info.homeSets));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<AccountInfo> loader) {
|
||||
}
|
||||
|
||||
protected static class AccountInfo {
|
||||
List<String> homeSets = new LinkedList<>();
|
||||
}
|
||||
|
||||
protected static class AccountInfoLoader extends AsyncTaskLoader<AccountInfo> {
|
||||
private final Account account;
|
||||
private final ServiceDB.OpenHelper dbHelper;
|
||||
|
||||
public AccountInfoLoader(Context context, Account account) {
|
||||
super(context);
|
||||
this.account = account;
|
||||
dbHelper = new ServiceDB.OpenHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccountInfo loadInBackground() {
|
||||
final AccountInfo info = new AccountInfo();
|
||||
|
||||
// find DAV service and home sets
|
||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||
try {
|
||||
@Cleanup Cursor cursorService = db.query(ServiceDB.Services._TABLE, new String[] { ServiceDB.Services.ID },
|
||||
ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?",
|
||||
new String[] { account.name, ServiceDB.Services.SERVICE_CALDAV }, null, null, null);
|
||||
if (!cursorService.moveToNext())
|
||||
return null;
|
||||
String strServiceID = cursorService.getString(0);
|
||||
|
||||
@Cleanup Cursor cursorHomeSets = db.query(ServiceDB.HomeSets._TABLE, new String[] { ServiceDB.HomeSets.URL },
|
||||
ServiceDB.HomeSets.SERVICE_ID + "=?", new String[] { strServiceID }, null, null, null);
|
||||
while (cursorHomeSets.moveToNext())
|
||||
info.homeSets.add(cursorHomeSets.getString(0));
|
||||
} finally {
|
||||
dbHelper.close();
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the GNU Public License v3.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
package at.bitfire.davdroid.ui;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import at.bitfire.dav4android.DavResource;
|
||||
import at.bitfire.dav4android.XmlUtils;
|
||||
import at.bitfire.dav4android.exception.HttpException;
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.DavUtils;
|
||||
import at.bitfire.davdroid.HttpClient;
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.model.CollectionInfo;
|
||||
import at.bitfire.davdroid.model.ServiceDB;
|
||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||
import at.bitfire.ical4android.DateUtils;
|
||||
import lombok.Cleanup;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class CreateCollectionFragment extends DialogFragment {
|
||||
private static final String
|
||||
ARG_ACCOUNT = "account",
|
||||
ARG_COLLECTION_INFO = "collectionInfo";
|
||||
|
||||
public static CreateCollectionFragment newInstance(Account account, CollectionInfo info) {
|
||||
CreateCollectionFragment frag = new CreateCollectionFragment();
|
||||
Bundle args = new Bundle(2);
|
||||
args.putParcelable(ARG_ACCOUNT, account);
|
||||
args.putSerializable(ARG_COLLECTION_INFO, info);
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
|
||||
new CreateCollectionTask().execute(getArguments());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Dialog dialog = new ProgressDialog.Builder(getContext())
|
||||
.setTitle(R.string.create_collection_creating)
|
||||
.setMessage(R.string.please_wait)
|
||||
.create();
|
||||
setCancelable(false);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
||||
protected class CreateCollectionTask extends AsyncTask<Bundle, Void, Exception> {
|
||||
@Override
|
||||
protected Exception doInBackground(Bundle... params) {
|
||||
Bundle args = params[0];
|
||||
Account account = args.getParcelable(ARG_ACCOUNT);
|
||||
CollectionInfo info = (CollectionInfo)args.getSerializable(ARG_COLLECTION_INFO);
|
||||
|
||||
OkHttpClient client = HttpClient.create(getContext());
|
||||
client = HttpClient.addAuthentication(client, new AccountSettings(getContext(), account));
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
XmlSerializer serializer = XmlUtils.newSerializer();
|
||||
serializer.setOutput(writer);
|
||||
serializer.startDocument("UTF-8", null);
|
||||
serializer.setPrefix("", XmlUtils.NS_WEBDAV);
|
||||
serializer.setPrefix("CAL", XmlUtils.NS_CALDAV);
|
||||
serializer.setPrefix("CARD", XmlUtils.NS_CARDDAV);
|
||||
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "mkcol");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "set");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "prop");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "resourcetype");
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "collection");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "collection");
|
||||
if (info.type == CollectionInfo.Type.ADDRESS_BOOK) {
|
||||
serializer.startTag(XmlUtils.NS_CARDDAV, "addressbook");
|
||||
serializer.endTag(XmlUtils.NS_CARDDAV, "addressbook");
|
||||
} else if (info.type == CollectionInfo.Type.CALENDAR) {
|
||||
serializer.startTag(XmlUtils.NS_CALDAV, "calendar");
|
||||
serializer.endTag(XmlUtils.NS_CALDAV, "calendar");
|
||||
}
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "resourcetype");
|
||||
if (info.displayName != null) {
|
||||
serializer.startTag(XmlUtils.NS_WEBDAV, "displayname");
|
||||
serializer.text(info.displayName);
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "displayname");
|
||||
}
|
||||
|
||||
// addressbook-specific properties
|
||||
if (info.type == CollectionInfo.Type.ADDRESS_BOOK) {
|
||||
if (info.description != null) {
|
||||
serializer.startTag(XmlUtils.NS_CARDDAV, "addressbook-description");
|
||||
serializer.text(info.description);
|
||||
serializer.endTag(XmlUtils.NS_CARDDAV, "addressbook-description");
|
||||
}
|
||||
}
|
||||
|
||||
// calendar-specific properties
|
||||
if (info.type == CollectionInfo.Type.CALENDAR) {
|
||||
if (info.description != null) {
|
||||
serializer.startTag(XmlUtils.NS_CALDAV, "calendar-description");
|
||||
serializer.text(info.description);
|
||||
serializer.endTag(XmlUtils.NS_CALDAV, "calendar-description");
|
||||
}
|
||||
|
||||
if (info.color != null) {
|
||||
serializer.startTag(XmlUtils.NS_APPLE_ICAL, "calendar-color");
|
||||
serializer.text(DavUtils.ARGBtoCalDAVColor(info.color));
|
||||
serializer.endTag(XmlUtils.NS_APPLE_ICAL, "calendar-color");
|
||||
}
|
||||
|
||||
if (info.timeZone != null) {
|
||||
serializer.startTag(XmlUtils.NS_CALDAV, "calendar-timezone");
|
||||
serializer.cdsect(info.timeZone);
|
||||
serializer.endTag(XmlUtils.NS_CALDAV, "calendar-timezone");
|
||||
}
|
||||
|
||||
serializer.startTag(XmlUtils.NS_CALDAV, "supported-calendar-component-set");
|
||||
if (BooleanUtils.isTrue(info.supportsVEVENT)) {
|
||||
serializer.startTag(XmlUtils.NS_CALDAV, "comp");
|
||||
serializer.attribute(null, "name", "VEVENT");
|
||||
serializer.endTag(XmlUtils.NS_CALDAV, "comp");
|
||||
}
|
||||
if (BooleanUtils.isTrue(info.supportsVTODO)) {
|
||||
serializer.startTag(XmlUtils.NS_CALDAV, "comp");
|
||||
serializer.attribute(null, "name", "VTODO");
|
||||
serializer.endTag(XmlUtils.NS_CALDAV, "comp");
|
||||
}
|
||||
serializer.endTag(XmlUtils.NS_CALDAV, "supported-calendar-component-set");
|
||||
}
|
||||
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "prop");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "set");
|
||||
serializer.endTag(XmlUtils.NS_WEBDAV, "mkcol");
|
||||
serializer.endDocument();
|
||||
} catch (IOException e) {
|
||||
Constants.log.error("Couldn't assemble Extended MKCOL request", e);
|
||||
}
|
||||
|
||||
ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
|
||||
DavResource collection = new DavResource(null, client, HttpUrl.parse(info.url));
|
||||
try {
|
||||
// create collection on remote server
|
||||
collection.mkCol(writer.toString());
|
||||
|
||||
// now insert collection into database:
|
||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||
|
||||
// 1. find service ID
|
||||
String serviceType = null;
|
||||
if (info.type == CollectionInfo.Type.ADDRESS_BOOK)
|
||||
serviceType = ServiceDB.Services.SERVICE_CARDDAV;
|
||||
else if (info.type == CollectionInfo.Type.CALENDAR)
|
||||
serviceType = ServiceDB.Services.SERVICE_CALDAV;
|
||||
else
|
||||
throw new IllegalArgumentException("Collection must be an address book or calendar");
|
||||
@Cleanup Cursor c = db.query(ServiceDB.Services._TABLE, new String[] { ServiceDB.Services.ID },
|
||||
ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?",
|
||||
new String[] { account.name, serviceType }, null, null, null
|
||||
);
|
||||
if (!c.moveToNext())
|
||||
throw new IllegalStateException();
|
||||
long serviceID = c.getLong(0);
|
||||
|
||||
// 2. add collection to service
|
||||
ContentValues values = info.toDB();
|
||||
values.put(ServiceDB.Collections.SERVICE_ID, serviceID);
|
||||
db.insert(ServiceDB.Collections._TABLE, null, values);
|
||||
} catch(IOException|HttpException|IllegalStateException e) {
|
||||
return e;
|
||||
} finally {
|
||||
dbHelper.close();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Exception e) {
|
||||
dismissAllowingStateLoss();
|
||||
|
||||
Activity parent = getActivity();
|
||||
if (parent != null) {
|
||||
if (e != null)
|
||||
Toast.makeText(parent, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||
else
|
||||
parent.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -12,6 +12,7 @@ import android.accounts.Account;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
@ -19,14 +20,16 @@ import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import at.bitfire.dav4android.DavResource;
|
||||
import at.bitfire.dav4android.exception.HttpException;
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.HttpClient;
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.model.CollectionInfo;
|
||||
import at.bitfire.davdroid.model.ServiceDB;
|
||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||
@ -38,15 +41,6 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
|
||||
ARG_ACCOUNT = "account",
|
||||
ARG_COLLECTION_INFO = "collectionInfo";
|
||||
|
||||
public static DeleteCollectionFragment newInstance(Account account, CollectionInfo collectionInfo) {
|
||||
DeleteCollectionFragment frag = new DeleteCollectionFragment();
|
||||
Bundle args = new Bundle(2);
|
||||
args.putParcelable(ARG_ACCOUNT, account);
|
||||
args.putSerializable(ARG_COLLECTION_INFO, collectionInfo);
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -57,11 +51,10 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Dialog dialog = new ProgressDialog.Builder(getContext())
|
||||
.setTitle("Deleting collection")
|
||||
.setMessage("Deleting collection from server, please wait.")
|
||||
.setCancelable(false)
|
||||
.setTitle(R.string.delete_collection_deleting_collection)
|
||||
.setMessage(R.string.please_wait)
|
||||
.create();
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
setCancelable(false);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@ -79,8 +72,8 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Exception> loader, Exception exception) {
|
||||
String msg = (exception == null) ? "Collection deleted" : exception.getLocalizedMessage();
|
||||
Toast.makeText(getContext(), msg, Toast.LENGTH_LONG).show();
|
||||
if (exception != null)
|
||||
Toast.makeText(getContext(), exception.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||
dismissAllowingStateLoss();
|
||||
|
||||
AccountActivity activity = (AccountActivity)getActivity();
|
||||
@ -113,23 +106,64 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
|
||||
|
||||
@Override
|
||||
public Exception loadInBackground() {
|
||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||
|
||||
OkHttpClient httpClient = HttpClient.create(getContext());
|
||||
httpClient = HttpClient.addAuthentication(httpClient, new AccountSettings(getContext(), account));
|
||||
|
||||
DavResource collection = new DavResource(null, httpClient, url);
|
||||
try {
|
||||
// delete collection from server
|
||||
collection.delete(null);
|
||||
|
||||
// delete collection locally
|
||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||
db.delete(ServiceDB.Collections._TABLE, ServiceDB.Collections.ID + "=?", new String[] { String.valueOf(collectionId) });
|
||||
|
||||
return null;
|
||||
} catch (IOException|HttpException e) {
|
||||
return e;
|
||||
} finally {
|
||||
db.close();
|
||||
dbHelper.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ConfirmDeleteCollectionFragment extends DialogFragment {
|
||||
|
||||
public static ConfirmDeleteCollectionFragment newInstance(Account account, CollectionInfo collectionInfo) {
|
||||
ConfirmDeleteCollectionFragment frag = new ConfirmDeleteCollectionFragment();
|
||||
Bundle args = new Bundle(2);
|
||||
args.putParcelable(ARG_ACCOUNT, account);
|
||||
args.putSerializable(ARG_COLLECTION_INFO, collectionInfo);
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
CollectionInfo collectionInfo = (CollectionInfo)getArguments().getSerializable(ARG_COLLECTION_INFO);
|
||||
String name = TextUtils.isEmpty(collectionInfo.displayName) ? collectionInfo.url : collectionInfo.displayName;
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setTitle(R.string.delete_collection_confirm_title)
|
||||
.setMessage(getString(R.string.delete_collection_confirm_warning, name))
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
DialogFragment frag = new DeleteCollectionFragment();
|
||||
frag.setArguments(getArguments());
|
||||
frag.show(getFragmentManager(), null);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dismiss();
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
17
app/src/main/res/drawable/ic_menu_light.xml
Normal file
17
app/src/main/res/drawable/ic_menu_light.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<!--
|
||||
~ Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||
~ All rights reserved. This program and the accompanying materials
|
||||
~ are made available under the terms of the GNU Public License v3.0
|
||||
~ which accompanies this distribution, and is available at
|
||||
~ http://www.gnu.org/licenses/gpl.html
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M3,18h18v-2H3v2zm0,-5h18v-2H3v2zm0,-7v2h18V6H3z"/>
|
||||
</vector>
|
@ -22,4 +22,22 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Title"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/path_segment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Path segment (collection name)"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Description"/>
|
||||
|
||||
</LinearLayout>
|
121
app/src/main/res/layout/activity_create_calendar.xml
Normal file
121
app/src/main/res/layout/activity_create_calendar.xml
Normal file
@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||
~ All rights reserved. This program and the accompanying materials
|
||||
~ are made available under the terms of the GNU Public License v3.0
|
||||
~ which accompanies this distribution, and is available at
|
||||
~ http://www.gnu.org/licenses/gpl.html
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Create CalDAV collection"
|
||||
android:textAppearance="@style/TextView.Heading"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Home set:"/>
|
||||
<android.support.v7.widget.AppCompatSpinner
|
||||
android:id="@+id/home_set"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Display name (title) of this collection:"/>
|
||||
<EditText
|
||||
android:id="@+id/display_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="My Calendar"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Description (optional):"/>
|
||||
<EditText
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="Calendar description"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/color"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:background="@color/orangeA700"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Set a collection color"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Time zone:"/>
|
||||
<android.support.v7.widget.AppCompatSpinner
|
||||
android:id="@+id/time_zone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Collection type"
|
||||
android:textAppearance="@style/TextView.Heading"/>
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/type"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<android.support.v7.widget.AppCompatRadioButton
|
||||
android:id="@+id/type_events"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="Calendar (only events)"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatRadioButton
|
||||
android:id="@+id/type_tasks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Task list (only tasks)"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatRadioButton
|
||||
android:id="@+id/type_events_and_tasks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Combined (events and tasks)"/>
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
17
app/src/main/res/menu/activity_create_calendar.xml
Normal file
17
app/src/main/res/menu/activity_create_calendar.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||
~ All rights reserved. This program and the accompanying materials
|
||||
~ are made available under the terms of the GNU Public License v3.0
|
||||
~ which accompanies this distribution, and is available at
|
||||
~ http://www.gnu.org/licenses/gpl.html
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item android:title="Create calendar"
|
||||
android:onClick="onCreateCalendar"
|
||||
app:showAsAction="always"/>
|
||||
|
||||
</menu>
|
@ -13,7 +13,7 @@
|
||||
<string name="app_name">DAVdroid</string>
|
||||
<string name="help">Help</string>
|
||||
<string name="manage_accounts">Manage accounts</string>
|
||||
<string name="please_wait">Please wait</string>
|
||||
<string name="please_wait">Please wait …</string>
|
||||
<string name="send">Send</string>
|
||||
<string name="skip">Skip</string>
|
||||
|
||||
@ -170,8 +170,14 @@
|
||||
<item>Once a day</item>
|
||||
</string-array>
|
||||
|
||||
<!-- CreateAddressBookActivity -->
|
||||
<!-- collection management -->
|
||||
<string name="create_address_book_title">Create address book</string>
|
||||
<string name="create_address_book_creating">Creating address book</string>
|
||||
<string name="create_calendar_title">Create calendar</string>
|
||||
<string name="create_collection_creating">Creating collection</string>
|
||||
<string name="delete_collection_confirm_title">Are you sure?</string>
|
||||
<string name="delete_collection_confirm_warning">This collection (%s) and all its entries from the server will be removed from the server.</string>
|
||||
<string name="delete_collection_deleting_collection">Deleting collection</string>
|
||||
|
||||
<string name="settings_android_update_title">Android version update</string>
|
||||
<string name="settings_android_update_description">Android version updates may have an impact on how DAVdroid works. If there are problems, please delete your DAVdroid accounts and add them again.</string>
|
||||
|
@ -92,10 +92,10 @@
|
||||
|
||||
<!-- text content -->
|
||||
|
||||
<!-- <style name="TextView.Heading" parent="AppTheme">
|
||||
<item name="android:padding">5dp</item>
|
||||
<item name="android:background">#7ca42b</item>
|
||||
<item name="android:textColor">@color/white</item>
|
||||
</style> -->
|
||||
<style name="TextView.Heading" parent="AppTheme">
|
||||
<item name="android:layout_marginBottom">8dp</item>
|
||||
<item name="android:textSize">22sp</item>
|
||||
<item name="android:textColor">@color/orangeA700</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -1 +1 @@
|
||||
Subproject commit 0e9522bb3a2d4e33bac214883f8316b91be0960e
|
||||
Subproject commit fd19c6531ad5c1cbe210a7e70f5781cbfd5744a7
|
Loading…
Reference in New Issue
Block a user