Show warning bar if any account is not set to MAM always

Stephen Paul Weber created

Change summary

src/cheogram/res/values/strings.xml                                        |  1 
src/main/java/eu/siacs/conversations/entities/Account.java                 | 10 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java   |  7 
src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java | 16 
src/main/res/layout/fragment_conversations_overview.xml                    | 45 
5 files changed, 77 insertions(+), 2 deletions(-)

Detailed changes

src/cheogram/res/values/strings.xml 🔗

@@ -23,6 +23,7 @@
     <string name="action_complete">Finish</string>
     <string name="action_close">Close</string>
     <string name="action_execute">Go</string>
+    <string name="action_fix">Fix</string>
     <string name="pref_theme_oledblack">OLED Black</string>
     <string name="pref_theme_custom">Custom</string>
     <string name="invite_to_app">Invite to Chat</string>

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

@@ -39,6 +39,7 @@ import eu.siacs.conversations.services.AvatarService;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.utils.XmppUri;
+import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xmpp.Jid;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import eu.siacs.conversations.xmpp.jingle.RtpCapability;
@@ -114,6 +115,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
     private String fastToken;
     private Integer color = null;
     private final HashMultimap<String, Contact> gateways = HashMultimap.create();
+    private Element mamPrefs = null;
 
     public Account(final Jid jid, final String password) {
         this(
@@ -213,6 +215,14 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
                 cursor.getString(cursor.getColumnIndexOrThrow(FAST_TOKEN)));
     }
 
+    public void setMamPrefs(Element prefs) {
+        mamPrefs = prefs;
+    }
+
+    public Element mamPrefs() {
+        return mamPrefs;
+    }
+
     public boolean httpUploadAvailable(long size) {
         return xmppConnection != null && xmppConnection.getFeatures().httpUpload(size);
     }

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -431,6 +431,7 @@ public class XmppConnectionService extends Service {
                 for (Conversation conversation : pendingJoins) {
                     joinMuc(conversation);
                 }
+                fetchMamPreferences(account, null);
                 scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
             } else if (account.getStatus() == Account.State.OFFLINE || account.getStatus() == Account.State.DISABLED || account.getStatus() == Account.State.LOGGED_OUT) {
                 resetSendingToWaiting(account);
@@ -5830,9 +5831,10 @@ public class XmppConnectionService extends Service {
         sendIqPacket(account, request, (packet) -> {
             final Element prefs = packet.findChild("prefs", version.namespace);
             if (packet.getType() == Iq.Type.RESULT && prefs != null) {
-                callback.onPreferencesFetched(prefs);
+                account.setMamPrefs(prefs);
+                if (callback != null) callback.onPreferencesFetched(prefs);
             } else {
-                callback.onPreferencesFetchFailed();
+                if (callback != null) callback.onPreferencesFetchFailed();
             }
         });
     }
@@ -5931,6 +5933,7 @@ public class XmppConnectionService extends Service {
     public void pushMamPreferences(Account account, Element prefs) {
         final Iq set = new Iq(Iq.Type.SET);
         set.addChild(prefs);
+        account.setMamPrefs(prefs);
         sendIqPacket(account, set, null);
     }
 

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

@@ -511,6 +511,22 @@ public class ConversationsOverviewFragment extends XmppFragment {
 			binding.fab.setVisibility(View.VISIBLE);
 		}
 		setupSwipe();
+
+		binding.snackbar.setVisibility(View.GONE);
+		if (activity.xmppConnectionService == null) return;
+		for (final var account : activity.xmppConnectionService.getAccounts()) {
+			if (account.mamPrefs() != null && !"always".equals(account.mamPrefs().getAttribute("default"))) {
+				binding.snackbar.setVisibility(View.VISIBLE);
+				binding.snackbarMessage.setText("Your account " + account.getJid().asBareJid().toEscapedString() + " does not have archiving fully enabled. This may result in missed messages if you use multiple devices or apps.");
+				binding.snackbarAction.setOnClickListener((v) -> {
+					final var prefs = account.mamPrefs();
+					prefs.setAttribute("default", "always");
+					activity.xmppConnectionService.pushMamPreferences(account, prefs);
+					refresh();
+				});
+				break;
+			}
+		}
 	}
 
 	private void setScrollPosition(ScrollState scrollPosition) {

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

@@ -5,6 +5,49 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+        <RelativeLayout
+            android:id="@+id/snackbar"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_above="@+id/context_preview"
+            android:layout_marginLeft="8dp"
+            android:layout_marginRight="8dp"
+            android:layout_marginBottom="4dp"
+            android:background="@drawable/snackbar"
+            android:minHeight="48dp"
+            android:visibility="gone">
+
+            <TextView
+                android:id="@+id/snackbar_message"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentStart="true"
+                android:layout_centerVertical="true"
+                android:layout_marginStart="24dp"
+                android:layout_toStartOf="@+id/snackbar_action"
+                android:textColor="?colorOnSurfaceInverse"
+                android:text="Warning" />
+
+            <TextView
+                android:id="@+id/snackbar_action"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:paddingLeft="24dp"
+                android:paddingTop="16dp"
+                android:paddingRight="24dp"
+                android:paddingBottom="16dp"
+                android:textAllCaps="true"
+                android:textColor="?colorOnSurfaceInverse"
+                android:textStyle="bold"
+                android:text="@string/action_fix" />
+        </RelativeLayout>
 
         <com.cheogram.android.ContextMenuRecyclerView
             android:id="@+id/list"
@@ -12,6 +55,8 @@
             android:layout_height="match_parent"
             android:scrollbars="vertical" />
 
+        </LinearLayout>
+
         <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
             android:id="@+id/fab"
             android:layout_width="wrap_content"