diff --git a/README.md b/README.md index b6f000f672..d691e01e61 100644 --- a/README.md +++ b/README.md @@ -166,8 +166,9 @@ FairEmail uses: * [ShortcutBadger](https://github.com/leolin310148/ShortcutBadger). Copyright 2014 Leo Lin. [Apache license](https://github.com/leolin310148/ShortcutBadger/blob/master/LICENSE). * [PhotoView](https://github.com/chrisbanes/PhotoView). Copyright 2018 Chris Banes. [Apache License](https://github.com/chrisbanes/PhotoView/blob/master/LICENSE). * [Bugsnag exception reporter for Android](https://github.com/bugsnag/bugsnag-android). Copyright (c) 2012 Bugsnag. [MIT License](https://github.com/bugsnag/bugsnag-android/blob/master/LICENSE.txt). +* [biweekly](https://github.com/mangstadt/biweekly). Copyright (c) 2013-2018, Michael Angstadt. [BSD 2-Clause](https://github.com/mangstadt/biweekly/blob/master/LICENSE). -FairEmail is sponsored by: +Error reporting is sponsored by: ![Bugsnag Logo](/images/bugsnag_logo_navy.png) diff --git a/app/build.gradle b/app/build.gradle index 7fba83524a..1d23c43efa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -133,6 +133,7 @@ dependencies { def badge_version = "1.1.22" def photoview_version = "2.3.0" def bugsnag_version = "4.14.0" + def biweekly_version = "0.6.3" // https://developer.android.com/jetpack/androidx/releases/ @@ -217,6 +218,11 @@ dependencies { // https://github.com/bugsnag/bugsnag-android implementation "com.bugsnag:bugsnag-android:$bugsnag_version" + // https://github.com/mangstadt/biweekly + implementation("net.sf.biweekly:biweekly:$biweekly_version") { + exclude group: 'com.fasterxml.jackson.core', module: 'jackson-core' + } + // git clone https://android.googlesource.com/platform/frameworks/opt/colorpicker implementation project(path: ':colorpicker') } diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index f8f96c252c..bd9187c63a 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -121,6 +121,13 @@ import java.util.List; import javax.mail.Address; import javax.mail.internet.InternetAddress; +import biweekly.Biweekly; +import biweekly.ICalendar; +import biweekly.component.VEvent; +import biweekly.property.Attendee; +import biweekly.property.Summary; +import biweekly.util.ICalDate; + public class AdapterMessage extends RecyclerView.Adapter { private Context context; private LayoutInflater inflater; @@ -253,10 +260,17 @@ public class AdapterMessage extends RecyclerView.Adapter 1); boolean downloading = false; + boolean calendar = false; List a = new ArrayList<>(); for (EntityAttachment attachment : attachments) { boolean inline = (TextUtils.isEmpty(attachment.name) || @@ -1011,9 +1041,92 @@ public class AdapterMessage extends RecyclerView.Adapter() { + @Override + protected void onPreExecute(Bundle args) { + grpCalendar.setVisibility(View.VISIBLE); + pbCalendarWait.setVisibility(View.VISIBLE); + } + + @Override + protected void onPostExecute(Bundle args) { + pbCalendarWait.setVisibility(View.GONE); + } + + @Override + protected ICalendar onExecute(Context context, Bundle args) throws IOException { + File file = (File) args.getSerializable("file"); + return Biweekly.parse(file).first(); + } + + @Override + protected void onExecuted(Bundle args, ICalendar icalendar) { + if (icalendar == null || icalendar.getEvents().size() == 0) + return; + + DateFormat df = SimpleDateFormat.getDateTimeInstance(); + + VEvent event = icalendar.getEvents().get(0); + + Summary summary = event.getSummary(); + + ICalDate start = event.getDateStart() == null ? null : event.getDateStart().getValue(); + ICalDate end = event.getDateEnd() == null ? null : event.getDateEnd().getValue(); + + List attendee = new ArrayList<>(); + for (Attendee a : event.getAttendees()) { + String email = a.getEmail(); + String name = a.getCommonName(); + if (TextUtils.isEmpty(name)) { + if (!TextUtils.isEmpty(email)) + attendee.add(email); + } else { + if (TextUtils.isEmpty(email) || name.equals(email)) + attendee.add(name); + else + attendee.add(name + " (" + email + ")"); + } + } + + tvCalendarSummary.setText(summary == null ? null : summary.getValue()); + tvCalendarSummary.setVisibility(summary == null ? View.GONE : View.VISIBLE); + + tvCalendarStart.setText(start == null ? null : df.format(start.getTime())); + tvCalendarStart.setVisibility(start == null ? View.GONE : View.VISIBLE); + + tvCalendarEnd.setText(end == null ? null : df.format(end.getTime())); + tvCalendarEnd.setVisibility(end == null ? View.GONE : View.VISIBLE); + + tvAttendees.setText(TextUtils.join(", ", attendee)); + tvAttendees.setVisibility(attendee.size() == 0 ? View.GONE : View.VISIBLE); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(context, owner, ex); + } + }.execute(context, owner, args, "message:calendar"); + } } adapterAttachment.set(a); + if (!calendar) { + tvCalendarSummary.setVisibility(View.GONE); + tvCalendarStart.setVisibility(View.GONE); + tvCalendarEnd.setVisibility(View.GONE); + tvAttendees.setVisibility(View.GONE); + pbCalendarWait.setVisibility(View.GONE); + grpCalendar.setVisibility(View.GONE); + } + cbInline.setOnCheckedChangeListener(null); cbInline.setChecked(show_inline); cbInline.setVisibility(has_inline ? View.VISIBLE : View.GONE); diff --git a/app/src/main/res/layout/include_message_calendar.xml b/app/src/main/res/layout/include_message_calendar.xml new file mode 100644 index 0000000000..4b0221efc8 --- /dev/null +++ b/app/src/main/res/layout/include_message_calendar.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_message_compact.xml b/app/src/main/res/layout/item_message_compact.xml index 12d2276cd9..2023abcecf 100644 --- a/app/src/main/res/layout/item_message_compact.xml +++ b/app/src/main/res/layout/item_message_compact.xml @@ -350,13 +350,21 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/inMessage" /> + + + app:layout_constraintTop_toBottomOf="@id/InCalendar" /> + + + app:layout_constraintTop_toBottomOf="@id/InCalendar" /> Unsupported encoding: %1$s Via: %1$s + Accept + Decline + Maybe + Try FairEmail, an open source, privacy friendly email app for Android This is a pro feature