/* * Copyright (c) 2016 Qiscus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.qiscus.sdk.ui.adapter.viewholder; import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.browser.customtabs.CustomTabsIntent; import androidx.core.content.ContextCompat; import androidx.core.util.PatternsCompat; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; import android.text.style.ClickableSpan; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.RequestOptions; import com.qiscus.nirmana.Nirmana; import com.qiscus.sdk.Qiscus; import com.qiscus.sdk.R; import com.qiscus.sdk.chat.core.data.model.QiscusComment; import com.qiscus.sdk.chat.core.util.QiscusTextUtil; import com.qiscus.sdk.data.model.QiscusMentionConfig; import com.qiscus.sdk.ui.adapter.OnItemClickListener; import com.qiscus.sdk.ui.adapter.OnLongItemClickListener; import com.qiscus.sdk.ui.adapter.OnUploadIconClickListener; import com.qiscus.sdk.ui.view.ClickableMovementMethod; import com.qiscus.sdk.ui.view.QiscusProgressView; import com.qiscus.sdk.util.QiscusImageUtil; import java.io.File; import java.util.regex.Matcher; /** * Created on : September 27, 2016 * Author : zetbaitsu * Name : Zetra * GitHub : https://github.com/zetbaitsu */ public abstract class QiscusBaseImageMessageViewHolder extends QiscusBaseMessageViewHolder<QiscusComment> implements QiscusComment.ProgressListener, QiscusComment.DownloadingListener { @NonNull protected ImageView thumbnailView; @Nullable protected TextView captionView; @Nullable protected ImageView imageFrameView; @Nullable protected QiscusProgressView progressView; @Nullable protected ImageView downloadIconView; protected int rightProgressFinishedColor; protected int leftProgressFinishedColor; protected QiscusComment qiscusComment; public QiscusBaseImageMessageViewHolder(View itemView, OnItemClickListener itemClickListener, OnLongItemClickListener longItemClickListener) { this(itemView, itemClickListener, longItemClickListener, null); } public QiscusBaseImageMessageViewHolder(View itemView, OnItemClickListener itemClickListener, OnLongItemClickListener longItemClickListener, OnUploadIconClickListener uploadIconClickListener) { super(itemView, itemClickListener, longItemClickListener); thumbnailView = getThumbnailView(itemView); captionView = getCaptionView(itemView); imageFrameView = getImageFrameView(itemView); progressView = getProgressView(itemView); downloadIconView = getDownloadIconView(itemView); if (captionView != null) { captionView.setMovementMethod(ClickableMovementMethod.getInstance()); captionView.setClickable(false); captionView.setLongClickable(false); } if (downloadIconView != null) { downloadIconView.setOnClickListener(v -> { if (uploadIconClickListener != null && qiscusComment.getState() == QiscusComment.STATE_FAILED) { uploadIconClickListener.onUploadIconClick(v, getAdapterPosition()); } else { onClick(messageBubbleView); } }); } } @Override protected void loadChatConfig() { super.loadChatConfig(); rightProgressFinishedColor = ContextCompat.getColor(Qiscus.getApps(), Qiscus.getChatConfig().getRightProgressFinishedColor()); leftProgressFinishedColor = ContextCompat.getColor(Qiscus.getApps(), Qiscus.getChatConfig().getLeftProgressFinishedColor()); } @NonNull protected abstract ImageView getThumbnailView(View itemView); @Nullable protected abstract TextView getCaptionView(View itemView); @Nullable protected abstract ImageView getImageFrameView(View itemView); @Nullable protected abstract QiscusProgressView getProgressView(View itemView); @Nullable protected abstract ImageView getDownloadIconView(View itemView); @Override public void bind(QiscusComment qiscusComment) { super.bind(qiscusComment); this.qiscusComment = qiscusComment; qiscusComment.setProgressListener(this); qiscusComment.setDownloadingListener(this); setUpDownloadIcon(qiscusComment); showProgressOrNot(qiscusComment); if (captionView != null) { setUpLinks(); } } protected void setUpDownloadIcon(QiscusComment qiscusComment) { if (downloadIconView != null) { if (qiscusComment.getState() <= QiscusComment.STATE_SENDING) { downloadIconView.setImageResource(R.drawable.ic_qiscus_upload); } else { downloadIconView.setImageResource(R.drawable.ic_qiscus_download); } } } protected void showProgressOrNot(QiscusComment qiscusComment) { if (progressView != null) { progressView.setProgress(qiscusComment.getProgress()); progressView.setVisibility( qiscusComment.isDownloading() || qiscusComment.getState() == QiscusComment.STATE_PENDING || qiscusComment.getState() == QiscusComment.STATE_SENDING ? View.VISIBLE : View.GONE ); } } @Override protected void setUpColor() { if (imageFrameView != null) { imageFrameView.setColorFilter(messageFromMe ? rightBubbleColor : leftBubbleColor); } if (progressView != null) { progressView.setFinishedColor(messageFromMe ? rightProgressFinishedColor : leftProgressFinishedColor); } if (captionView != null) { captionView.setTextColor(messageFromMe ? rightBubbleTextColor : leftBubbleTextColor); captionView.setLinkTextColor(messageFromMe ? rightLinkTextColor : leftLinkTextColor); } super.setUpColor(); } @Override protected void showMessage(QiscusComment qiscusComment) { showImage(qiscusComment); showCaption(qiscusComment); } protected void showCaption(QiscusComment qiscusComment) { if (captionView != null) { captionView.setVisibility(TextUtils.isEmpty(qiscusComment.getCaption()) ? View.GONE : View.VISIBLE); QiscusMentionConfig mentionConfig = Qiscus.getChatConfig().getMentionConfig(); if (mentionConfig.isEnableMention()) { Spannable spannable = QiscusTextUtil.createQiscusSpannableText( qiscusComment.getCaption(), roomMembers, messageFromMe ? mentionConfig.getRightMentionAllColor() : mentionConfig.getLeftMentionAllColor(), messageFromMe ? mentionConfig.getRightMentionOtherColor() : mentionConfig.getLeftMentionOtherColor(), messageFromMe ? mentionConfig.getRightMentionMeColor() : mentionConfig.getLeftMentionMeColor(), mentionConfig.getMentionClickHandler() ); captionView.setText(spannable); } else { captionView.setText(qiscusComment.getCaption()); } } } protected void showImage(QiscusComment qiscusComment) { if (qiscusComment.getAttachmentUri().toString().startsWith("http")) { //We have sent it showSentImage(qiscusComment); } else { //Still uploading the image showSendingImage(qiscusComment); } } protected void showSentImage(QiscusComment qiscusComment) { File localPath = Qiscus.getDataStore().getLocalPath(qiscusComment.getId()); if (localPath == null) { //If the image not yet downloaded showDownloadIcon(true); showBlurryImage(qiscusComment); } else { showDownloadIcon(false); showLocalFileImage(localPath); } } protected void showLocalFileImage(File localPath) { Nirmana.getInstance().get() .setDefaultRequestOptions(new RequestOptions() .dontAnimate() .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .placeholder(R.drawable.qiscus_image_placeholder) .error(R.drawable.qiscus_image_placeholder)) .load(localPath) .into(thumbnailView); } protected void showSendingImage(QiscusComment qiscusComment) { showDownloadIcon(true); File localPath = new File(qiscusComment.getAttachmentUri().toString()); if (localPath.exists()) { //If the image still exist showLocalFileImage(localPath); } else { //If the image file have been removed Nirmana.getInstance().get() .setDefaultRequestOptions(new RequestOptions().dontAnimate()) .load(R.drawable.qiscus_image_placeholder) .into(thumbnailView); } } protected void showBlurryImage(QiscusComment qiscusComment) { Nirmana.getInstance().get() .setDefaultRequestOptions(new RequestOptions() .dontAnimate() .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .placeholder(R.drawable.qiscus_image_placeholder) .error(R.drawable.qiscus_image_placeholder)) .load(QiscusImageUtil.generateBlurryThumbnailUrl(qiscusComment.getAttachmentUri().toString())) .into(thumbnailView); } protected void showDownloadIcon(boolean show) { if (downloadIconView != null) { downloadIconView.setVisibility(show ? View.VISIBLE : View.GONE); } } @Override public void onProgress(QiscusComment qiscusComment, int percentage) { if (qiscusComment.equals(this.qiscusComment) && progressView != null) { progressView.setProgress(percentage); } } @Override public void onDownloading(QiscusComment qiscusComment, boolean downloading) { if (qiscusComment.equals(this.qiscusComment) && progressView != null) { progressView.setVisibility(downloading ? View.VISIBLE : View.GONE); } } private void setUpLinks() { String message = captionView.getText().toString(); Matcher matcher = PatternsCompat.AUTOLINK_WEB_URL.matcher(message); while (matcher.find()) { int start = matcher.start(); if (start > 0 && message.charAt(start - 1) == '@') { continue; } int end = matcher.end(); clickify(start, end, () -> { String url = message.substring(start, end); if (!url.startsWith("http")) { url = "http://" + url; } new CustomTabsIntent.Builder() .setToolbarColor(ContextCompat.getColor(Qiscus.getApps(), Qiscus.getChatConfig().getAppBarColor())) .setShowTitle(true) .addDefaultShareMenuItem() .enableUrlBarHiding() .build() .launchUrl(captionView.getContext(), Uri.parse(url)); }); } } private void clickify(int start, int end, ClickSpan.OnClickListener listener) { CharSequence text = captionView.getText(); ClickSpan span = new ClickSpan(listener); if (start == -1) { return; } if (text instanceof Spannable) { ((Spannable) text).setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { SpannableString s = SpannableString.valueOf(text); s.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); captionView.setText(s); } } private static class ClickSpan extends ClickableSpan { private OnClickListener listener; public ClickSpan(OnClickListener listener) { this.listener = listener; } @Override public void onClick(View widget) { if (listener != null) { listener.onClick(); } } public interface OnClickListener { void onClick(); } } }