diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java index de4b1f4626723de5c4e281daaeecdc39e6f8814d..411dadf584295480e2eb8e29290df6a0ecdafdf3 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java @@ -18,11 +18,13 @@ import androidx.databinding.DataBindingUtil; import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.color.MaterialColors; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ItemMediaBinding; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.ui.util.Attachment; import eu.siacs.conversations.ui.util.ViewUtil; +import eu.siacs.conversations.utils.MimeUtils; import eu.siacs.conversations.worker.ExportBackupWorker; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -33,13 +35,12 @@ import java.util.concurrent.RejectedExecutionException; public class MediaAdapter extends RecyclerView.Adapter { public static final List DOCUMENT_MIMES = - Arrays.asList( - "application/pdf", - "application/vnd.oasis.opendocument.text", - "application/msword", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - "text/x-tex", - "text/plain"); + new ImmutableList.Builder() + .add("application/pdf") + .add("text/x-tex") + .add("text/plain") + .addAll(MimeUtils.WORD_DOCUMENT_MIMES) + .build(); public static final List SPREAD_SHEET_MIMES = Arrays.asList( "text/comma-separated-values", diff --git a/src/main/java/eu/siacs/conversations/utils/MimeUtils.java b/src/main/java/eu/siacs/conversations/utils/MimeUtils.java index 00ccf81243ac0e475dfb1432e51078cb7fc971e6..de23f3bba0ac561e9b7a00f7f8041af6e51424d2 100644 --- a/src/main/java/eu/siacs/conversations/utils/MimeUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/MimeUtils.java @@ -48,6 +48,12 @@ public final class MimeUtils { "video/3gpp", // .3gp files can contain audio, video or both "video/3gpp2"); + public static final List WORD_DOCUMENT_MIMES = + Arrays.asList( + "application/vnd.oasis.opendocument.text", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + private static final Map mimeTypeToExtensionMap = new HashMap<>(); private static final Map extensionToMimeTypeMap = new HashMap<>(); diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 245f196a66a70b16bbfc02d567370e947a9c9010..9f3aab8bc9ca937c35f530e91ec494e580c6006e 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -7,21 +7,12 @@ import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.Pair; import android.widget.TextView; - import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; import androidx.annotation.StringRes; import androidx.core.content.ContextCompat; - import com.google.android.material.color.MaterialColors; import com.google.common.base.Strings; - -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Locale; - import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -37,35 +28,42 @@ import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.ui.util.QuoteHelper; import eu.siacs.conversations.worker.ExportBackupWorker; import eu.siacs.conversations.xmpp.Jid; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; public class UIHelper { - private static final List LOCATION_QUESTIONS = Arrays.asList( - "where are you", //en - "where are you now", //en - "where are you right now", //en - "whats your 20", //en - "what is your 20", //en - "what's your 20", //en - "whats your twenty", //en - "what is your twenty", //en - "what's your twenty", //en - "wo bist du", //de - "wo bist du jetzt", //de - "wo bist du gerade", //de - "wo seid ihr", //de - "wo seid ihr jetzt", //de - "wo seid ihr gerade", //de - "dónde estás", //es - "donde estas" //es - ); - - private static final List PUNCTIONATION = Arrays.asList('.', ',', '?', '!', ';', ':'); - - private static final int SHORT_DATE_FLAGS = DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL; - private static final int FULL_DATE_FLAGS = DateUtils.FORMAT_SHOW_TIME - | DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE; + private static final List LOCATION_QUESTIONS = + Arrays.asList( + "where are you", // en + "where are you now", // en + "where are you right now", // en + "whats your 20", // en + "what is your 20", // en + "what's your 20", // en + "whats your twenty", // en + "what is your twenty", // en + "what's your twenty", // en + "wo bist du", // de + "wo bist du jetzt", // de + "wo bist du gerade", // de + "wo seid ihr", // de + "wo seid ihr jetzt", // de + "wo seid ihr gerade", // de + "dónde estás", // es + "donde estas" // es + ); + + private static final List PUNCTIONATION = + Arrays.asList('.', ',', '?', '!', ';', ':'); + + private static final int SHORT_DATE_FLAGS = + DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL; + private static final int FULL_DATE_FLAGS = + DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE; public static String readableTimeDifference(Context context, long time) { return readableTimeDifference(context, time, false); @@ -75,8 +73,7 @@ public class UIHelper { return readableTimeDifference(context, time, true); } - private static String readableTimeDifference(Context context, long time, - boolean fullDate) { + private static String readableTimeDifference(Context context, long time, boolean fullDate) { if (time == 0) { return context.getString(R.string.just_now); } @@ -93,11 +90,9 @@ public class UIHelper { return df.format(date); } else { if (fullDate) { - return DateUtils.formatDateTime(context, date.getTime(), - FULL_DATE_FLAGS); + return DateUtils.formatDateTime(context, date.getTime(), FULL_DATE_FLAGS); } else { - return DateUtils.formatDateTime(context, date.getTime(), - SHORT_DATE_FLAGS); + return DateUtils.formatDateTime(context, date.getTime(), SHORT_DATE_FLAGS); } } } @@ -116,8 +111,7 @@ public class UIHelper { cal1.add(Calendar.DAY_OF_YEAR, -1); cal2.setTime(new Date(date)); return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) - && cal1.get(Calendar.DAY_OF_YEAR) == cal2 - .get(Calendar.DAY_OF_YEAR); + && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR); } public static boolean sameDay(long a, long b) { @@ -130,8 +124,7 @@ public class UIHelper { cal1.setTime(a); cal2.setTime(b); return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) - && cal1.get(Calendar.DAY_OF_YEAR) == cal2 - .get(Calendar.DAY_OF_YEAR); + && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR); } public static String lastseen(Context context, boolean active, long time) { @@ -147,52 +140,68 @@ public class UIHelper { } else if (difference < 60 * 60 * 2) { return context.getString(R.string.last_seen_hour); } else if (difference < 60 * 60 * 24) { - return context.getString(R.string.last_seen_hours, - Math.round(difference / (60.0 * 60.0))); + return context.getString( + R.string.last_seen_hours, Math.round(difference / (60.0 * 60.0))); } else if (difference < 60 * 60 * 48) { return context.getString(R.string.last_seen_day); } else { - return context.getString(R.string.last_seen_days, - Math.round(difference / (60.0 * 60.0 * 24.0))); + return context.getString( + R.string.last_seen_days, Math.round(difference / (60.0 * 60.0 * 24.0))); } } - public static int getColorForName(final String name) { return XEP0392Helper.rgbFromNick(name); } - - public static Pair getMessagePreview(final Context context, final Message message) { + public static Pair getMessagePreview( + final Context context, final Message message) { return getMessagePreview(context, message, 0); } - public static Pair getMessagePreview(final Context context, final Message message, @ColorInt int textColor) { + public static Pair getMessagePreview( + final Context context, final Message message, @ColorInt int textColor) { final Transferable d = message.getTransferable(); if (d != null) { switch (d.getStatus()) { case Transferable.STATUS_CHECKING: - return new Pair<>(context.getString(R.string.checking_x, - getFileDescriptionString(context, message)), true); + return new Pair<>( + context.getString( + R.string.checking_x, + getFileDescriptionString(context, message)), + true); case Transferable.STATUS_DOWNLOADING: - return new Pair<>(context.getString(R.string.receiving_x_file, - getFileDescriptionString(context, message), - d.getProgress()), true); + return new Pair<>( + context.getString( + R.string.receiving_x_file, + getFileDescriptionString(context, message), + d.getProgress()), + true); case Transferable.STATUS_OFFER: case Transferable.STATUS_OFFER_CHECK_FILESIZE: - return new Pair<>(context.getString(R.string.x_file_offered_for_download, - getFileDescriptionString(context, message)), true); + return new Pair<>( + context.getString( + R.string.x_file_offered_for_download, + getFileDescriptionString(context, message)), + true); case Transferable.STATUS_FAILED: return new Pair<>(context.getString(R.string.file_transmission_failed), true); case Transferable.STATUS_CANCELLED: - return new Pair<>(context.getString(R.string.file_transmission_cancelled), true); + return new Pair<>( + context.getString(R.string.file_transmission_cancelled), true); case Transferable.STATUS_UPLOADING: if (message.getStatus() == Message.STATUS_OFFERED) { - return new Pair<>(context.getString(R.string.offering_x_file, - getFileDescriptionString(context, message)), true); + return new Pair<>( + context.getString( + R.string.offering_x_file, + getFileDescriptionString(context, message)), + true); } else { - return new Pair<>(context.getString(R.string.sending_x_file, - getFileDescriptionString(context, message)), true); + return new Pair<>( + context.getString( + R.string.sending_x_file, + getFileDescriptionString(context, message)), + true); } default: return new Pair<>("", false); @@ -215,18 +224,28 @@ public class UIHelper { if (!rtpSessionStatus.successful && received) { return new Pair<>(context.getString(R.string.missed_call), true); } else { - return new Pair<>(context.getString(received ? R.string.incoming_call : R.string.outgoing_call), true); + return new Pair<>( + context.getString( + received ? R.string.incoming_call : R.string.outgoing_call), + true); } } else { final String body = MessageUtils.filterLtrRtl(message.getBody()); if (body.startsWith(Message.ME_COMMAND)) { - return new Pair<>(body.replaceAll("^" + Message.ME_COMMAND, - UIHelper.getMessageDisplayName(message) + " "), false); + return new Pair<>( + body.replaceAll( + "^" + Message.ME_COMMAND, + UIHelper.getMessageDisplayName(message) + " "), + false); } else if (message.isGeoUri()) { return new Pair<>(context.getString(R.string.location), true); - } else if (message.treatAsDownloadable() || MessageUtils.unInitiatedButKnownSize(message)) { - return new Pair<>(context.getString(R.string.x_file_offered_for_download, - getFileDescriptionString(context, message)), true); + } else if (message.treatAsDownloadable() + || MessageUtils.unInitiatedButKnownSize(message)) { + return new Pair<>( + context.getString( + R.string.x_file_offered_for_download, + getFileDescriptionString(context, message)), + true); } else { SpannableStringBuilder styledBody = new SpannableStringBuilder(body); if (textColor != 0) { @@ -283,18 +302,18 @@ public class UIHelper { return input.length() > 256 ? StylingHelper.subSequence(input, 0, 256) : input; } - public static boolean isPositionPrecededByBodyStart(CharSequence body, int pos){ + public static boolean isPositionPrecededByBodyStart(CharSequence body, int pos) { // true if not a single linebreak before current position - for (int i = pos - 1; i >= 0; i--){ - if (body.charAt(i) != ' '){ + for (int i = pos - 1; i >= 0; i--) { + if (body.charAt(i) != ' ') { return false; } } return true; } - public static boolean isPositionPrecededByLineStart(CharSequence body, int pos){ - if (isPositionPrecededByBodyStart(body, pos)){ + public static boolean isPositionPrecededByLineStart(CharSequence body, int pos) { + if (isPositionPrecededByBodyStart(body, pos)) { return true; } return body.charAt(pos - 1) == '\n'; @@ -342,7 +361,8 @@ public class UIHelper { final char c = body.charAt(i); if (Character.isWhitespace(c)) { return false; - } else if (QuoteHelper.isPositionQuoteCharacter(body, pos) || QuoteHelper.isPositionQuoteEndCharacter(body, pos)) { + } else if (QuoteHelper.isPositionQuoteCharacter(body, pos) + || QuoteHelper.isPositionQuoteEndCharacter(body, pos)) { return body.length() == i + 1 || Character.isWhitespace(body.charAt(i + 1)); } } @@ -405,6 +425,8 @@ public class UIHelper { return context.getString(R.string.image); } else if (mime.contains("pdf")) { return context.getString(R.string.pdf_document); + } else if (MimeUtils.WORD_DOCUMENT_MIMES.contains(mime)) { + return context.getString(R.string.word_document); } else if (mime.equals("application/vnd.android.package-archive")) { return context.getString(R.string.apk); } else if (mime.equals(ExportBackupWorker.MIME_TYPE)) { @@ -413,7 +435,8 @@ public class UIHelper { return context.getString(R.string.vcard); } else if (mime.equals("text/x-vcalendar") || mime.equals("text/calendar")) { return context.getString(R.string.event); - } else if (mime.equals("application/epub+zip") || mime.equals("application/vnd.amazon.mobi8-ebook")) { + } else if (mime.equals("application/epub+zip") + || mime.equals("application/vnd.amazon.mobi8-ebook")) { return context.getString(R.string.ebook); } else if (mime.equals("application/gpx+xml")) { return context.getString(R.string.gpx_track); @@ -438,7 +461,8 @@ public class UIHelper { return contact != null ? contact.getDisplayName() : ""; } } else { - if (conversation instanceof Conversation && conversation.getMode() == Conversation.MODE_MULTI) { + if (conversation instanceof Conversation + && conversation.getMode() == Conversation.MODE_MULTI) { return ((Conversation) conversation).getMucOptions().getSelf().getName(); } else { final Account account = conversation.getAccount(); @@ -449,12 +473,11 @@ public class UIHelper { } else { return displayName; } - } } } - public static String getMessageHint(final Context context,final Conversation conversation) { + public static String getMessageHint(final Context context, final Conversation conversation) { return switch (conversation.getNextEncryption()) { case Message.ENCRYPTION_NONE -> { if (Config.multipleEncryptionChoices()) { @@ -491,10 +514,12 @@ public class UIHelper { || message.getType() != Message.TYPE_TEXT) { return false; } - final String body = Strings.nullToEmpty(message.getBody()) - .trim() - .toLowerCase(Locale.getDefault()) - .replace("?", "").replace("¿", ""); + final String body = + Strings.nullToEmpty(message.getBody()) + .trim() + .toLowerCase(Locale.getDefault()) + .replace("?", "") + .replace("¿", ""); return LOCATION_QUESTIONS.contains(body); } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e143b167cc19d9189fd545eebf32737505493109..6bf79ca139943c41aa2d439f1203b19e73bdcccd 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -422,6 +422,7 @@ vector graphic multimedia file PDF document + Word document Android App Audiobook Contact