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);
}