show links in SOS message

Daniel Gultsch created

Change summary

build.gradle                                                             |  2 
gradle/wrapper/gradle-wrapper.properties                                 |  2 
src/main/java/de/gultsch/common/Linkify.java                             |  4 
src/main/java/eu/siacs/conversations/entities/Account.java               |  4 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java |  1 
src/main/java/eu/siacs/conversations/ui/AboutActivity.java               | 15 
src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java   |  5 
src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java         | 13 
src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java           | 14 
src/main/java/eu/siacs/conversations/utils/StylingHelper.java            |  8 
src/main/res/layout/activity_about.xml                                   |  7 
src/main/res/layout/activity_edit_account.xml                            | 25 
src/main/res/layout/activity_muc_details.xml                             |  1 
src/main/res/layout/item_message_content.xml                             |  1 
14 files changed, 60 insertions(+), 42 deletions(-)

Detailed changes

build.gradle 🔗

@@ -6,7 +6,7 @@ buildscript {
         mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:8.5.2'
+        classpath 'com.android.tools.build:gradle:8.9.1'
         classpath "com.diffplug.spotless:spotless-plugin-gradle:7.0.2"
     }
 }

gradle/wrapper/gradle-wrapper.properties 🔗

@@ -1,6 +1,6 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
 networkTimeout=10000
 validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME

src/main/java/de/gultsch/common/Linkify.java 🔗

@@ -30,7 +30,7 @@
 package de.gultsch.common;
 
 import android.net.Uri;
-import android.text.Editable;
+import android.text.Spannable;
 import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -66,7 +66,7 @@ public class Linkify {
         };
     }
 
