From 1e63a8291579043659f86dbb46d4d63d3225c471 Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Sun, 23 Sep 2018 16:42:56 +0200 Subject: preview media before sending them and allow sharing and attaching of multiple files --- .../messenger/ui/adapter/AccountAdapter.java | 8 +- .../messenger/ui/adapter/ConversationAdapter.java | 10 +- .../messenger/ui/adapter/ListItemAdapter.java | 8 +- .../messenger/ui/adapter/MediaPreviewAdapter.java | 211 +++++++++++++++++++++ 4 files changed, 224 insertions(+), 13 deletions(-) create mode 100644 src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java (limited to 'src/main/java/de/pixart/messenger/ui/adapter') diff --git a/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java index 01b432d65..e37ea6121 100644 --- a/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java +++ b/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java @@ -24,7 +24,7 @@ import de.pixart.messenger.R; import de.pixart.messenger.entities.Account; import de.pixart.messenger.ui.ManageAccountActivity; import de.pixart.messenger.ui.XmppActivity; -import de.pixart.messenger.ui.util.Color; +import de.pixart.messenger.ui.util.StyledAttributes; import de.pixart.messenger.utils.UIHelper; public class AccountAdapter extends ArrayAdapter { @@ -65,14 +65,14 @@ public class AccountAdapter extends ArrayAdapter { statusView.setText(getContext().getString(account.getStatus().getReadableId())); switch (account.getStatus()) { case ONLINE: - statusView.setTextColor(Color.get(activity, R.attr.TextColorOnline)); + statusView.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline)); break; case DISABLED: case CONNECTING: - statusView.setTextColor(Color.get(activity, android.R.attr.textColorSecondary)); + statusView.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary)); break; default: - statusView.setTextColor(Color.get(activity, R.attr.TextColorError)); + statusView.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError)); break; } final SwitchCompat tglAccountState = view.findViewById(R.id.tgl_account_status); diff --git a/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java index 36cae0eb3..55dd6d65f 100644 --- a/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java +++ b/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java @@ -31,7 +31,7 @@ import de.pixart.messenger.entities.MucOptions; import de.pixart.messenger.entities.Transferable; import de.pixart.messenger.ui.ConversationFragment; import de.pixart.messenger.ui.XmppActivity; -import de.pixart.messenger.ui.util.Color; +import de.pixart.messenger.ui.util.StyledAttributes; import de.pixart.messenger.ui.widget.UnreadCountCustomView; import de.pixart.messenger.utils.EmojiWrapper; import de.pixart.messenger.utils.IrregularUnicodeDetector; @@ -97,9 +97,9 @@ public class ConversationAdapter extends RecyclerView.Adapter { } } if (offline) { - viewHolder.name.setTextColor(Color.get(activity, R.attr.text_Color_Main)); + viewHolder.name.setTextColor(StyledAttributes.get(activity, R.attr.text_Color_Main)); viewHolder.name.setAlpha(INACTIVE_ALPHA); viewHolder.jid.setAlpha(INACTIVE_ALPHA); viewHolder.avatar.setAlpha(INACTIVE_ALPHA); viewHolder.tags.setAlpha(INACTIVE_ALPHA); } else { if (ShowPresenceColoredNames()) { - viewHolder.name.setTextColor(color != 0 ? color : Color.get(activity, R.attr.text_Color_Main)); + viewHolder.name.setTextColor(color != 0 ? color : StyledAttributes.get(activity, R.attr.text_Color_Main)); } else { - viewHolder.name.setTextColor(Color.get(activity, R.attr.text_Color_Main)); + viewHolder.name.setTextColor(StyledAttributes.get(activity, R.attr.text_Color_Main)); } viewHolder.name.setAlpha(ACTIVE_ALPHA); viewHolder.jid.setAlpha(ACTIVE_ALPHA); diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java new file mode 100644 index 000000000..bbcaa5dc6 --- /dev/null +++ b/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java @@ -0,0 +1,211 @@ +package de.pixart.messenger.ui.adapter; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.databinding.DataBindingUtil; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.support.annotation.AttrRes; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.ImageView; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.RejectedExecutionException; + +import de.pixart.messenger.R; +import de.pixart.messenger.databinding.MediaPreviewBinding; +import de.pixart.messenger.ui.ConversationFragment; +import de.pixart.messenger.ui.XmppActivity; +import de.pixart.messenger.ui.util.Attachment; +import de.pixart.messenger.ui.util.StyledAttributes; + +public class MediaPreviewAdapter extends RecyclerView.Adapter { + + private final List mediaPreviews = new ArrayList<>(); + + private final ConversationFragment conversationFragment; + + public MediaPreviewAdapter(ConversationFragment fragment) { + this.conversationFragment = fragment; + } + + private static boolean cancelPotentialWork(Attachment attachment, ImageView imageView) { + final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final Attachment oldAttachment = bitmapWorkerTask.attachment; + if (oldAttachment == null || !oldAttachment.equals(attachment)) { + bitmapWorkerTask.cancel(true); + } else { + return false; + } + } + return true; + } + + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; + } + + @NonNull + @Override + public MediaPreviewViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + MediaPreviewBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media_preview, parent, false); + return new MediaPreviewViewHolder(binding); + } + + @Override + public void onBindViewHolder(@NonNull MediaPreviewViewHolder holder, int position) { + final Context context = conversationFragment.getActivity(); + final Attachment attachment = mediaPreviews.get(position); + if (attachment.renderThumbnail()) { + holder.binding.mediaPreview.setImageAlpha(255); + loadPreview(attachment, holder.binding.mediaPreview); + } else { + cancelPotentialWork(attachment, holder.binding.mediaPreview); + holder.binding.mediaPreview.setBackgroundColor(StyledAttributes.getColor(context, R.attr.color_background_tertiary)); + holder.binding.mediaPreview.setImageAlpha(Math.round(StyledAttributes.getFloat(context, R.attr.icon_alpha) * 255)); + final @AttrRes int attr; + if (attachment.getType() == Attachment.Type.LOCATION) { + attr = R.attr.media_preview_location; + } else if (attachment.getType() == Attachment.Type.RECORDING) { + attr = R.attr.media_preview_recording; + } else { + final String mime = attachment.getMime(); + if (mime == null) { + attr = R.attr.media_preview_file; + } else if (mime.startsWith("audio/")) { + attr = R.attr.media_preview_audio; + } else if (mime.equals("text/calendar") || (mime.equals("text/x-vcalendar"))) { + attr = R.attr.media_preview_calendar; + } else if (mime.equals("text/x-vcard")) { + attr = R.attr.media_preview_contact; + } else if (mime.equals("application/vnd.android.package-archive")) { + attr = R.attr.media_preview_app; + } else if (mime.equals("application/zip") || mime.equals("application/rar")) { + attr = R.attr.media_preview_archive; + } else { + attr = R.attr.media_preview_file; + } + } + holder.binding.mediaPreview.setImageDrawable(StyledAttributes.getDrawable(context, attr)); + } + holder.binding.deleteButton.setOnClickListener(v -> { + int pos = mediaPreviews.indexOf(attachment); + mediaPreviews.remove(pos); + notifyItemRemoved(pos); + conversationFragment.toggleInputMethod(); + }); + } + + public void addMediaPreviews(List attachments) { + this.mediaPreviews.addAll(attachments); + notifyDataSetChanged(); + } + + private void loadPreview(Attachment attachment, ImageView imageView) { + if (cancelPotentialWork(attachment, imageView)) { + XmppActivity activity = (XmppActivity) conversationFragment.getActivity(); + final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment, Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)), true); + if (bm != null) { + cancelPotentialWork(attachment, imageView); + imageView.setImageBitmap(bm); + imageView.setBackgroundColor(0x00000000); + } else { + imageView.setBackgroundColor(0xff333333); + imageView.setImageDrawable(null); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final AsyncDrawable asyncDrawable = new AsyncDrawable(conversationFragment.getActivity().getResources(), null, task); + imageView.setImageDrawable(asyncDrawable); + try { + task.execute(attachment); + } catch (final RejectedExecutionException ignored) { + } + } + } + } + + @Override + public int getItemCount() { + return mediaPreviews.size(); + } + + public boolean hasAttachments() { + return mediaPreviews.size() > 0; + } + + public List getAttachments() { + return mediaPreviews; + } + + static class AsyncDrawable extends BitmapDrawable { + private final WeakReference bitmapWorkerTaskReference; + + AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask); + } + + BitmapWorkerTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } + } + + class MediaPreviewViewHolder extends RecyclerView.ViewHolder { + + private final MediaPreviewBinding binding; + + MediaPreviewViewHolder(MediaPreviewBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } + + class BitmapWorkerTask extends AsyncTask { + private final WeakReference imageViewReference; + private Attachment attachment = null; + + BitmapWorkerTask(ImageView imageView) { + imageViewReference = new WeakReference<>(imageView); + } + + @Override + protected Bitmap doInBackground(Attachment... params) { + Activity activity = conversationFragment.getActivity(); + if (activity instanceof XmppActivity) { + final XmppActivity xmppActivity = (XmppActivity) activity; + this.attachment = params[0]; + return xmppActivity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, Math.round(xmppActivity.getResources().getDimension(R.dimen.media_preview_size)), false); + } else { + return null; + } + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap != null && !isCancelled()) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + imageView.setBackgroundColor(0x00000000); + } + } + } + } +} \ No newline at end of file -- cgit v1.2.3