diff --git a/app/src/main/java/eu/faircode/email/AdapterImage.java b/app/src/main/java/eu/faircode/email/AdapterImage.java new file mode 100644 index 0000000000..b581fbf8d7 --- /dev/null +++ b/app/src/main/java/eu/faircode/email/AdapterImage.java @@ -0,0 +1,181 @@ +package eu.faircode.email; + +/* + This file is part of FairEmail. + + FairEmail is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + FairEmail is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FairEmail. If not, see . + + Copyright 2018-2019 by Marcel Bokhorst (M66B) +*/ + +import android.content.Context; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +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 androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.ListUpdateCallback; +import androidx.recyclerview.widget.RecyclerView; + +public class AdapterImage extends RecyclerView.Adapter { + private Context context; + private LayoutInflater inflater; + private LifecycleOwner owner; + + private List all = new ArrayList<>(); + private List filtered = new ArrayList<>(); + + public class ViewHolder extends RecyclerView.ViewHolder { + View itemView; + ImageView image; + TextView caption; + + ViewHolder(View itemView) { + super(itemView); + + this.itemView = itemView; + image = itemView.findViewById(R.id.image); + caption = itemView.findViewById(R.id.caption); + } + + private void bindTo(EntityAttachment attachment) { + if (attachment.available) { + Drawable d = BitmapDrawable.createFromPath( + EntityAttachment.getFile(context, attachment.id).getAbsolutePath()); + if (d == null) + image.setImageResource(R.drawable.baseline_broken_image_24); + else + image.setImageDrawable(d); + } else + image.setImageResource(R.drawable.baseline_image_24); + + caption.setText(attachment.name); + } + } + + AdapterImage(Context context, LifecycleOwner owner) { + this.context = context; + this.inflater = LayoutInflater.from(context); + this.owner = owner; + setHasStableIds(true); + } + + public void set(@NonNull List attachments) { + Log.i("Set images=" + attachments.size()); + + Collections.sort(attachments, new Comparator() { + @Override + public int compare(EntityAttachment a1, EntityAttachment a2) { + return a1.sequence.compareTo(a2.sequence); + } + }); + + all = attachments; + + DiffUtil.DiffResult diff = DiffUtil.calculateDiff(new MessageDiffCallback(filtered, all)); + + filtered.clear(); + filtered.addAll(all); + + diff.dispatchUpdatesTo(new ListUpdateCallback() { + @Override + public void onInserted(int position, int count) { + Log.i("Inserted @" + position + " #" + count); + } + + @Override + public void onRemoved(int position, int count) { + Log.i("Removed @" + position + " #" + count); + } + + @Override + public void onMoved(int fromPosition, int toPosition) { + Log.i("Moved " + fromPosition + ">" + toPosition); + } + + @Override + public void onChanged(int position, int count, Object payload) { + Log.i("Changed @" + position + " #" + count); + } + }); + diff.dispatchUpdatesTo(this); + } + + private class MessageDiffCallback extends DiffUtil.Callback { + private List prev; + private List next; + + MessageDiffCallback(List prev, List next) { + this.prev = prev; + this.next = next; + } + + @Override + public int getOldListSize() { + return prev.size(); + } + + @Override + public int getNewListSize() { + return next.size(); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + EntityAttachment a1 = prev.get(oldItemPosition); + EntityAttachment a2 = next.get(newItemPosition); + return a1.id.equals(a2.id); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + EntityAttachment a1 = prev.get(oldItemPosition); + EntityAttachment a2 = next.get(newItemPosition); + return a1.equals(a2); + } + } + + @Override + public long getItemId(int position) { + return filtered.get(position).id; + } + + @Override + public int getItemCount() { + return filtered.size(); + } + + @Override + @NonNull + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new ViewHolder(inflater.inflate(R.layout.item_image, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + EntityAttachment attachment = filtered.get(position); + holder.bindTo(attachment); + } +} diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index 4a71228adf..fe91df5276 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -105,6 +105,7 @@ import androidx.recyclerview.selection.SelectionTracker; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; public class AdapterMessage extends RecyclerView.Adapter { private Context context; @@ -195,12 +196,15 @@ public class AdapterMessage extends RecyclerView.Adapter> liveAttachments = null; private Observer> observerAttachments = null; @@ -248,8 +252,8 @@ public class AdapterMessage extends RecyclerView.Adapter 0 && show_expanded ? View.VISIBLE : View.GONE); bnvActions.setVisibility(viewType == ViewType.THREAD && show_expanded ? View.INVISIBLE : View.GONE); @@ -594,7 +610,7 @@ public class AdapterMessage extends RecyclerView.Adapter(); - adapter.set(attachments); + adapterAttachment.set(attachments); boolean download = false; boolean save = (attachments.size() > 1); @@ -608,10 +624,17 @@ public class AdapterMessage extends RecyclerView.Adapter images = new ArrayList<>(); + for (EntityAttachment attachment : attachments) + if (attachment.cid == null && attachment.type.startsWith("image")) + images.add(attachment); + adapterImage.set(images); + rvImage.setVisibility(images.size() > 0 ? View.VISIBLE : View.INVISIBLE); + if (message.content) { Bundle args = new Bundle(); args.putSerializable("message", message); diff --git a/app/src/main/res/layout/item_image.xml b/app/src/main/res/layout/item_image.xml new file mode 100644 index 0000000000..4dee825574 --- /dev/null +++ b/app/src/main/res/layout/item_image.xml @@ -0,0 +1,29 @@ + + + + + + + \ 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 7b630dc085..97c640122a 100644 --- a/app/src/main/res/layout/item_message_compact.xml +++ b/app/src/main/res/layout/item_message_compact.xml @@ -548,8 +548,6 @@ android:layout_marginStart="6dp" android:layout_marginTop="3dp" android:layout_marginEnd="6dp" - android:scrollbarStyle="outsideOverlay" - android:scrollbars="vertical" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/vSeparatorAttachments" /> @@ -687,13 +685,22 @@ app:layout_constraintStart_toStartOf="@id/tvBody" app:layout_constraintTop_toTopOf="@id/tvBody" /> + + + app:layout_constraintTop_toBottomOf="@id/rvImage" /> @@ -677,13 +675,22 @@ app:layout_constraintStart_toStartOf="@id/tvBody" app:layout_constraintTop_toTopOf="@id/tvBody" /> + + + app:layout_constraintTop_toBottomOf="@id/rvImage" />