-    public static void addLinks(final Editable body) {
+    public static void addLinks(final Spannable body) {
         android.text.util.Linkify.addLinks(body, Patterns.URI_GENERIC, null, MATCH_FILTER, null);
     }
 

src/main/java/eu/siacs/conversations/entities/Account.java 🔗

@@ -796,7 +796,9 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
 
     public boolean isServiceOutage() {
         final var sos = this.serviceOutageStatus;
-        if (sos != null && ServiceOutageStatus.isPossibleOutage(this.status)) {
+        if (sos != null
+                && isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY)
+                && ServiceOutageStatus.isPossibleOutage(this.status)) {
             return sos.isNow();
         }
         return false;

src/main/java/eu/siacs/conversations/ui/AboutActivity.java 🔗

@@ -3,20 +3,27 @@ package eu.siacs.conversations.ui;
 import static eu.siacs.conversations.ui.XmppActivity.configureActionBar;
 
 import android.os.Bundle;
-
+import android.text.SpannableString;
+import android.text.method.LinkMovementMethod;
 import androidx.databinding.DataBindingUtil;
-
+import de.gultsch.common.Linkify;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.databinding.ActivityAboutBinding;
+import eu.siacs.conversations.ui.text.FixedURLSpan;
 
 public class AboutActivity extends ActionBarActivity {
 
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        final ActivityAboutBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_about);
+        final ActivityAboutBinding binding =
+                DataBindingUtil.setContentView(this, R.layout.activity_about);
+        final var text = new SpannableString(getString(R.string.pref_about_message));
+        Linkify.addLinks(text);
+        FixedURLSpan.fix(text);
+        binding.about.setText(text);
+        binding.about.setMovementMethod(LinkMovementMethod.getInstance());
         Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
 
         setSupportActionBar(binding.toolbar);

src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java 🔗

@@ -10,7 +10,7 @@ import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
 import android.text.Editable;
-import android.text.SpannableStringBuilder;
+import android.text.SpannableString;
 import android.text.TextWatcher;
 import android.text.method.LinkMovementMethod;
 import android.view.Menu;
@@ -557,7 +557,7 @@ public class ConferenceDetailsActivity extends XmppActivity
             this.binding.mucTitle.setVisibility(View.GONE);
         }
         if (printableValue(subject)) {
-            SpannableStringBuilder spannable = new SpannableStringBuilder(subject);
+            final var spannable = new SpannableString(subject);
             StylingHelper.format(spannable, this.binding.mucSubject.getCurrentTextColor());
             Linkify.addLinks(spannable);
             FixedURLSpan.fix(spannable);
@@ -568,7 +568,6 @@ public class ConferenceDetailsActivity extends XmppActivity
                                     .TextAppearance_Material3_BodyMedium
                             : com.google.android.material.R.style
                                     .TextAppearance_Material3_BodyLarge);
-            this.binding.mucSubject.setAutoLinkMask(0);
             this.binding.mucSubject.setVisibility(View.VISIBLE);
             this.binding.mucSubject.setMovementMethod(LinkMovementMethod.getInstance());
         } else {

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -16,9 +16,11 @@ import android.provider.Settings;
 import android.security.KeyChain;
 import android.security.KeyChainAliasCallback;
 import android.text.Editable;
+import android.text.SpannableString;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.text.format.DateUtils;
+import android.text.method.LinkMovementMethod;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -40,6 +42,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.textfield.TextInputLayout;
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Strings;
+import de.gultsch.common.Linkify;
 import eu.siacs.conversations.AppSettings;
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
@@ -58,6 +61,7 @@ import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
 import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested;
 import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 import eu.siacs.conversations.ui.adapter.PresenceTemplateAdapter;
+import eu.siacs.conversations.ui.text.FixedURLSpan;
 import eu.siacs.conversations.ui.util.AvatarWorkerTask;
 import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
 import eu.siacs.conversations.ui.util.PendingItem;
@@ -1442,8 +1446,12 @@ public class EditAccountActivity extends OmemoActivity
                 if (Strings.isNullOrEmpty(sosMessage)) {
                     this.binding.sosMessage.setVisibility(View.GONE);
                 } else {
-                    this.binding.sosMessage.setText(sosMessage);
+                    final var sosMessageSpannable = new SpannableString(sosMessage);
+                    Linkify.addLinks(sosMessageSpannable);
+                    FixedURLSpan.fix(sosMessageSpannable);
+                    this.binding.sosMessage.setText(sosMessageSpannable);
                     this.binding.sosMessage.setVisibility(View.VISIBLE);
+                    this.binding.sosMessage.setMovementMethod(LinkMovementMethod.getInstance());
                 }
                 final var expectedEnd = sos.getExpectedEnd();
                 if (expectedEnd <= 0) {
@@ -1457,7 +1465,8 @@ public class EditAccountActivity extends OmemoActivity
                                             this,
                                             expectedEnd,
                                             DateUtils.FORMAT_SHOW_TIME
-                                                    | DateUtils.FORMAT_ABBREV_ALL
+                                                    | DateUtils.FORMAT_NUMERIC_DATE
+                                                    | DateUtils.FORMAT_SHOW_YEAR
                                                     | DateUtils.FORMAT_SHOW_DATE)));
                 }
             } else {

src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java 🔗

@@ -34,7 +34,7 @@ import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
-import android.text.Editable;
+import android.text.Spannable;
 import android.text.Spanned;
 import android.text.style.URLSpan;
 import android.util.Log;
@@ -56,12 +56,12 @@ public class FixedURLSpan extends URLSpan {
         super(url);
     }
 
-    public static void fix(final Editable editable) {
-        for (final URLSpan urlspan : editable.getSpans(0, editable.length() - 1, URLSpan.class)) {
-            final int start = editable.getSpanStart(urlspan);
-            final int end = editable.getSpanEnd(urlspan);
-            editable.removeSpan(urlspan);
-            editable.setSpan(
+    public static void fix(final Spannable spannable) {
+        for (final URLSpan urlspan : spannable.getSpans(0, spannable.length() - 1, URLSpan.class)) {
+            final int start = spannable.getSpanStart(urlspan);
+            final int end = spannable.getSpanEnd(urlspan);
+            spannable.removeSpan(urlspan);
+            spannable.setSpan(
                     new FixedURLSpan(urlspan.getURL()),
                     start,
                     end,

src/main/java/eu/siacs/conversations/utils/StylingHelper.java 🔗

@@ -70,7 +70,7 @@ public class StylingHelper {
     }
 
     public static void format(
-            final Editable editable, int start, int end, @ColorInt int textColor) {
+            final Spannable editable, int start, int end, @ColorInt int textColor) {
         for (ImStyleParser.Style style : ImStyleParser.parse(editable, start, end)) {
             final int keywordLength = style.getKeyword().length();
             editable.setSpan(
@@ -85,7 +85,7 @@ public class StylingHelper {
         }
     }
 
-    public static void format(final Editable editable, @ColorInt final int textColor) {
+    public static void format(final Spannable editable, @ColorInt final int textColor) {
         format(editable, 0, editable.length() - 1, textColor);
     }
 
@@ -121,7 +121,7 @@ public class StylingHelper {
     }
 
     private static void highlight(
-            final TextView view, final Editable editable, final String needle) {
+            final TextView view, final Spannable editable, final String needle) {
         final int length = needle.length();
         String string = editable.toString();
         int start = indexOfIgnoreCase(string, needle, 0);
@@ -197,7 +197,7 @@ public class StylingHelper {
     }
 
     private static void makeKeywordOpaque(
-            final Editable editable, int start, int end, @ColorInt int fallbackTextColor) {
+            final Spannable editable, int start, int end, @ColorInt int fallbackTextColor) {
         QuoteSpan[] quoteSpans = editable.getSpans(start, end, QuoteSpan.class);
         @ColorInt
         int textColor = quoteSpans.length > 0 ? quoteSpans[0].getColor() : fallbackTextColor;

src/main/res/layout/activity_about.xml 🔗

@@ -1,4 +1,5 @@
-<layout xmlns:android="http://schemas.android.com/apk/res/android">
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -25,13 +26,13 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
                 <TextView
+                    android:id="@+id/about"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:autoLink="web"
                     android:fontFamily="monospace"
                     android:linksClickable="true"
                     android:layout_margin="@dimen/card_padding_regular"
-                    android:text="@string/pref_about_message"
+                    tools:text="@string/pref_about_message"
                     android:textAppearance="?textAppearanceBodyMedium"
                     android:typeface="monospace" />
             </LinearLayout>

src/main/res/layout/activity_edit_account.xml 🔗

@@ -147,8 +147,8 @@
                 </com.google.android.material.card.MaterialCardView>
 
                 <com.google.android.material.card.MaterialCardView
-                    style="?attr/materialCardViewElevatedStyle"
                     android:id="@+id/service_outage"
+                    style="?attr/materialCardViewElevatedStyle"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginLeft="@dimen/activity_horizontal_margin"
@@ -156,8 +156,8 @@
                     android:layout_marginRight="@dimen/activity_horizontal_margin"
                     android:layout_marginBottom="@dimen/activity_vertical_margin"
                     android:visibility="gone"
-                    tools:visibility="visible"
-                    app:cardBackgroundColor="?colorErrorContainer">
+                    app:cardBackgroundColor="?colorErrorContainer"
+                    tools:visibility="visible">
 
                     <LinearLayout
                         android:layout_width="match_parent"
@@ -168,29 +168,30 @@
 
                         <TextView
                             android:id="@+id/sos_title"
-                            android:textColor="?colorOnErrorContainer"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:text="@string/account_status_service_outage_known"
-                            android:textAppearance="?textAppearanceTitleLarge" />
+                            android:textAppearance="?textAppearanceTitleLarge"
+                            android:textColor="?colorOnErrorContainer" />
 
                         <TextView
-                            android:textColor="?colorOnErrorContainer"
                             android:id="@+id/sos_message"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:layout_marginTop="8dp"
-                            tools:text="Our service is currently performing server updates"
-                            android:textAppearance="?textAppearanceBodyMedium" />
+                            android:textAppearance="?textAppearanceBodyMedium"
+                            android:textColor="?colorOnErrorContainer"
+                            android:textColorLink="?colorOnErrorContainer"
+                            tools:text="Our service is currently performing server updates" />
 
                         <TextView
-                            android:textColor="?colorOnErrorContainer"
                             android:id="@+id/sos_scheduled_end"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:layout_marginTop="8dp"
-                            tools:text="@string/sos_scheduled_return"
-                            android:textAppearance="?textAppearanceBodyMedium" />
+                            android:layout_marginTop="16sp"
+                            android:textAppearance="?textAppearanceBodyLarge"
+                            android:textColor="?colorOnErrorContainer"
+                            tools:text="@string/sos_scheduled_return" />
                     </LinearLayout>
                 </com.google.android.material.card.MaterialCardView>
 

src/main/res/layout/activity_muc_details.xml 🔗

@@ -86,7 +86,6 @@
                                             android:id="@+id/muc_subject"
                                             android:layout_width="wrap_content"
                                             android:layout_height="wrap_content"
-                                            android:autoLink="web"
                                             android:textAppearance="?textAppearanceTitleMedium" />
                                     </LinearLayout>
 

src/main/res/layout/item_message_content.xml 🔗

@@ -11,7 +11,6 @@
             android:layout_height="wrap_content"
             android:layout_marginHorizontal="10dp"
             android:layout_marginTop="4dp"
-            android:autoLink="web"
             android:longClickable="false"
             android:textAppearance="?textAppearanceBodyMedium" />