From 70e09133311e82e3ab18542fe192778842a4df90 Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 3 Aug 2018 19:12:19 +0000 Subject: [PATCH] Attachment download --- FAQ.md | 1 + .../eu/faircode/email/AdapterAttachment.java | 31 ++- .../java/eu/faircode/email/DaoAttachment.java | 7 + .../eu/faircode/email/EntityAttachment.java | 6 + .../eu/faircode/email/EntityOperation.java | 1 + .../main/java/eu/faircode/email/Helper.java | 8 + .../java/eu/faircode/email/MessageHelper.java | 1 + .../eu/faircode/email/ServiceSynchronize.java | 221 ++++++++++-------- .../baseline_get_app_black_18.png | Bin 0 -> 187 bytes .../baseline_get_app_black_24.png | Bin 0 -> 164 bytes .../baseline_get_app_black_36.png | Bin 0 -> 207 bytes .../baseline_get_app_black_48.png | Bin 0 -> 185 bytes .../baseline_get_app_white_18.png | Bin 0 -> 190 bytes .../baseline_get_app_white_24.png | Bin 0 -> 167 bytes .../baseline_get_app_white_36.png | Bin 0 -> 211 bytes .../baseline_get_app_white_48.png | Bin 0 -> 186 bytes .../baseline_get_app_black_18.png | Bin 0 -> 143 bytes .../baseline_get_app_black_24.png | Bin 0 -> 121 bytes .../baseline_get_app_black_36.png | Bin 0 -> 164 bytes .../baseline_get_app_black_48.png | Bin 0 -> 159 bytes .../baseline_get_app_white_18.png | Bin 0 -> 146 bytes .../baseline_get_app_white_24.png | Bin 0 -> 121 bytes .../baseline_get_app_white_36.png | Bin 0 -> 167 bytes .../baseline_get_app_white_48.png | Bin 0 -> 161 bytes .../baseline_get_app_black_18.png | Bin 0 -> 164 bytes .../baseline_get_app_black_24.png | Bin 0 -> 159 bytes .../baseline_get_app_black_36.png | Bin 0 -> 185 bytes .../baseline_get_app_black_48.png | Bin 0 -> 208 bytes .../baseline_get_app_white_18.png | Bin 0 -> 167 bytes .../baseline_get_app_white_24.png | Bin 0 -> 161 bytes .../baseline_get_app_white_36.png | Bin 0 -> 186 bytes .../baseline_get_app_white_48.png | Bin 0 -> 208 bytes .../baseline_get_app_black_18.png | Bin 0 -> 207 bytes .../baseline_get_app_black_24.png | Bin 0 -> 185 bytes .../baseline_get_app_black_36.png | Bin 0 -> 261 bytes .../baseline_get_app_black_48.png | Bin 0 -> 263 bytes .../baseline_get_app_white_18.png | Bin 0 -> 211 bytes .../baseline_get_app_white_24.png | Bin 0 -> 186 bytes .../baseline_get_app_white_36.png | Bin 0 -> 261 bytes .../baseline_get_app_white_48.png | Bin 0 -> 263 bytes .../baseline_get_app_black_18.png | Bin 0 -> 185 bytes .../baseline_get_app_black_24.png | Bin 0 -> 208 bytes .../baseline_get_app_black_36.png | Bin 0 -> 263 bytes .../baseline_get_app_black_48.png | Bin 0 -> 303 bytes .../baseline_get_app_white_18.png | Bin 0 -> 186 bytes .../baseline_get_app_white_24.png | Bin 0 -> 208 bytes .../baseline_get_app_white_36.png | Bin 0 -> 263 bytes .../baseline_get_app_white_48.png | Bin 0 -> 303 bytes .../main/res/drawable/baseline_get_app_24.xml | 10 + app/src/main/res/layout/item_attachment.xml | 25 +- 50 files changed, 202 insertions(+), 109 deletions(-) create mode 100755 app/src/main/res/drawable-hdpi/baseline_get_app_black_18.png create mode 100755 app/src/main/res/drawable-hdpi/baseline_get_app_black_24.png create mode 100755 app/src/main/res/drawable-hdpi/baseline_get_app_black_36.png create mode 100755 app/src/main/res/drawable-hdpi/baseline_get_app_black_48.png create mode 100755 app/src/main/res/drawable-hdpi/baseline_get_app_white_18.png create mode 100755 app/src/main/res/drawable-hdpi/baseline_get_app_white_24.png create mode 100755 app/src/main/res/drawable-hdpi/baseline_get_app_white_36.png create mode 100755 app/src/main/res/drawable-hdpi/baseline_get_app_white_48.png create mode 100755 app/src/main/res/drawable-mdpi/baseline_get_app_black_18.png create mode 100755 app/src/main/res/drawable-mdpi/baseline_get_app_black_24.png create mode 100755 app/src/main/res/drawable-mdpi/baseline_get_app_black_36.png create mode 100755 app/src/main/res/drawable-mdpi/baseline_get_app_black_48.png create mode 100755 app/src/main/res/drawable-mdpi/baseline_get_app_white_18.png create mode 100755 app/src/main/res/drawable-mdpi/baseline_get_app_white_24.png create mode 100755 app/src/main/res/drawable-mdpi/baseline_get_app_white_36.png create mode 100755 app/src/main/res/drawable-mdpi/baseline_get_app_white_48.png create mode 100755 app/src/main/res/drawable-xhdpi/baseline_get_app_black_18.png create mode 100755 app/src/main/res/drawable-xhdpi/baseline_get_app_black_24.png create mode 100755 app/src/main/res/drawable-xhdpi/baseline_get_app_black_36.png create mode 100755 app/src/main/res/drawable-xhdpi/baseline_get_app_black_48.png create mode 100755 app/src/main/res/drawable-xhdpi/baseline_get_app_white_18.png create mode 100755 app/src/main/res/drawable-xhdpi/baseline_get_app_white_24.png create mode 100755 app/src/main/res/drawable-xhdpi/baseline_get_app_white_36.png create mode 100755 app/src/main/res/drawable-xhdpi/baseline_get_app_white_48.png create mode 100755 app/src/main/res/drawable-xxhdpi/baseline_get_app_black_18.png create mode 100755 app/src/main/res/drawable-xxhdpi/baseline_get_app_black_24.png create mode 100755 app/src/main/res/drawable-xxhdpi/baseline_get_app_black_36.png create mode 100755 app/src/main/res/drawable-xxhdpi/baseline_get_app_black_48.png create mode 100755 app/src/main/res/drawable-xxhdpi/baseline_get_app_white_18.png create mode 100755 app/src/main/res/drawable-xxhdpi/baseline_get_app_white_24.png create mode 100755 app/src/main/res/drawable-xxhdpi/baseline_get_app_white_36.png create mode 100755 app/src/main/res/drawable-xxhdpi/baseline_get_app_white_48.png create mode 100755 app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_18.png create mode 100755 app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_24.png create mode 100755 app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_36.png create mode 100755 app/src/main/res/drawable-xxxhdpi/baseline_get_app_black_48.png create mode 100755 app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_18.png create mode 100755 app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_24.png create mode 100755 app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_36.png create mode 100755 app/src/main/res/drawable-xxxhdpi/baseline_get_app_white_48.png create mode 100755 app/src/main/res/drawable/baseline_get_app_24.xml diff --git a/FAQ.md b/FAQ.md index 3b3d2d774e..f8084c5bf0 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 c07bc2fa14..7df294a065 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 774c5c9568..664952664b 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 0480e9039c..cdaa32e7cc 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 9a91b48f06..b86679847d 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 5d40134590..d346b0f843 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 b34bb24cba..8ac017e3b3 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 0000000000000000000000000000000000000000..91f1ec8698402d280cf2d87c0c6fd78ea628b1f6 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&i0wmS%+S~(DO`a}}Ar*{oPdBnQI7qZTEN@lo zXg=(iY~rSD;v{V9%#bU1sE|eBfs*CL_tzPh&g1`4QMrDa-rA?zI%k;ujVuehVEiW9 z|7KNmdKI;Vst0Cj9b-2eap literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d94bd3f7842ccd9612a93d42477c822d10963db7 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBvOQfKLn;{GUfalfKtY80qO|H_ z1F5~!lZ=fRiv&f?>n3?GS$$!-Qx?PJoDYjRb2i^xz-GF_QQW58KmTF#wTEvHyEA=T z+UYIQX$V16`acG$smZH4fw|TlUrnS-i*Zm{F7BYTZC(m WSUqB%>OBSMLIzJ)KbLh*2~7a!sZ84d literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..481f7309ab52ace8e0302a41586fc5cfaf8ad07b GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!4W2HJAr*{oFEp|qaA06LIAz~l zbyXRb|7QwV@7T=&%734J*HfX9MaTn_$da*4>@;~aN1<@rk()y4-g9(uF|v;@lx;7Q nu~Ow@_;AkvYT7SOp#Adg0bjjVCCGgNvKc&G{an^LB{Ts5H=I1` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e87c43db6a20436574e7402f378e4164bc8baaea GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&i0wmS%+S~(Dt)4E9Ar*{C5}O{>ANDNv*>dLgG0hhwsd+hUVIW0nhIiZ*hL96yv_F1j4*aHYQCaQXb+h{xyW83kGW z%H_Vcsb2P_sLsrbXQy~c^f0-aY|`jZ52-kmaDYpy^8_dRsrMYs!UjJ*T#h+R+oPLR nRlYTix2`u$bnR}fpDx;-7ah4P@^YsF9mL@2>gTe~DWM4feC9!i literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b6874a6013c4f3113fb0c6ee616c6c6c6d94014e GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB@;qG}Ln;{GUR%h^pdjEJ=$0tr zW_>;=CoDyDWkbN_`3fg(OLtD2q|CtV&}m-R#I=h{V?hH`mB9}AY4@7)WdD7OzH(%D zT5_3)VV#I!+LQwl0Y`oW9+?ry*5e@f*d2r>PqH(9x2nNJW9gG@=3CdIrCno>qyuec N@O1TaS?83{1ORs9ImQ40 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bf2c09e9782890ec16e8cf3d90d8364ae0cce303 GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL1|)l2v+e?^S)MMAAr*{o&u`>y4q#vobW3WP z(sNMbOXREmBW%+zr8+r!oSFON+NIfV&YU^ZAXy=E=MVpegCE-r5)ZX-3ak0dFi5oL zWEM-zopr0L}_f{Qv*} literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5dc1f63015598d52bd5f6de684eeb81635b040bf GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jh-%!Ar*{oFR(KnVh~_3Typ*A z;|DYDcDC4*u`@7yR&QeA6jJe+py1ea4opJ03uZ<>`yu8T|HPw9#&e>wW|4|(-;xs( zMJy*Nxd*`ni%|t9340bPW&W38Nbqw4na9HUOBm>Yd6Kh)AG_SB1-XvF)78&qol`;+ E0E^%}J^%m! literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..043f6f6b7169cbe2a7dbd36828ebf9adab42aa05 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@W2dPZ!6K3dUrKpaTpY{0kD9i+G9{ z9{ta_k@!OD2xAb>QPv0^Er&_Z6;dM1J%kzWIIKCnOVg-jLn4Q>h5=6^hiaQCPsFwW ohMRsWVG1)iIu9mnRc2;jm@Q#H>#^KzBcKfop00i_>zopr0AlzlS^xk5 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0b23150f2436bbc6c83bd48b0a33baac00f9c7d7 GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj4xTQKAr*{o&nogUIB+mK&g*-> z*fO-UA*T7I%GTQ(;#bY&uespu#&%lbkV0QXlaXJ*G0syKj*{vId0X%NY?Q6|TU981 TJSgQC&@2W|S3j3^P6|k1|%Oc%$NbBvOQfKLn;{GUfalfKtY80qO|H_ z1F5~!lZ=fRiv&f?>n3?GS$$!-Qx?PJoDYjRb2i^xz-GF_QQW58KmTF#wTEvHyEA=T z+UYIQX$V16`acG$smZH4fwKg8 z=-+h*8~Kt=HtZ~`Q}%o}yVT)ABVWk^X4w}G>^|vf?=GG5i0DX9`SH>2PlbHl9)A0K z?egyr_kVwQ{P%~)wJ_oS_ea!so__7X{)X9el1f0g2S5AyEKhjHY9R5YZ&k(a;UbM s@PhN7V`arVZ;ZdF&HWI8c1!nW-zwGc5tvA2JFxd;)gt9P^o7rvACfwISZ>g~Ihi UTRU=B1I=RaboFyt=akR{035j|sQ>@~ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b6874a6013c4f3113fb0c6ee616c6c6c6d94014e GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB@;qG}Ln;{GUR%h^pdjEJ=$0tr zW_>;=CoDyDWkbN_`3fg(OLtD2q|CtV&}m-R#I=h{V?hH`mB9}AY4@7)WdD7OzH(%D zT5_3)VV#I!+LQwl0Y`oW9+?ry*5e@f*d2r>PqH(9x2nNJW9gG@=3CdIrCno>qyuec N@O1TaS?83{1ORs9ImQ40 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0032a69813451abe36abdf3fff48212719bb3995 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUt3{MxwkP61P=Qj!-P+(|qaNk~@ z5gfGq0=MOi2Kms?{~7yz7&!zK92yuHnOG7E-c_Fs?$~;MJKIfxGu(ps&}#wtnd?{8 h?&JpQT(xSI+{tj07+1cv?|^nPc)I$ztaD0e0swy+GdBPL literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d94bd3f7842ccd9612a93d42477c822d10963db7 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBvOQfKLn;{GUfalfKtY80qO|H_ z1F5~!lZ=fRiv&f?>n3?GS$$!-Qx?PJoDYjRb2i^xz-GF_QQW58KmTF#wTEvHyEA=T z+UYIQX$V16`acG$smZH4fwKg8 z=-+h*8~Kt=HtZ~`Q}%o}yVT)ABVWk^X4w}G>^|vf?=GG5i0DX9`SH>2PlbHl9)A0K z?egyr_kVwQ{P%~)wJ_oS_ea!so__7X{)X9el1@;~aN1<@rk()y4-g9(uF|v;@lx;7Q nu~Ow@_;AkvYT7SOp#Adg0bjjVCCGgNvKc&G{an^LB{Ts5H=I1` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1dab5bbcf9527231c83bcf52644b54fd7a562398 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeG3?%1&o4*=JaR&H=xB_ViXik240LWr43GxeO z_}|d-YF7`CTkPrL7*fIb_UuAlrT_s}$D(&!J15CG266eu>{nTFk%jR|f9%HTk9jLC zAGVxt8;b#NBdQN-7To;R+lZ9%V)#I>jH9@r>mdKI;Vst0GI7ZfB*mh literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b6874a6013c4f3113fb0c6ee616c6c6c6d94014e GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB@;qG}Ln;{GUR%h^pdjEJ=$0tr zW_>;=CoDyDWkbN_`3fg(OLtD2q|CtV&}m-R#I=h{V?hH`mB9}AY4@7)WdD7OzH(%D zT5_3)VV#I!+LQwl0Y`oW9+?ry*5e@f*d2r>PqH(9x2nNJW9gG@=3CdIrCno>qyuec N@O1TaS?83{1ORs9ImQ40 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0032a69813451abe36abdf3fff48212719bb3995 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUt3{MxwkP61P=Qj!-P+(|qaNk~@ z5gfGq0=MOi2Kms?{~7yz7&!zK92yuHnOG7E-c_Fs?$~;MJKIfxGu(ps&}#wtnd?{8 h?&JpQT(xSI+{tj07+1cv?|^nPc)I$ztaD0e0swy+GdBPL literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5dc1f63015598d52bd5f6de684eeb81635b040bf GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jh-%!Ar*{oFR(KnVh~_3Typ*A z;|DYDcDC4*u`@7yR&QeA6jJe+py1ea4opJ03uZ<>`yu8T|HPw9#&e>wW|4|(-;xs( zMJy*Nxd*`ni%|t9340bPW&W38Nbqw4na9HUOBm>Yd6Kh)AG_SB1-XvF)78&qol`;+ E0E^%}J^%m! literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..221786ba99435f976abb7cd6bf6e35d42b93b198 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeG3?%1&o4*=JaR&H=xB}__U{GAKG#SWYE(!7r zX87OG@@iKPkX!8O;uuoF`1b5VUZwy6R>z`uTstSpIR5q9U zEg!a=Z{=Or!kO2?_pXIY&hJ|5vDRCyT6$abO!Thkg%mC|TlUrnS-i*Zm{F7BYTZC(m WSUqB%>OBSMLIzJ)KbLh*2~7a!sZ84d literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..481f7309ab52ace8e0302a41586fc5cfaf8ad07b GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!4W2HJAr*{oFEp|qaA06LIAz~l zbyXRb|7QwV@7T=&%734J*HfX9MaTn_$da*4>@;~aN1<@rk()y4-g9(uF|v;@lx;7Q nu~Ow@_;AkvYT7SOp#Adg0bjjVCCGgNvKc&G{an^LB{Ts5H=I1` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9ee99ccd7f23f8233b24d2a04fe7e7c35abcb84f GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^IUvl!3?yqky#4_xp#Yx{S0IfB9%xH00t&H}1o;Is zI5hlMIFMapEdvypQv(#jj1QUf@Zd-e^q_3K-$_<%4 zSxAIMIor6kbJc?j$5MDQ%KLm7SQsQYoYVw2HNM+Fo4Mn<_D;K+7YBBRTSy;|n`-z( zpjnB{(Wgs-#ZWUz;K-5=M}f&oY=Jyo5-x@sNdiX~bU2CtRbU8I9!smbxbvoa`hRm{ Y^FI~OCrpnmUI+4wr>mdKI;Vst0B*NWoB#j- literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fad39a14c43341ee53d1e34253c57c12151178f3 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^6F``W8A#63;L-+CoB=)|u0R?Bnv-810J4}%g8YIR z{x`I|+SLQ(uJUwo45?szdyX-UHIT>QqM+TT32&YsUd^;?N}kehU6C`MjHf0rKX?@P zn(^A}KUMMdw=x#@n%&Yk|KPRQQOTNk^V$!Ecds5?9{hMxu-?Mhpq)!fJRe?KfW|m@ tX$eGxB*w!_pVwZO++$wl@TLD+l>O_r7|&<-3Z8+yvd$@?2>^Ecaq$2E literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bf2c09e9782890ec16e8cf3d90d8364ae0cce303 GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL1|)l2v+e?^S)MMAAr*{o&u`>y4q#vobW3WP z(sNMbOXREmBW%+zr8+r!oSFON+NIfV&YU^ZAXy=E=MVpegCE-r5)ZX-3ak0dFi5oL zWEM-zopr0L}_f{Qv*} literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5dc1f63015598d52bd5f6de684eeb81635b040bf GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jh-%!Ar*{oFR(KnVh~_3Typ*A z;|DYDcDC4*u`@7yR&QeA6jJe+py1ea4opJ03uZ<>`yu8T|HPw9#&e>wW|4|(-;xs( zMJy*Nxd*`ni%|t9340bPW&W38Nbqw4na9HUOBm>Yd6Kh)AG_SB1-XvF)78&qol`;+ E0E^%}J^%m! literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4e04a30198d72eedd3a749158ce4fc091a2b0f8b GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^IUvl!3?yqky#4_xp#Yx{S0Mc#71#x>wE~K=l?3?( zGdMK-S2&PeVl4v{nd9l=7*fHQBylW3q=!jSRb_$47PHi3l>`%oTW(u>v!t(@t;!9V zJy}SEMLFBJwR6>j3&&D;GRpgW8CV!3IGof3H#NT7KbyJZy7o@HnimIlhFeGN^F5VT@o&a8c7027j!s^099ZJR31yKy14VEd-{KK aWAi^1&nHZeEnWw7CxfS}pUXO@geCxTuwFg@ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f9bfb5edba7fdff1e63a71c0dfaab6ae5dc2a9a9 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^6F``W8A#63;L-+CoB=)|u0Z-f7!+45O$Kt9OM?7@ z8U8o4yxP?RDjWv+R;i913rU`GJA70J0Yf7HdZ(Wfyo{Xm^Fh6({ z_nPtA>pxZT^|vw>_nO_(IRD_a*ip%vc=Os1g?FzWTps**Qn22_*r1(DN<1H4T7bql vcxeelge1npOP|+Xm)v7s>gTe~DWM4f1o3xI literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..481f7309ab52ace8e0302a41586fc5cfaf8ad07b GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!4W2HJAr*{oFEp|qaA06LIAz~l zbyXRb|7QwV@7T=&%734J*HfX9MaTn_$da*4>@;~aN1<@rk()y4-g9(uF|v;@lx;7Q nu~Ow@_;AkvYT7SOp#Adg0bjjVCCGgNvKc&G{an^LB{Ts5H=I1` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1dab5bbcf9527231c83bcf52644b54fd7a562398 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeG3?%1&o4*=JaR&H=xB_ViXik240LWr43GxeO z_}|d-YF7`CTkPrL7*fIb_UuAlrT_s}$D(&!J15CG266eu>{nTFk%jR|f9%HTk9jLC zAGVxt8;b#NBdQN-7To;R+lZ9%V)#I>jH9@r>mdKI;Vst0GI7ZfB*mh literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fad39a14c43341ee53d1e34253c57c12151178f3 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^6F``W8A#63;L-+CoB=)|u0R?Bnv-810J4}%g8YIR z{x`I|+SLQ(uJUwo45?szdyX-UHIT>QqM+TT32&YsUd^;?N}kehU6C`MjHf0rKX?@P zn(^A}KUMMdw=x#@n%&Yk|KPRQQOTNk^V$!Ecds5?9{hMxu-?Mhpq)!fJRe?KfW|m@ tX$eGxB*w!_pVwZO++$wl@TLD+l>O_r7|&<-3Z8+yvd$@?2>^Ecaq$2E literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1415a59fbe6d895fc6783f74c27e732c87e5d6f8 GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvK8A$4HYMBD0I0Jk_T!AzMG$+420Aw+j1o;Is z{BLM^wW|lnz2xcQ7*fIb_WD9Wr$8Q;KsCMAB}>jLXtt_d(ib{nJumUw57F>v57g#mJVL>{uZSTG9uIj{&POjTISlBw#U*(kmdKI;Vst01Uxj;s5{u literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5dc1f63015598d52bd5f6de684eeb81635b040bf GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jh-%!Ar*{oFR(KnVh~_3Typ*A z;|DYDcDC4*u`@7yR&QeA6jJe+py1ea4opJ03uZ<>`yu8T|HPw9#&e>wW|4|(-;xs( zMJy*Nxd*`ni%|t9340bPW&W38Nbqw4na9HUOBm>Yd6Kh)AG_SB1-XvF)78&qol`;+ E0E^%}J^%m! literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..221786ba99435f976abb7cd6bf6e35d42b93b198 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeG3?%1&o4*=JaR&H=xB}__U{GAKG#SWYE(!7r zX87OG@@iKPkX!8O;uuoF`1b5VUZwy6R>z`uTstSpIR5q9U zEg!a=Z{=Or!kO2?_pXIY&hJ|5vDRCyT6$abO!Thkg%mCDjWv+R;i913rU`GJA70J0Yf7HdZ(Wfyo{Xm^Fh6({ z_nPtA>pxZT^|vw>_nO_(IRD_a*ip%vc=Os1g?FzWTps**Qn22_*r1(DN<1H4T7bql vcxeelge1npOP|+Xm)v7s>gTe~DWM4f1o3xI literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bb66c5d1df0fe485b293bb5989f2995c68c7b407 GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvK8A$4HYMBD0I0Jk_T!Hj|Fet8AnhfMHmjw9* zGyHF8d9|wt$i3w0;uuoF`1bljL8m|-mq0bW)+I~MD`>W=UD6jiVm&YM+Yiz3cW=MD zy2QjA{Wzh}%wq&5Zgjspez4+$1>dda=Y;`sdqf_xxL7a>`Z=%&CrnjX%#x|aj SPJRjW9fPN + + diff --git a/app/src/main/res/layout/item_attachment.xml b/app/src/main/res/layout/item_attachment.xml index 6f116ded30..373c1b3265 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