From f14e546dc699d108211b34a8b121cf44a7d54c5e Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 12 Dec 2018 19:21:41 -0200 Subject: [PATCH] [android] allow to attach multiple images --- .../briar/android/view/ImagePreview.java | 74 ++++------------- .../android/view/ImagePreviewAdapter.java | 52 ++++++++++++ .../android/view/ImagePreviewViewHolder.java | 81 +++++++++++++++++++ .../view/TextAttachmentController.java | 3 +- .../src/main/res/layout/image_preview.xml | 12 +-- .../res/layout/list_item_image_preview.xml | 35 ++++++++ .../layout/list_item_image_preview_single.xml | 33 ++++++++ 7 files changed, 225 insertions(+), 65 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreviewAdapter.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreviewViewHolder.java create mode 100644 briar-android/src/main/res/layout/list_item_image_preview.xml create mode 100644 briar-android/src/main/res/layout/list_item_image_preview_single.xml diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreview.java b/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreview.java index c19c9d771..4111c8631 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreview.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreview.java @@ -1,43 +1,27 @@ package org.briarproject.briar.android.view; import android.content.Context; -import android.graphics.Bitmap; import android.net.Uri; import android.support.annotation.Nullable; import android.support.constraint.ConstraintLayout; -import android.support.v7.graphics.Palette; +import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.LayoutInflater; -import android.widget.ImageView; -import android.widget.Toast; - -import com.bumptech.glide.load.DataSource; -import com.bumptech.glide.load.engine.GlideException; -import com.bumptech.glide.request.RequestListener; -import com.bumptech.glide.request.target.Target; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.R; -import org.briarproject.briar.android.conversation.glide.GlideApp; import java.util.List; import static android.content.Context.LAYOUT_INFLATER_SERVICE; -import static android.graphics.Color.BLACK; -import static android.graphics.Color.WHITE; -import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_YES; -import static android.support.v7.app.AppCompatDelegate.getDefaultNightMode; -import static android.widget.Toast.LENGTH_LONG; -import static com.bumptech.glide.load.engine.DiskCacheStrategy.NONE; -import static com.bumptech.glide.load.resource.bitmap.DownsampleStrategy.FIT_CENTER; +import static android.support.v4.content.ContextCompat.getColor; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static java.util.Objects.requireNonNull; @NotNullByDefault public class ImagePreview extends ConstraintLayout { - private final ImageView imageView; - private final int backgroundColor = - getDefaultNightMode() == MODE_NIGHT_YES ? BLACK : WHITE; + private final RecyclerView imageList; @Nullable private ImagePreviewListener listener; @@ -59,9 +43,11 @@ public class ImagePreview extends ConstraintLayout { context.getSystemService(LAYOUT_INFLATER_SERVICE)); inflater.inflate(R.layout.image_preview, this, true); - // find image view and set background color - imageView = findViewById(R.id.imageView); - imageView.setBackgroundColor(backgroundColor); + // set background color + setBackgroundColor(getColor(context, R.color.card_background)); + + // find list + imageList = findViewById(R.id.imageList); // set cancel listener findViewById(R.id.imageCancelButton).setOnClickListener(view -> { @@ -74,42 +60,14 @@ public class ImagePreview extends ConstraintLayout { } void showPreview(List imageUris) { + if (listener == null) throw new IllegalStateException(); + if (imageUris.size() == 1) { + LayoutParams params = (LayoutParams) imageList.getLayoutParams(); + params.width = MATCH_PARENT; + imageList.setLayoutParams(params); + } setVisibility(VISIBLE); - GlideApp.with(imageView) - .asBitmap() - .load(imageUris.get(0)) // TODO show more than the first - .diskCacheStrategy(NONE) - .downsample(FIT_CENTER) - .addListener(new RequestListener() { - @Override - public boolean onLoadFailed(@Nullable GlideException e, - Object model, Target target, - boolean isFirstResource) { - if (listener != null) listener.onCancel(); - Toast.makeText(imageView.getContext(), - R.string.image_attach_error, LENGTH_LONG) - .show(); - return false; - } - - @Override - public boolean onResourceReady(Bitmap resource, - Object model, Target target, - DataSource dataSource, boolean isFirstResource) { - Palette.from(resource).generate( - ImagePreview.this::onPaletteGenerated); - return false; - } - }) - .into(imageView); - } - - void onPaletteGenerated(@Nullable Palette palette) { - if (palette == null) return; - int color = getDefaultNightMode() == MODE_NIGHT_YES ? - palette.getDarkMutedColor(backgroundColor) : - palette.getLightMutedColor(backgroundColor); - imageView.setBackgroundColor(color); + imageList.setAdapter(new ImagePreviewAdapter(imageUris, listener)); } interface ImagePreviewListener { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreviewAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreviewAdapter.java new file mode 100644 index 000000000..057d6e229 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreviewAdapter.java @@ -0,0 +1,52 @@ +package org.briarproject.briar.android.view; + +import android.net.Uri; +import android.support.annotation.LayoutRes; +import android.support.v7.widget.RecyclerView.Adapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.view.ImagePreview.ImagePreviewListener; + +import java.util.List; + +import static java.util.Objects.requireNonNull; + +@NotNullByDefault +class ImagePreviewAdapter extends Adapter { + + private final List items; + private final ImagePreviewListener listener; + @LayoutRes + private final int layout; + + public ImagePreviewAdapter(List items, ImagePreviewListener listener) { + this.items = items; + this.listener = listener; + this.layout = items.size() == 1 ? + R.layout.list_item_image_preview_single : + R.layout.list_item_image_preview; + } + + @Override + public ImagePreviewViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) { + View v = LayoutInflater.from(viewGroup.getContext()) + .inflate(layout, viewGroup, false); + return new ImagePreviewViewHolder(v, items.size() == 1, + requireNonNull(listener)); + } + + @Override + public void onBindViewHolder(ImagePreviewViewHolder viewHolder, int position) { + viewHolder.bind(items.get(position)); + } + + @Override + public int getItemCount() { + return items.size(); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreviewViewHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreviewViewHolder.java new file mode 100644 index 000000000..9db3ea118 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/ImagePreviewViewHolder.java @@ -0,0 +1,81 @@ +package org.briarproject.briar.android.view; + +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.support.annotation.DrawableRes; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.Toast; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.conversation.glide.GlideApp; +import org.briarproject.briar.android.view.ImagePreview.ImagePreviewListener; + +import static android.view.View.INVISIBLE; +import static android.widget.Toast.LENGTH_LONG; +import static com.bumptech.glide.load.engine.DiskCacheStrategy.NONE; +import static com.bumptech.glide.load.resource.bitmap.DownsampleStrategy.FIT_CENTER; +import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade; + +@NotNullByDefault +class ImagePreviewViewHolder extends ViewHolder { + + @DrawableRes + private static final int ERROR_RES = R.drawable.ic_image_broken; + + private final boolean single; + private final ImagePreviewListener listener; + + private final ImageView imageView; + private final ProgressBar progressBar; + + ImagePreviewViewHolder(View v, boolean single, + ImagePreviewListener listener) { + super(v); + this.single = single; + this.listener = listener; + this.imageView = v.findViewById(R.id.imageView); + this.progressBar = v.findViewById(R.id.progressBar); + } + + void bind(Uri uri) { + GlideApp.with(imageView) + .load(uri) + .diskCacheStrategy(NONE) + .error(ERROR_RES) + .downsample(FIT_CENTER) + .transition(withCrossFade()) + .addListener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, + Object model, Target target, + boolean isFirstResource) { + if (single) listener.onCancel(); + progressBar.setVisibility(INVISIBLE); + Toast.makeText(imageView.getContext(), + R.string.image_attach_error, LENGTH_LONG) + .show(); + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, + Object model, Target target, + DataSource dataSource, boolean isFirstResource) { + progressBar.setVisibility(INVISIBLE); + return false; + } + }) + .into(imageView); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java index 883119cf2..939d0d045 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java @@ -81,8 +81,7 @@ public class TextAttachmentController extends TextSendController ACTION_OPEN_DOCUMENT : ACTION_GET_CONTENT); intent.addCategory(CATEGORY_OPENABLE); intent.setType("image/*"); - if (SDK_INT >= 18) // TODO set true to allow attaching multiple images - intent.putExtra(EXTRA_ALLOW_MULTIPLE, false); + if (SDK_INT >= 18) intent.putExtra(EXTRA_ALLOW_MULTIPLE, true); requireNonNull(imageListener).onAttachImage(intent); } diff --git a/briar-android/src/main/res/layout/image_preview.xml b/briar-android/src/main/res/layout/image_preview.xml index 456cf2a21..e21a322b7 100644 --- a/briar-android/src/main/res/layout/image_preview.xml +++ b/briar-android/src/main/res/layout/image_preview.xml @@ -13,21 +13,23 @@ android:id="@+id/divider" style="@style/Divider.Horizontal" android:layout_alignParentTop="true" - app:layout_constraintBottom_toTopOf="@+id/imageView" + app:layout_constraintBottom_toTopOf="@+id/imageList" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"/> - + tools:listitem="@layout/list_item_image"/> + + + + + + + diff --git a/briar-android/src/main/res/layout/list_item_image_preview_single.xml b/briar-android/src/main/res/layout/list_item_image_preview_single.xml new file mode 100644 index 000000000..038e52bbc --- /dev/null +++ b/briar-android/src/main/res/layout/list_item_image_preview_single.xml @@ -0,0 +1,33 @@ + + + + + + + +