Added inserting calendar events

This commit is contained in:
M66B 2019-09-30 13:40:14 +02:00
parent c674b8a024
commit 2fd7e4a7cd
4 changed files with 95 additions and 26 deletions

2
FAQ.md
View File

@ -2329,7 +2329,7 @@ You can reset all questions set to not to be asked again in the three-dots overf
Calendar and contact management can better be done in a separate, specialized app
and is too complex to add to FairEmail, which is in itself already complex enough.
Note that FairEmail does support replying to calendar invites.
Note that FairEmail does support replying to calendar invites and adding calendar invites to your personal calendar.
Please see here for some open source apps:

View File

@ -45,6 +45,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.Settings;
import android.text.Editable;
@ -155,7 +156,6 @@ import biweekly.parameter.ParticipationStatus;
import biweekly.property.Attendee;
import biweekly.property.Method;
import biweekly.property.Organizer;
import biweekly.property.Summary;
import biweekly.util.ICalDate;
import static android.app.Activity.RESULT_OK;
@ -328,6 +328,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private Button btnCalendarAccept;
private Button btnCalendarDecline;
private Button btnCalendarMaybe;
private ImageButton ibCalendar;
private ContentLoadingProgressBar pbCalendarWait;
private RecyclerView rvImage;
@ -440,6 +441,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
btnCalendarAccept = vsBody.findViewById(R.id.btnCalendarAccept);
btnCalendarDecline = vsBody.findViewById(R.id.btnCalendarDecline);
btnCalendarMaybe = vsBody.findViewById(R.id.btnCalendarMaybe);
ibCalendar = vsBody.findViewById(R.id.ibCalendar);
pbCalendarWait = vsBody.findViewById(R.id.pbCalendarWait);
rvAttachment = attachments.findViewById(R.id.rvAttachment);
@ -544,6 +546,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
btnCalendarAccept.setOnClickListener(this);
btnCalendarDecline.setOnClickListener(this);
btnCalendarMaybe.setOnClickListener(this);
ibCalendar.setOnClickListener(this);
gestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
@ -595,6 +598,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
btnCalendarAccept.setOnClickListener(null);
btnCalendarDecline.setOnClickListener(null);
btnCalendarMaybe.setOnClickListener(null);
ibCalendar.setOnClickListener(null);
}
}
@ -1353,7 +1357,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
VEvent event = icalendar.getEvents().get(0);
Summary summary = event.getSummary();
String summary = event.getSummary() == null ? null : event.getSummary().getValue();
ICalDate start = event.getDateStart() == null ? null : event.getDateStart().getValue();
ICalDate end = event.getDateEnd() == null ? null : event.getDateEnd().getValue();
@ -1375,7 +1379,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
Organizer organizer = event.getOrganizer();
tvCalendarSummary.setText(summary == null ? null : summary.getValue());
tvCalendarSummary.setText(summary);
tvCalendarSummary.setVisibility(summary == null ? View.GONE : View.VISIBLE);
tvCalendarStart.setText(start == null ? null : DTF.format(start.getTime()));
@ -1411,9 +1415,9 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
args.putLong("id", message.id);
args.putInt("action", action);
new SimpleTask<File>() {
new SimpleTask<Object>() {
@Override
protected File onExecute(Context context, Bundle args) throws Throwable {
protected Object onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id");
int action = args.getInt("action");
@ -1430,6 +1434,44 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ICalendar icalendar = Biweekly.parse(file).first();
VEvent event = icalendar.getEvents().get(0);
if (action == R.id.ibCalendar) {
String summary = event.getSummary() == null ? null : event.getSummary().getValue();
ICalDate start = event.getDateStart() == null ? null : event.getDateStart().getValue();
ICalDate end = event.getDateEnd() == null ? null : event.getDateEnd().getValue();
String location = event.getLocation() == null ? null : event.getLocation().getValue();
List<String> attendee = new ArrayList<>();
for (Attendee a : event.getAttendees()) {
String email = a.getEmail();
if (!TextUtils.isEmpty(email))
attendee.add(email);
}
// https://developer.android.com/guide/topics/providers/calendar-provider.html#intent-insert
Intent intent = new Intent(Intent.ACTION_INSERT)
.setData(CalendarContract.Events.CONTENT_URI)
.putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY);
if (summary != null)
intent.putExtra(CalendarContract.Events.TITLE, summary);
if (start != null)
intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, start.getTime());
if (end != null)
intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end.getTime());
if (location != null)
intent.putExtra(CalendarContract.Events.EVENT_LOCATION, location);
if (attendee.size() > 0)
intent.putExtra(Intent.EXTRA_EMAIL, TextUtils.join(",", attendee));
return intent;
}
// https://tools.ietf.org/html/rfc5546#section-4.2.2
VEvent ev = new VEvent();
ev.setOrganizer(event.getOrganizer());
@ -1473,26 +1515,30 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
}
@Override
protected void onExecuted(Bundle args, File ics) {
String status = null;
switch (action) {
case R.id.btnCalendarAccept:
status = context.getString(R.string.title_icalendar_accept);
break;
case R.id.btnCalendarDecline:
status = context.getString(R.string.title_icalendar_decline);
break;
case R.id.btnCalendarMaybe:
status = context.getString(R.string.title_icalendar_maybe);
break;
}
protected void onExecuted(Bundle args, Object result) {
if (result instanceof File) {
String status = null;
switch (action) {
case R.id.btnCalendarAccept:
status = context.getString(R.string.title_icalendar_accept);
break;
case R.id.btnCalendarDecline:
status = context.getString(R.string.title_icalendar_decline);
break;
case R.id.btnCalendarMaybe:
status = context.getString(R.string.title_icalendar_maybe);
break;
}
Intent reply = new Intent(context, ActivityCompose.class)
.putExtra("action", "participation")
.putExtra("reference", args.getLong("id"))
.putExtra("ics", ics)
.putExtra("status", status);
context.startActivity(reply);
Intent reply = new Intent(context, ActivityCompose.class)
.putExtra("action", "participation")
.putExtra("reference", args.getLong("id"))
.putExtra("ics", (File) result)
.putExtra("status", status);
context.startActivity(reply);
} else if (result instanceof Intent) {
context.startActivity((Intent) result);
}
}
@Override
@ -1572,6 +1618,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
case R.id.btnCalendarAccept:
case R.id.btnCalendarDecline:
case R.id.btnCalendarMaybe:
case R.id.ibCalendar:
onActionCalendar(message, view.getId());
break;
default:

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M17,12h-5v5h5v-5zM16,1v2L8,3L8,1L6,1v2L5,3c-1.11,0 -1.99,0.9 -1.99,2L3,19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2h-1L18,1h-2zM19,19L5,19L5,8h14v11z"/>
</vector>

View File

@ -108,6 +108,18 @@
app:layout_constraintStart_toEndOf="@id/btnCalendarDecline"
app:layout_constraintTop_toBottomOf="@id/tvAttendees" />
<ImageButton
android:id="@+id/ibCalendar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="?attr/colorActionBackground"
android:contentDescription="@string/title_decrypt"
android:tint="@color/action_foreground"
android:tooltipText="@string/title_icalendar_accept"
app:layout_constraintBottom_toBottomOf="@id/btnCalendarAccept"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/baseline_event_24" />
<View
android:id="@+id/paddingBottom"
android:layout_width="wrap_content"
@ -137,5 +149,5 @@
android:id="@+id/grpCalendarResponse"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="btnCalendarAccept,btnCalendarDecline,btnCalendarMaybe" />
app:constraint_referenced_ids="btnCalendarAccept,btnCalendarDecline,btnCalendarMaybe,ibCalendar" />
</androidx.constraintlayout.widget.ConstraintLayout>