refactor muc search to use http

Daniel Gultsch created

Change summary

build.gradle                                                                    |   2 
src/main/java/eu/siacs/conversations/Config.java                                |   2 
src/main/java/eu/siacs/conversations/entities/ChannelSearchResult.java          |  35 
src/main/java/eu/siacs/conversations/http/services/MuclumbusService.java        |  85 
src/main/java/eu/siacs/conversations/services/AvatarService.java                |  18 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java        | 105 
src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java           |  54 
src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java |  14 
src/main/res/values/strings.xml                                                 |   2 
9 files changed, 210 insertions(+), 107 deletions(-)

Detailed changes

build.gradle 🔗

@@ -64,6 +64,8 @@ dependencies {
     implementation 'org.conscrypt:conscrypt-android:1.3.0'
     implementation 'me.drakeet.support:toastcompat:1.1.0'
     implementation "com.leinardi.android:speed-dial:2.0.1"
+    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
+    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
     quicksyImplementation 'io.michaelrocks:libphonenumber-android:8.10.1'
 }
 

src/main/java/eu/siacs/conversations/Config.java 🔗

@@ -41,7 +41,7 @@ public final class Config {
     public static final String MAGIC_CREATE_DOMAIN = "conversations.im";
     public static final String QUICKSY_DOMAIN = "quicksy.im";
 
-    public static final Jid CHANNEL_DISCOVERY = Jid.of("rodrigo.de.mucobedo@dreckshal.de");
+    public static final String CHANNEL_DISCOVERY = "https://search.jabbercat.org";
 
     public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox
 

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

@@ -1,35 +0,0 @@
-package eu.siacs.conversations.entities;
-
-import eu.siacs.conversations.services.AvatarService;
-import eu.siacs.conversations.utils.UIHelper;
-import rocks.xmpp.addr.Jid;
-
-public class ChannelSearchResult implements AvatarService.Avatarable {
-
-    private final String name;
-    private final String description;
-    private final Jid room;
-
-    public String getName() {
-        return name;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public Jid getRoom() {
-        return room;
-    }
-
-    public ChannelSearchResult(String name, String description, Jid room) {
-        this.name = name;
-        this.description = description;
-        this.room = room;
-    }
-
-    @Override
-    public int getAvatarBackgroundColor() {
-        return UIHelper.getColorForName(room != null ? room.asBareJid().toEscapedString() : getName());
-    }
-}

src/main/java/eu/siacs/conversations/http/services/MuclumbusService.java 🔗

@@ -0,0 +1,85 @@
+package eu.siacs.conversations.http.services;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import eu.siacs.conversations.services.AvatarService;
+import eu.siacs.conversations.utils.UIHelper;
+import retrofit2.Call;
+import retrofit2.http.Body;
+import retrofit2.http.GET;
+import retrofit2.http.POST;
+import retrofit2.http.Query;
+import rocks.xmpp.addr.Jid;
+
+public interface MuclumbusService {
+
+    @GET("/api/1.0/rooms/unsafe")
+    Call<Rooms> getRooms(@Query("p") int page);
+
+    @POST("/api/1.0/search")
+    Call<SearchResult> search(@Body SearchRequest searchRequest);
+
+    class Rooms {
+        int page;
+        int total;
+        int pages;
+        public List<Room> items;
+    }
+
+    class Room implements AvatarService.Avatarable {
+
+        public String address;
+        public int nusers;
+        public boolean is_open;
+        public String anonymity_mode;
+        public String name;
+        public String description;
+        public String language;
+
+        public String getName() {
+            return name;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public Jid getRoom() {
+            try {
+                return Jid.of(address);
+            } catch (IllegalArgumentException e) {
+                return null;
+            }
+        }
+
+        @Override
+        public int getAvatarBackgroundColor() {
+            Jid room = getRoom();
+            return UIHelper.getColorForName(room != null ? room.asBareJid().toEscapedString() : name);
+        }
+    }
+
+    class SearchRequest {
+
+        public Set<String> keywords;
+
+        public SearchRequest(String keyword) {
+            this.keywords = Collections.singleton(keyword);
+        }
+    }
+
+    class SearchResult {
+
+        public Result result;
+
+    }
+
+    class Result {
+
+        public List<Room> items;
+
+    }
+
+}

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

@@ -3,7 +3,6 @@ package eu.siacs.conversations.services;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
@@ -14,7 +13,6 @@ import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
 import android.support.annotation.Nullable;
 import android.support.v4.content.res.ResourcesCompat;
 import android.text.TextUtils;
@@ -33,17 +31,16 @@ import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Bookmark;
-import eu.siacs.conversations.entities.ChannelSearchResult;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Conversational;
 import eu.siacs.conversations.entities.ListItem;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.MucOptions;
+import eu.siacs.conversations.http.services.MuclumbusService;
 import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
 import eu.siacs.conversations.xmpp.XmppConnection;
-import eu.siacs.conversations.xmpp.pep.Avatar;
 import rocks.xmpp.addr.Jid;
 
 public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
@@ -83,15 +80,20 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
 			return get((ListItem) avatarable, size, cachedOnly);
 		} else if (avatarable instanceof MucOptions.User) {
 			return get((MucOptions.User) avatarable, size, cachedOnly);
-		} else if (avatarable instanceof ChannelSearchResult) {
-			return get((ChannelSearchResult) avatarable, size, cachedOnly);
+		} else if (avatarable instanceof MuclumbusService.Room) {
+			return get((MuclumbusService.Room) avatarable, size, cachedOnly);
 		}
 		throw new AssertionError("AvatarService does not know how to generate avatar from "+avatarable.getClass().getName());
 
 	}
 
-	private Bitmap get(final ChannelSearchResult result, final int size, boolean cacheOnly) {
-		return get(result.getName(), result.getRoom().asBareJid().toEscapedString(), size, cacheOnly);
+	private Bitmap get(final MuclumbusService.Room result, final int size, boolean cacheOnly) {
+		final Jid room = result.getRoom();
+		Conversation conversation = room != null ? mXmppConnectionService.findFirstMuc(room) : null;
+		if (conversation != null) {
+			return get(conversation,size,cacheOnly);
+		}
+		return get(result.getName(), room != null ? room.asBareJid().toEscapedString() : result.getName(), size, cacheOnly);
 	}
 
 	private Bitmap get(final Contact contact, final int size, boolean cachedOnly) {

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

@@ -49,7 +49,6 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection;
 
 import java.io.File;
 import java.net.URL;
-import java.nio.channels.Channel;
 import java.security.SecureRandom;
 import java.security.Security;
 import java.security.cert.CertificateException;
@@ -69,6 +68,9 @@ import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -85,7 +87,6 @@ import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Blockable;
 import eu.siacs.conversations.entities.Bookmark;
-import eu.siacs.conversations.entities.ChannelSearchResult;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Conversational;
@@ -102,6 +103,7 @@ import eu.siacs.conversations.generator.MessageGenerator;
 import eu.siacs.conversations.generator.PresenceGenerator;
 import eu.siacs.conversations.http.HttpConnectionManager;
 import eu.siacs.conversations.http.CustomURLStreamHandlerFactory;
+import eu.siacs.conversations.http.services.MuclumbusService;
 import eu.siacs.conversations.parser.AbstractParser;
 import eu.siacs.conversations.parser.IqParser;
 import eu.siacs.conversations.parser.MessageParser;
@@ -114,7 +116,6 @@ import eu.siacs.conversations.ui.UiCallback;
 import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
 import eu.siacs.conversations.ui.interfaces.OnMediaLoaded;
 import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable;
-import eu.siacs.conversations.utils.AccountUtils;
 import eu.siacs.conversations.utils.Compatibility;
 import eu.siacs.conversations.utils.ConversationsFileObserver;
 import eu.siacs.conversations.utils.CryptoHelper;
@@ -154,6 +155,11 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
 import me.leolin.shortcutbadger.ShortcutBadger;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
 import rocks.xmpp.addr.Jid;
 
 public class XmppConnectionService extends Service {
@@ -236,6 +242,7 @@ public class XmppConnectionService extends Service {
     private AvatarService mAvatarService = new AvatarService(this);
     private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
     private PushManagementService mPushManagementService = new PushManagementService(this);
+    private MuclumbusService muclumbusService;
     private QuickConversationsService mQuickConversationsService = new QuickConversationsService(this);
     private final ConversationsFileObserver fileObserver = new ConversationsFileObserver(
             Environment.getExternalStorageDirectory().getAbsolutePath()
@@ -798,56 +805,61 @@ public class XmppConnectionService extends Service {
         return pingNow;
     }
 
-    public void discoverChannels(String query, OnChannelSearchResultsFound listener) {
-        IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
-        packet.setTo(Config.CHANNEL_DISCOVERY);
-        Element search = packet.addChild("search","https://xmlns.zombofant.net/muclumbus/search/1.0");
-        search.addChild("set","http://jabber.org/protocol/rsm").addChild("max").setContent("100");
-        Bundle bundle = new Bundle();
-        if (!TextUtils.isEmpty(query)) {
-            bundle.putString("q",query);
-        }
-        Data data = Data.create("https://xmlns.zombofant.net/muclumbus/search/1.0#params", bundle);
-        search.addChild(data);
-        final Account account = AccountUtils.getFirstEnabled(this);
-        if (account == null) {
-            return;
+    public void discoverChannels(String query, OnChannelSearchResultsFound onChannelSearchResultsFound) {
+        Log.d(Config.LOGTAG,"discover channels. query="+query);
+        if (query == null || query.trim().isEmpty()) {
+            discoverChannelsInternal(onChannelSearchResultsFound);
+        } else {
+            discoverChannelsInternal(query, onChannelSearchResultsFound);
         }
-        sendIqPacket(account, packet, new OnIqPacketReceived() {
-            @Override
-            public void onIqPacketReceived(Account account, IqPacket response) {
-                ArrayList<ChannelSearchResult> searchResults = new ArrayList<>();
-                if (response.getType() == IqPacket.TYPE.RESULT) {
-                    Element result = response.findChild("result","https://xmlns.zombofant.net/muclumbus/search/1.0");
-                    if (result != null) {
-                        for(Element child : result.getChildren()) {
-                            if ("item".equals(child.getName())) {
-                                String name = child.findChildContent("name");
-                                String description = child.findChildContent("description");
-                                Jid room = child.getAttributeAsJid("address");
-                                if (room != null) {
-                                    searchResults.add(new ChannelSearchResult(name,description,room));
-                                } else {
-                                    Log.d(Config.LOGTAG,"skipping because room was null");
-                                }
-                            }
-                        }
-                    } else {
-                        Log.d(Config.LOGTAG,"result was null");
+    }
+
+    private void discoverChannelsInternal(OnChannelSearchResultsFound listener) {
+        Call<MuclumbusService.Rooms> call = muclumbusService.getRooms(1);
+        try {
+            call.enqueue(new Callback<MuclumbusService.Rooms>() {
+                @Override
+                public void onResponse(Call<MuclumbusService.Rooms> call, Response<MuclumbusService.Rooms> response) {
+                    final MuclumbusService.Rooms body = response.body();
+                    if (body == null) {
+                        return;
                     }
-                } else {
-                    Log.d(Config.LOGTAG,response.toString());
+                    listener.onChannelSearchResultsFound(body.items);
                 }
-                if (listener != null) {
-                    listener.onChannelSearchResultsFound(searchResults);
+
+                @Override
+                public void onFailure(Call<MuclumbusService.Rooms> call, Throwable throwable) {
+
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void discoverChannelsInternal(String query, OnChannelSearchResultsFound listener) {
+        Call<MuclumbusService.SearchResult> searchResultCall = muclumbusService.search(new MuclumbusService.SearchRequest(query));
+
+        searchResultCall.enqueue(new Callback<MuclumbusService.SearchResult>() {
+            @Override
+            public void onResponse(Call<MuclumbusService.SearchResult> call, Response<MuclumbusService.SearchResult> response) {
+                System.out.println(response.message());
+                MuclumbusService.SearchResult body = response.body();
+                if (body == null) {
+                    return;
                 }
+                listener.onChannelSearchResultsFound(body.result.items);
+            }
 
+            @Override
+            public void onFailure(Call<MuclumbusService.SearchResult> call, Throwable throwable) {
+                throwable.printStackTrace();
             }
         });
     }
 
     public interface OnChannelSearchResultsFound {
-        void onChannelSearchResultsFound(List<ChannelSearchResult> results);
+        void onChannelSearchResultsFound(List<MuclumbusService.Room> results);
     }
 
     public boolean isDataSaverDisabled() {
@@ -1118,6 +1130,13 @@ public class XmppConnectionService extends Service {
         }
         mForceDuringOnCreate.set(false);
         toggleForegroundService();
+
+        Retrofit retrofit = new Retrofit.Builder()
+                .baseUrl(Config.CHANNEL_DISCOVERY)
+                .addConverterFactory(GsonConverterFactory.create())
+                .callbackExecutor(Executors.newSingleThreadExecutor())
+                .build();
+        muclumbusService = retrofit.create(MuclumbusService.class);
     }
 
     private void checkForDeletedFiles() {

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

@@ -2,13 +2,12 @@ package eu.siacs.conversations.ui;
 
 import android.app.AlertDialog;
 import android.content.Context;
-import android.content.DialogInterface;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.databinding.DataBindingUtil;
 import android.os.Bundle;
 import android.support.v7.widget.Toolbar;
 import android.text.Html;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -17,19 +16,18 @@ import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.TextView;
 
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
-import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.databinding.ActivityChannelDiscoveryBinding;
 import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.entities.ChannelSearchResult;
 import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.http.services.MuclumbusService;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.ui.adapter.ChannelSearchResultAdapter;
+import eu.siacs.conversations.ui.util.PendingItem;
 import eu.siacs.conversations.ui.util.SoftKeyboardUtils;
 import eu.siacs.conversations.utils.AccountUtils;
 import rocks.xmpp.addr.Jid;
@@ -40,6 +38,9 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
 
     private final ChannelSearchResultAdapter adapter = new ChannelSearchResultAdapter();
 
+    private final PendingItem<String> mInitialSearchValue = new PendingItem<>();
+
+    private MenuItem mMenuSearchView;
     private EditText mSearchEditText;
 
     private boolean optedIn = false;
@@ -52,7 +53,13 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
     @Override
     void onBackendConnected() {
         if (optedIn) {
-            xmppConnectionService.discoverChannels(null, this);
+            String query;
+            if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) {
+                query = mSearchEditText.getText().toString();
+            } else {
+                query = mInitialSearchValue.peek();
+            }
+            xmppConnectionService.discoverChannels(query, this);
         }
     }
 
@@ -65,17 +72,32 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
         binding.list.setAdapter(this.adapter);
         this.adapter.setOnChannelSearchResultSelectedListener(this);
         optedIn = getPreferences().getBoolean(CHANNEL_DISCOVERY_OPT_IN, false);
+
+        final String search = savedInstanceState == null ? null : savedInstanceState.getString("search");
+        if (search != null) {
+            mInitialSearchValue.push(search);
+        }
+
     }
 
     @Override
     public boolean onCreateOptionsMenu(final Menu menu) {
         getMenuInflater().inflate(R.menu.muc_users_activity, menu);
-        final MenuItem menuSearchView = menu.findItem(R.id.action_search);
-        final View mSearchView = menuSearchView.getActionView();
+        mMenuSearchView = menu.findItem(R.id.action_search);
+        final View mSearchView = mMenuSearchView.getActionView();
         mSearchEditText = mSearchView.findViewById(R.id.search_field);
         mSearchEditText.setHint(R.string.search_channels);
+        String initialSearchValue = mInitialSearchValue.pop();
+        if (initialSearchValue != null) {
+            mMenuSearchView.expandActionView();
+            mSearchEditText.append(initialSearchValue);
+            mSearchEditText.requestFocus();
+            if (optedIn) {
+                xmppConnectionService.discoverChannels(initialSearchValue, this);
+            }
+        }
         mSearchEditText.setOnEditorActionListener(this);
-        menuSearchView.setOnActionExpandListener(this);
+        mMenuSearchView.setOnActionExpandListener(this);
         return true;
     }
 
@@ -117,6 +139,14 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
         }
     }
 
+    @Override
+    public void onSaveInstanceState(Bundle savedInstanceState) {
+        if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) {
+            savedInstanceState.putString("search", mSearchEditText != null ? mSearchEditText.getText().toString() : null);
+        }
+        super.onSaveInstanceState(savedInstanceState);
+    }
+
     private void optIn() {
         SharedPreferences preferences = getPreferences();
         preferences.edit().putBoolean(CHANNEL_DISCOVERY_OPT_IN,true).apply();
@@ -135,13 +165,13 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
     }
 
     @Override
-    public void onChannelSearchResultsFound(List<ChannelSearchResult> results) {
+    public void onChannelSearchResultsFound(List<MuclumbusService.Room> results) {
         runOnUiThread(() -> adapter.submitList(results));
 
     }
 
     @Override
-    public void onChannelSearchResult(final ChannelSearchResult result) {
+    public void onChannelSearchResult(final MuclumbusService.Room result) {
         List<String> accounts = AccountUtils.getEnabledAccounts(xmppConnectionService);
         if (accounts.size() == 1) {
             joinChannelSearchResult(accounts.get(0),result);
@@ -157,7 +187,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
 
     }
 
-    public void joinChannelSearchResult(String accountJid, ChannelSearchResult result) {
+    public void joinChannelSearchResult(String accountJid, MuclumbusService.Room result) {
         Account account = xmppConnectionService.findAccountByJid(Jid.of(accountJid));
         final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, result.getRoom(), true, true, true);
         switchToConversation(conversation);

src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java 🔗

@@ -12,21 +12,21 @@ import android.view.ViewGroup;
 
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.databinding.SearchResultItemBinding;
-import eu.siacs.conversations.entities.ChannelSearchResult;
+import eu.siacs.conversations.http.services.MuclumbusService;
 import eu.siacs.conversations.ui.util.AvatarWorkerTask;
 
-public class ChannelSearchResultAdapter extends ListAdapter<ChannelSearchResult, ChannelSearchResultAdapter.ViewHolder> {
+public class ChannelSearchResultAdapter extends ListAdapter<MuclumbusService.Room, ChannelSearchResultAdapter.ViewHolder> {
 
     private OnChannelSearchResultSelected listener;
 
-    private static final DiffUtil.ItemCallback<ChannelSearchResult> DIFF = new DiffUtil.ItemCallback<ChannelSearchResult>() {
+    private static final DiffUtil.ItemCallback<MuclumbusService.Room> DIFF = new DiffUtil.ItemCallback<MuclumbusService.Room>() {
         @Override
-        public boolean areItemsTheSame(@NonNull ChannelSearchResult a, @NonNull ChannelSearchResult b) {
+        public boolean areItemsTheSame(@NonNull MuclumbusService.Room a, @NonNull MuclumbusService.Room b) {
             return false;
         }
 
         @Override
-        public boolean areContentsTheSame(@NonNull ChannelSearchResult a, @NonNull ChannelSearchResult b) {
+        public boolean areContentsTheSame(@NonNull MuclumbusService.Room a, @NonNull MuclumbusService.Room b) {
             return a.equals(b);
         }
     };
@@ -43,7 +43,7 @@ public class ChannelSearchResultAdapter extends ListAdapter<ChannelSearchResult,
 
     @Override
     public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
-        final ChannelSearchResult searchResult = getItem(position);
+        final MuclumbusService.Room searchResult = getItem(position);
         viewHolder.binding.name.setText(searchResult.getName());
         final String description = searchResult.getDescription();
         if (TextUtils.isEmpty(description)) {
@@ -73,6 +73,6 @@ public class ChannelSearchResultAdapter extends ListAdapter<ChannelSearchResult,
     }
 
     public interface OnChannelSearchResultSelected {
-        void onChannelSearchResult(ChannelSearchResult result);
+        void onChannelSearchResult(MuclumbusService.Room result);
     }
 }

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

@@ -860,5 +860,5 @@
     <string name="discover_channels">Discover channels</string>
     <string name="search_channels">Search channels</string>
     <string name="channel_discovery_opt_in_title">Possible privacy violation!</string>
-    <string name="channel_discover_opt_in_message"><![CDATA[Channel discovery uses a third party service called <a href="https://search.jabber.network">search.jabber.network</a>.<br><br>Using this feature will transmit your Jabber ID and search terms to that service. See their <a href="https://search.jabber.network/privacy">Privacy Policy</a> for more information.]]></string>
+    <string name="channel_discover_opt_in_message"><![CDATA[Channel discovery uses a third party service called <a href="https://search.jabbercat.org">search.jabbercat.org</a>.<br><br>Using this feature will transmit your IP address and search terms to that service. See their <a href="https://search.jabbercat.org/privacy">Privacy Policy</a> for more information.]]></string>
 </resources>