diff --git a/FAQ.md b/FAQ.md
index 3b3d2d77..f8084c5b 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -21,6 +21,7 @@ The low priority status bar notification shows the number of pending operations,
* Move message to another remote folder
* Delete message from remote folder
* Send message
+* Download attachment
**(3) What is a valid security certificate?**
diff --git a/app/src/main/java/eu/faircode/email/AdapterAttachment.java b/app/src/main/java/eu/faircode/email/AdapterAttachment.java
index c07bc2fa..7df294a0 100644
--- a/app/src/main/java/eu/faircode/email/AdapterAttachment.java
+++ b/app/src/main/java/eu/faircode/email/AdapterAttachment.java
@@ -28,15 +28,19 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
public class AdapterAttachment extends RecyclerView.Adapter {
private Context context;
+ private ExecutorService executor = Executors.newCachedThreadPool();
private List all = new ArrayList<>();
private List filtered = new ArrayList<>();
@@ -45,30 +49,39 @@ public class AdapterAttachment extends RecyclerView.Adapter> liveAttachments(long message);
+ @Query("SELECT * FROM attachment WHERE message = :message AND sequence = :sequence")
+ EntityAttachment getAttachment(long message, int sequence);
+
@Insert(onConflict = OnConflictStrategy.REPLACE)
long insertAttachment(EntityAttachment attachment);
+
+ @Update
+ void updateAttachment(EntityAttachment attachment);
}
diff --git a/app/src/main/java/eu/faircode/email/EntityAttachment.java b/app/src/main/java/eu/faircode/email/EntityAttachment.java
index 774c5c95..66495266 100644
--- a/app/src/main/java/eu/faircode/email/EntityAttachment.java
+++ b/app/src/main/java/eu/faircode/email/EntityAttachment.java
@@ -21,10 +21,13 @@ package eu.faircode.email;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.ForeignKey;
+import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import android.support.annotation.NonNull;
+import javax.mail.BodyPart;
+
import static android.arch.persistence.room.ForeignKey.CASCADE;
@Entity(
@@ -50,4 +53,7 @@ public class EntityAttachment {
@NonNull
public String type;
public byte[] content;
+
+ @Ignore
+ BodyPart part;
}
diff --git a/app/src/main/java/eu/faircode/email/EntityOperation.java b/app/src/main/java/eu/faircode/email/EntityOperation.java
index 0480e903..cdaa32e7 100644
--- a/app/src/main/java/eu/faircode/email/EntityOperation.java
+++ b/app/src/main/java/eu/faircode/email/EntityOperation.java
@@ -58,6 +58,7 @@ public class EntityOperation {
public static final String MOVE = "move";
public static final String DELETE = "delete";
public static final String SEND = "send";
+ public static final String ATTACHMENT = "attachment";
static void queue(Context context, EntityMessage message, String name) {
JSONArray jsonArray = new JSONArray();
diff --git a/app/src/main/java/eu/faircode/email/Helper.java b/app/src/main/java/eu/faircode/email/Helper.java
index 9a91b48f..b8667984 100644
--- a/app/src/main/java/eu/faircode/email/Helper.java
+++ b/app/src/main/java/eu/faircode/email/Helper.java
@@ -67,6 +67,14 @@ public class Helper {
return sb.toString();
}
+ static String humanReadableByteCount(long bytes, boolean si) {
+ int unit = si ? 1000 : 1024;
+ if (bytes < unit) return bytes + " B";
+ int exp = (int) (Math.log(bytes) / Math.log(unit));
+ String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
+ return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
+ }
+
static StringBuilder getDebugInfo() {
StringBuilder sb = new StringBuilder();
diff --git a/app/src/main/java/eu/faircode/email/MessageHelper.java b/app/src/main/java/eu/faircode/email/MessageHelper.java
index 5d401345..d346b0f8 100644
--- a/app/src/main/java/eu/faircode/email/MessageHelper.java
+++ b/app/src/main/java/eu/faircode/email/MessageHelper.java
@@ -313,6 +313,7 @@ public class MessageHelper {
attachment.sequence = result.size() + 1;
attachment.name = part.getFileName();
attachment.type = ct.getBaseType();
+ attachment.part = part;
result.add(attachment);
}
} else if (content instanceof Multipart) {
diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
index b34bb24c..8ac017e3 100644
--- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
+++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
@@ -50,7 +50,9 @@ import com.sun.mail.imap.protocol.IMAPProtocol;
import org.json.JSONArray;
import org.json.JSONException;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
@@ -566,124 +568,151 @@ public class ServiceSynchronize extends LifecycleService {
}
}
- private void processOperations(EntityFolder folder, IMAPStore istore, IMAPFolder ifolder) throws MessagingException, JSONException {
+ private void processOperations(EntityFolder folder, IMAPStore istore, IMAPFolder ifolder) throws MessagingException, JSONException, IOException {
try {
Log.i(Helper.TAG, folder.name + " start process");
DB db = DB.getInstance(this);
DaoOperation operation = db.operation();
DaoMessage message = db.message();
- for (TupleOperationEx op : operation.getOperations(folder.id)) {
- Log.i(Helper.TAG, folder.name +
- " Process op=" + op.id + "/" + op.name +
- " args=" + op.args +
- " msg=" + op.message);
-
- JSONArray jargs = new JSONArray(op.args);
+ for (TupleOperationEx op : operation.getOperations(folder.id))
try {
- if (EntityOperation.SEEN.equals(op.name)) {
- // Mark message (un)seen
- Message imessage = ifolder.getMessageByUID(op.uid);
- if (imessage == null)
- throw new MessageRemovedException();
- imessage.setFlag(Flags.Flag.SEEN, jargs.getBoolean(0));
-
- } else if (EntityOperation.ADD.equals(op.name)) {
- if (!folder.synchronize) {
- // Local drafts
- Log.w(Helper.TAG, "Folder synchronization disabled");
- return;
- }
+ Log.i(Helper.TAG, folder.name +
+ " start op=" + op.id + "/" + op.name +
+ " args=" + op.args +
+ " msg=" + op.message);
+
+ JSONArray jargs = new JSONArray(op.args);
+ try {
+ if (EntityOperation.SEEN.equals(op.name)) {
+ // Mark message (un)seen
+ Message imessage = ifolder.getMessageByUID(op.uid);
+ if (imessage == null)
+ throw new MessageRemovedException();
+ imessage.setFlag(Flags.Flag.SEEN, jargs.getBoolean(0));
+
+ } else if (EntityOperation.ADD.equals(op.name)) {
+ if (!folder.synchronize) {
+ // Local drafts
+ Log.w(Helper.TAG, "Folder synchronization disabled");
+ return;
+ }
- // Append message
- EntityMessage msg = message.getMessage(op.message);
- Properties props = MessageHelper.getSessionProperties();
- Session isession = Session.getDefaultInstance(props, null);
- MimeMessage imessage = MessageHelper.from(msg, isession);
- ifolder.appendMessages(new Message[]{imessage});
+ // Append message
+ EntityMessage msg = message.getMessage(op.message);
+ Properties props = MessageHelper.getSessionProperties();
+ Session isession = Session.getDefaultInstance(props, null);
+ MimeMessage imessage = MessageHelper.from(msg, isession);
+ ifolder.appendMessages(new Message[]{imessage});
- // Drafts can be appended multiple times
- try {
- if (msg.uid != null) {
- Message previously = ifolder.getMessageByUID(msg.uid);
- previously.setFlag(Flags.Flag.DELETED, true);
- ifolder.expunge();
+ // Drafts can be appended multiple times
+ try {
+ if (msg.uid != null) {
+ Message previously = ifolder.getMessageByUID(msg.uid);
+ previously.setFlag(Flags.Flag.DELETED, true);
+ ifolder.expunge();
+ }
+ } finally {
+ // Remote will report appended
+ message.deleteMessage(op.message);
}
- } finally {
- // Remote will report appended
+
+ } else if (EntityOperation.MOVE.equals(op.name)) {
+ // Move message
+ EntityFolder archive = db.folder().getFolder(jargs.getLong(0));
+ Message imessage = ifolder.getMessageByUID(op.uid);
+ Folder target = istore.getFolder(archive.name);
+ ifolder.moveMessages(new Message[]{imessage}, target);
+
message.deleteMessage(op.message);
- }
- } else if (EntityOperation.MOVE.equals(op.name)) {
- // Move message
- EntityFolder archive = db.folder().getFolder(jargs.getLong(0));
- Message imessage = ifolder.getMessageByUID(op.uid);
- Folder target = istore.getFolder(archive.name);
- ifolder.moveMessages(new Message[]{imessage}, target);
-
- message.deleteMessage(op.message);
-
- } else if (EntityOperation.DELETE.equals(op.name)) {
- // Delete message
- Message imessage = ifolder.getMessageByUID(op.uid);
- if (imessage == null)
- throw new MessageRemovedException();
- imessage.setFlag(Flags.Flag.DELETED, true);
- ifolder.expunge();
-
- message.deleteMessage(op.message);
-
- } else if (EntityOperation.SEND.equals(op.name)) {
- // Send message
- EntityMessage msg = message.getMessage(op.message);
- EntityMessage reply = (msg.replying == null ? null : message.getMessage(msg.replying));
- EntityIdentity ident = db.identity().getIdentity(msg.identity);
-
- if (!ident.synchronize) {
- // Message will remain in outbox
- return;
- }
+ } else if (EntityOperation.DELETE.equals(op.name)) {
+ // Delete message
+ Message imessage = ifolder.getMessageByUID(op.uid);
+ if (imessage == null)
+ throw new MessageRemovedException();
+ imessage.setFlag(Flags.Flag.DELETED, true);
+ ifolder.expunge();
- Properties props = MessageHelper.getSessionProperties();
- Session isession = Session.getDefaultInstance(props, null);
+ message.deleteMessage(op.message);
- MimeMessage imessage;
- if (reply == null)
- imessage = MessageHelper.from(msg, isession);
- else
- imessage = MessageHelper.from(msg, reply, isession);
- if (ident.replyto != null)
- imessage.setReplyTo(new Address[]{new InternetAddress(ident.replyto)});
+ } else if (EntityOperation.SEND.equals(op.name)) {
+ // Send message
+ EntityMessage msg = message.getMessage(op.message);
+ EntityMessage reply = (msg.replying == null ? null : message.getMessage(msg.replying));
+ EntityIdentity ident = db.identity().getIdentity(msg.identity);
- Transport itransport = isession.getTransport(ident.starttls ? "smtp" : "smtps");
- try {
- itransport.connect(ident.host, ident.port, ident.user, ident.password);
+ if (!ident.synchronize) {
+ // Message will remain in outbox
+ return;
+ }
- Address[] to = imessage.getAllRecipients();
- itransport.sendMessage(imessage, to);
- Log.i(Helper.TAG, "Sent via " + ident.host + "/" + ident.user +
- " to " + TextUtils.join(", ", to));
+ Properties props = MessageHelper.getSessionProperties();
+ Session isession = Session.getDefaultInstance(props, null);
- // Make sure the message is sent only once
- operation.deleteOperation(op.id);
- message.deleteMessage(op.message);
- } finally {
- itransport.close();
- }
+ MimeMessage imessage;
+ if (reply == null)
+ imessage = MessageHelper.from(msg, isession);
+ else
+ imessage = MessageHelper.from(msg, reply, isession);
+ if (ident.replyto != null)
+ imessage.setReplyTo(new Address[]{new InternetAddress(ident.replyto)});
- } else
- throw new MessagingException("Unknown operation name=" + op.name);
+ Transport itransport = isession.getTransport(ident.starttls ? "smtp" : "smtps");
+ try {
+ itransport.connect(ident.host, ident.port, ident.user, ident.password);
+
+ Address[] to = imessage.getAllRecipients();
+ itransport.sendMessage(imessage, to);
+ Log.i(Helper.TAG, "Sent via " + ident.host + "/" + ident.user +
+ " to " + TextUtils.join(", ", to));
+
+ // Make sure the message is sent only once
+ operation.deleteOperation(op.id);
+ message.deleteMessage(op.message);
+ } finally {
+ itransport.close();
+ }
- // Operation succeeded
- operation.deleteOperation(op.id);
+ } else if (EntityOperation.ATTACHMENT.equals(op.name)) {
+ int sequence = jargs.getInt(0);
+ EntityAttachment attachment = db.attachment().getAttachment(op.message, sequence);
- } catch (MessageRemovedException ex) {
- Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
+ Message imessage = ifolder.getMessageByUID(op.uid);
+ if (imessage == null)
+ throw new MessageRemovedException();
+
+ Properties props = MessageHelper.getSessionProperties();
+ Session isession = Session.getDefaultInstance(props, null);
+
+ MessageHelper helper = new MessageHelper((MimeMessage) imessage);
+ EntityAttachment a = helper.getAttachments().get(sequence - 1);
+
+ InputStream is = a.part.getInputStream();
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ for (int len = is.read(buffer); len != -1; len = is.read(buffer))
+ os.write(buffer, 0, len);
- // There is no use in repeating
- operation.deleteOperation(op.id);
+ attachment.content = os.toByteArray();
+ db.attachment().updateAttachment(attachment);
+ Log.i(Helper.TAG, "Downloaded bytes=" + attachment.content.length);
+
+ } else
+ throw new MessagingException("Unknown operation name=" + op.name);
+
+ // Operation succeeded
+ operation.deleteOperation(op.id);
+
+ } catch (MessageRemovedException ex) {
+ Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
+
+ // There is no use in repeating
+ operation.deleteOperation(op.id);
+ }
+ } finally {
+ Log.i(Helper.TAG, folder.name + " end op=" + op.id + "/" + op.name);
}
- }
} finally {
Log.i(Helper.TAG, folder.name + " end process");
}
diff --git a/app/src/main/res/drawable-hdpi/baseline_get_app_black_18.png b/app/src/main/res/drawable-hdpi/baseline_get_app_black_18.png
new file mode 100755
index 00000000..91f1ec86
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_get_app_black_18.png differ
diff --git a/app/src/main/res/drawable-hdpi/baseline_get_app_black_24.png b/app/src/main/res/drawable-hdpi/baseline_get_app_black_24.png
new file mode 100755
index 00000000..d94bd3f7
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_get_app_black_24.png differ
diff --git a/app/src/main/res/drawable-hdpi/baseline_get_app_black_36.png b/app/src/main/res/drawable-hdpi/baseline_get_app_black_36.png
new file mode 100755
index 00000000..bd44e036
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_get_app_black_36.png differ
diff --git a/app/src/main/res/drawable-hdpi/baseline_get_app_black_48.png b/app/src/main/res/drawable-hdpi/baseline_get_app_black_48.png
new file mode 100755
index 00000000..481f7309
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_get_app_black_48.png differ
diff --git a/app/src/main/res/drawable-hdpi/baseline_get_app_white_18.png b/app/src/main/res/drawable-hdpi/baseline_get_app_white_18.png
new file mode 100755
index 00000000..e87c43db
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_get_app_white_18.png differ
diff --git a/app/src/main/res/drawable-hdpi/baseline_get_app_white_24.png b/app/src/main/res/drawable-hdpi/baseline_get_app_white_24.png
new file mode 100755
index 00000000..b6874a60
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_get_app_white_24.png differ
diff --git a/app/src/main/res/drawable-hdpi/baseline_get_app_white_36.png b/app/src/main/res/drawable-hdpi/baseline_get_app_white_36.png
new file mode 100755
index 00000000..bf2c09e9
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_get_app_white_36.png differ
diff --git a/app/src/main/res/drawable-hdpi/baseline_get_app_white_48.png b/app/src/main/res/drawable-hdpi/baseline_get_app_white_48.png
new file mode 100755
index 00000000..5dc1f630
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_get_app_white_48.png differ
diff --git a/app/src/main/res/drawable-mdpi/baseline_get_app_black_18.png b/app/src/main/res/drawable-mdpi/baseline_get_app_black_18.png
new file mode 100755
index 00000000..043f6f6b
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_get_app_black_18.png differ
diff --git a/app/src/main/res/drawable-mdpi/baseline_get_app_black_24.png b/app/src/main/res/drawable-mdpi/baseline_get_app_black_24.png
new file mode 100755
index 00000000..0b23150f
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_get_app_black_24.png differ
diff --git a/app/src/main/res/drawable-mdpi/baseline_get_app_black_36.png b/app/src/main/res/drawable-mdpi/baseline_get_app_black_36.png
new file mode 100755
index 00000000..d94bd3f7
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_get_app_black_36.png differ
diff --git a/app/src/main/res/drawable-mdpi/baseline_get_app_black_48.png b/app/src/main/res/drawable-mdpi/baseline_get_app_black_48.png
new file mode 100755
index 00000000..b96f19e2
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_get_app_black_48.png differ
diff --git a/app/src/main/res/drawable-mdpi/baseline_get_app_white_18.png b/app/src/main/res/drawable-mdpi/baseline_get_app_white_18.png
new file mode 100755
index 00000000..e9a75f28
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_get_app_white_18.png differ
diff --git a/app/src/main/res/drawable-mdpi/baseline_get_app_white_24.png b/app/src/main/res/drawable-mdpi/baseline_get_app_white_24.png
new file mode 100755
index 00000000..ebfc6e9a
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_get_app_white_24.png differ
diff --git a/app/src/main/res/drawable-mdpi/baseline_get_app_white_36.png b/app/src/main/res/drawable-mdpi/baseline_get_app_white_36.png
new file mode 100755
index 00000000..b6874a60
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_get_app_white_36.png differ
diff --git a/app/src/main/res/drawable-mdpi/baseline_get_app_white_48.png b/app/src/main/res/drawable-mdpi/baseline_get_app_white_48.png
new file mode 100755
index 00000000..0032a698
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_get_app_white_48.png differ
diff --git a/app/src/main/res/drawable-xhdpi/baseline_get_app_black_18.png b/app/src/main/res/drawable-xhdpi/baseline_get_app_black_18.png
new file mode 100755
index 00000000..d94bd3f7
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_get_app_black_18.png differ
diff --git a/app/src/main/res/drawable-xhdpi/baseline_get_app_black_24.png b/app/src/main/res/drawable-xhdpi/baseline_get_app_black_24.png
new file mode 100755
index 00000000..b96f19e2
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_get_app_black_24.png differ
diff --git a/app/src/main/res/drawable-xhdpi/baseline_get_app_black_36.png b/app/src/main/res/drawable-xhdpi/baseline_get_app_black_36.png
new file mode 100755
index 00000000..481f7309
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_get_app_black_36.png differ
diff --git a/app/src/main/res/drawable-xhdpi/baseline_get_app_black_48.png b/app/src/main/res/drawable-xhdpi/baseline_get_app_black_48.png
new file mode 100755
index 00000000..1dab5bbc
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_get_app_black_48.png differ
diff --git a/app/src/main/res/drawable-xhdpi/baseline_get_app_white_18.png b/app/src/main/res/drawable-xhdpi/baseline_get_app_white_18.png
new file mode 100755
index 00000000..b6874a60
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_get_app_white_18.png differ
diff --git a/app/src/main/res/drawable-xhdpi/baseline_get_app_white_24.png b/app/src/main/res/drawable-xhdpi/baseline_get_app_white_24.png
new file mode 100755
index 00000000..0032a698
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_get_app_white_24.png differ
diff --git a/app/src/main/res/drawable-xhdpi/baseline_get_app_white_36.png b/app/src/main/res/drawable-xhdpi/baseline_get_app_white_36.png
new file mode 100755
index 00000000..5dc1f630
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_get_app_white_36.png differ
diff --git a/app/src/main/res/drawable-xhdpi/baseline_get_app_white_48.png b/app/src/main/res/drawable-xhdpi/baseline_get_app_white_48.png
new file mode 100755
index 00000000..221786ba
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_get_app_white_48.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_18.png b/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_18.png
new file mode 100755
index 00000000..bd44e036
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_18.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_24.png b/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_24.png
new file mode 100755
index 00000000..481f7309
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_24.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_36.png b/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_36.png
new file mode 100755
index 00000000..9ee99ccd
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_36.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_48.png b/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_48.png
new file mode 100755
index 00000000..fad39a14
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_get_app_black_48.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_18.png b/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_18.png
new file mode 100755
index 00000000..bf2c09e9
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_18.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_24.png b/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_24.png
new file mode 100755
index 00000000..5dc1f630
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_24.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_36.png b/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_36.png
new file mode 100755
index 00000000..4e04a301
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_36.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_48.png b/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_48.png
new file mode 100755
index 00000000..f9bfb5ed
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_get_app_white_48.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_18.png b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_18.png
new file mode 100755
index 00000000..481f7309
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_18.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_24.png b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_24.png
new file mode 100755
index 00000000..1dab5bbc
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_24.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_36.png b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_36.png
new file mode 100755
index 00000000..fad39a14
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_36.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_48.png b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_48.png
new file mode 100755
index 00000000..1415a59f
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_48.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_18.png b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_18.png
new file mode 100755
index 00000000..5dc1f630
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_18.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_24.png b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_24.png
new file mode 100755
index 00000000..221786ba
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_24.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_36.png b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_36.png
new file mode 100755
index 00000000..f9bfb5ed
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_36.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_48.png b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_48.png
new file mode 100755
index 00000000..bb66c5d1
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_48.png differ
diff --git a/app/src/main/res/drawable/baseline_get_app_24.xml b/app/src/main/res/drawable/baseline_get_app_24.xml
new file mode 100755
index 00000000..ae144526
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_get_app_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/item_attachment.xml b/app/src/main/res/layout/item_attachment.xml
index 6f116ded..373c1b32 100644
--- a/app/src/main/res/layout/item_attachment.xml
+++ b/app/src/main/res/layout/item_attachment.xml
@@ -16,25 +16,38 @@
+
+
\ No newline at end of file