~singpolyma/cheogram-android

4f4a5bb2a925b0f4c9fd62187cf90a4651af7ff7 — Stephen Paul Weber 1 year, 9 months ago 87ddf94
Actually display images we already have inline in XHTML-IM

If we already have the image for the Cid downloaded, then do create the
thumbnail and show it inline.
M src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java => src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +4 -3
@@ 48,6 48,7 @@ import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.PresenceTemplate;
import eu.siacs.conversations.entities.Roster;


@@ 733,12 734,12 @@ public class DatabaseBackend extends SQLiteOpenHelper {
        cursor.close();
    }

    public File getFileForCid(Cid cid) {
    public DownloadableFile getFileForCid(Cid cid) {
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.query("cheogram.cids", new String[]{"path"}, "cid=?", new String[]{cid.toString()}, null, null, null);
        File f = null;
        DownloadableFile f = null;
        if (cursor.moveToNext()) {
            f = new File(cursor.getString(0));
            f = new DownloadableFile(cursor.getString(0));
        }
        cursor.close();
        return f;

M src/main/java/eu/siacs/conversations/persistance/FileBackend.java => src/main/java/eu/siacs/conversations/persistance/FileBackend.java +26 -15
@@ 13,6 13,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.ImageDecoder;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.pdf.PdfRenderer;
import android.media.MediaMetadataRetriever;


@@ 995,16 996,18 @@ public class FileBackend {
    }

    public Drawable getThumbnail(Message message, Resources res, int size, boolean cacheOnly) throws IOException {
        final String uuid = message.getUuid();
        return getThumbnail(getFile(message), res, size, cacheOnly);
    }

    public Drawable getThumbnail(DownloadableFile file, Resources res, int size, boolean cacheOnly) throws IOException {
        final LruCache<String, Drawable> cache = mXmppConnectionService.getDrawableCache();
        Drawable thumbnail = cache.get(uuid);
        Drawable thumbnail = cache.get(file.getAbsolutePath());
        if ((thumbnail == null) && (!cacheOnly)) {
            synchronized (THUMBNAIL_LOCK) {
                thumbnail = cache.get(uuid);
                thumbnail = cache.get(file.getAbsolutePath());
                if (thumbnail != null) {
                    return thumbnail;
                }
                DownloadableFile file = getFile(message);
                final String mime = file.getMimeType();
                if ("application/pdf".equals(mime)) {
                    thumbnail = new BitmapDrawable(res, getPdfDocumentPreview(file, size));


@@ 1016,7 1019,7 @@ public class FileBackend {
                        throw new FileNotFoundException();
                    }
                }
                cache.put(uuid, thumbnail);
                cache.put(file.getAbsolutePath(), thumbnail);
            }
        }
        return thumbnail;


@@ 1028,22 1031,30 @@ public class FileBackend {
          return drawDrawable(drawable);
    }

    public static Rect rectForSize(int w, int h, int size) {
        int scalledW;
        int scalledH;
        if (w <= h) {
            scalledW = Math.max((int) (w / ((double) h / size)), 1);
            scalledH = size;
        } else {
            scalledW = size;
            scalledH = Math.max((int) (h / ((double) w / size)), 1);
        }

        if (scalledW > w || scalledH > h) return new Rect(0, 0, w, h);

        return new Rect(0, 0, scalledW, scalledH);
    }

    private Drawable getImagePreview(File file, Resources res, int size, final String mime) throws IOException {
        if (android.os.Build.VERSION.SDK_INT >= 28) {
            ImageDecoder.Source source = ImageDecoder.createSource(file);
            return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
                int w = info.getSize().getWidth();
                int h = info.getSize().getHeight();
                int scalledW;
                int scalledH;
                if (w <= h) {
                    scalledW = Math.max((int) (w / ((double) h / size)), 1);
                    scalledH = size;
                } else {
                    scalledW = size;
                    scalledH = Math.max((int) (h / ((double) w / size)), 1);
                }
                decoder.setTargetSize(scalledW, scalledH);
                Rect r = rectForSize(w, h, size);
                decoder.setTargetSize(r.width(), r.height());
            });
        } else {
            BitmapFactory.Options options = new BitmapFactory.Options();

M src/main/java/eu/siacs/conversations/services/XmppConnectionService.java => src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +2 -1
@@ 103,6 103,7 @@ import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Conversational;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;


@@ 549,7 550,7 @@ public class XmppConnectionService extends Service {
        return this.fileBackend;
    }

    public File getFileForCid(Cid cid) {
    public DownloadableFile getFileForCid(Cid cid) {
        return this.databaseBackend.getFileForCid(cid);
    }


M src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java => src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +49 -1
@@ 6,8 6,10 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;


@@ 32,15 34,19 @@ import android.widget.Toast;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;

import com.google.common.base.Strings;

import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import io.ipfs.cid.Cid;

import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;


@@ 439,7 445,25 @@ public class MessageAdapter extends ArrayAdapter<Message> {
        if (message.getBody() != null && !message.getBody().equals("")) {
            viewHolder.messageBody.setVisibility(View.VISIBLE);
            final String nick = UIHelper.getMessageDisplayName(message);
            SpannableStringBuilder body = message.getMergedBody();
            Drawable fallbackImg = ResourcesCompat.getDrawable(activity.getResources(), activity.getThemeResource(R.attr.ic_attach_photo, R.drawable.ic_attach_photo), null);
            fallbackImg.setBounds(FileBackend.rectForSize(fallbackImg.getIntrinsicWidth(), fallbackImg.getIntrinsicHeight(), (int) (metrics.density * 32)));
            SpannableStringBuilder body = message.getMergedBody((cid) -> {
                try {
                    DownloadableFile f = activity.xmppConnectionService.getFileForCid(cid);
                    if (f == null) return null;

                    Drawable d = activity.xmppConnectionService.getFileBackend().getThumbnail(f, activity.getResources(), (int) (metrics.density * 288), true);
                    if (d == null) {
                        new ThumbnailTask().execute(f);
                    } else {
                        d = d.getConstantState().newDrawable();
                        d.setBounds(FileBackend.rectForSize(d.getIntrinsicWidth(), d.getIntrinsicHeight(), (int) (metrics.density * 32)));
                    }
                    return d;
                } catch (final IOException e) {
                    return fallbackImg;
                }
            }, fallbackImg);
            boolean hasMeCommand = message.hasMeCommand();
            if (hasMeCommand) {
                body = body.replace(0, Message.ME_COMMAND.length(), nick + " ");


@@ 959,4 983,28 @@ public class MessageAdapter extends ArrayAdapter<Message> {
        protected TextView encryption;
        protected ListView commands_list;
    }

    class ThumbnailTask extends AsyncTask<DownloadableFile, Void, Drawable[]> {
        @Override
        protected Drawable[] doInBackground(DownloadableFile... params) {
            if (isCancelled()) return null;

            Drawable[] d = new Drawable[params.length];
            for (int i = 0; i < params.length; i++) {
                try {
                    d[i] = activity.xmppConnectionService.getFileBackend().getThumbnail(params[i], activity.getResources(), (int) (metrics.density * 288), false);
                } catch (final IOException e) {
                    d[i] = null;
                }
            }

            return d;
        }

        @Override
        protected void onPostExecute(final Drawable[] d) {
            if (isCancelled()) return;
            activity.xmppConnectionService.updateConversationUi();
        }
    }
}

M src/main/java/eu/siacs/conversations/utils/UIHelper.java => src/main/java/eu/siacs/conversations/utils/UIHelper.java +5 -1
@@ 1,12 1,14 @@
package eu.siacs.conversations.utils;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.SpannableStringBuilder;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.Pair;

import androidx.annotation.ColorInt;
import androidx.core.content.res.ResourcesCompat;

import com.google.common.base.Strings;



@@ 319,7 321,9 @@ public class UIHelper {
                return new Pair<>(context.getString(R.string.x_file_offered_for_download,
                        getFileDescriptionString(context, message)), true);
            } else {
                SpannableStringBuilder styledBody = new SpannableStringBuilder(body);
                Drawable fallbackImg = ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_attach_photo, null);
                fallbackImg.setBounds(0, 0, fallbackImg.getIntrinsicWidth(), fallbackImg.getIntrinsicHeight());
                SpannableStringBuilder styledBody = message.getSpannableBody(null, fallbackImg);
                if (textColor != 0) {
                    StylingHelper.format(styledBody, 0, styledBody.length() - 1, textColor);
                }