From 57243b50aa62b6f0d608da177cfdc4b3f7220469 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 24 Nov 2025 18:49:45 +0000
Subject: [PATCH] Add TransportListActivity to list, edit, and remove
transports
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
---
src/main/AndroidManifest.xml | 4 +
.../securesms/EditTransportActivity.java | 13 +-
.../securesms/TransportListActivity.java | 123 ++++++++++++++++++
.../securesms/TransportListAdapter.java | 90 +++++++++++++
.../AdvancedPreferenceFragment.java | 10 +-
.../res/layout/activity_transport_list.xml | 29 +++++
src/main/res/layout/transport_list_item.xml | 49 +++++++
7 files changed, 312 insertions(+), 6 deletions(-)
create mode 100644 src/main/java/org/thoughtcrime/securesms/TransportListActivity.java
create mode 100644 src/main/java/org/thoughtcrime/securesms/TransportListAdapter.java
create mode 100644 src/main/res/layout/activity_transport_list.xml
create mode 100644 src/main/res/layout/transport_list_item.xml
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index c6a3ba9ba..7d9c32124 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -240,6 +240,10 @@
android:exported="true">
+
+
relays = rpc.listTransports(accId);
- if (!relays.isEmpty()) config = relays.get(0);
+ if (transportAddr != null) {
+ // Find the transport with the specified address
+ for (EnteredLoginParam transport : relays) {
+ if (transportAddr.equals(transport.addr)) {
+ config = transport;
+ break;
+ }
+ }
+ } else if (!relays.isEmpty()) {
+ config = relays.get(0);
+ }
} catch (RpcException ignored) {}
ActionBar actionBar = getSupportActionBar();
diff --git a/src/main/java/org/thoughtcrime/securesms/TransportListActivity.java b/src/main/java/org/thoughtcrime/securesms/TransportListActivity.java
new file mode 100644
index 000000000..895336155
--- /dev/null
+++ b/src/main/java/org/thoughtcrime/securesms/TransportListActivity.java
@@ -0,0 +1,123 @@
+package org.thoughtcrime.securesms;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
+import org.thoughtcrime.securesms.connect.DcHelper;
+import org.thoughtcrime.securesms.util.Util;
+
+import java.util.List;
+
+import chat.delta.rpc.Rpc;
+import chat.delta.rpc.RpcException;
+import chat.delta.rpc.types.EnteredLoginParam;
+
+public class TransportListActivity extends BaseActionBarActivity
+ implements TransportListAdapter.OnTransportClickListener {
+
+ public static final String EXTRA_TRANSPORT_ADDR = "transport_addr";
+
+ private RecyclerView recyclerView;
+ private TransportListAdapter adapter;
+ private FloatingActionButton fabAdd;
+ private Rpc rpc;
+ private int accId;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_transport_list);
+
+ rpc = DcHelper.getRpc(this);
+ accId = DcHelper.getContext(this).getAccountId();
+
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setTitle(R.string.transports);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setElevation(0);
+ }
+
+ recyclerView = findViewById(R.id.transport_list);
+ fabAdd = findViewById(R.id.fab_add_transport);
+
+ adapter = new TransportListAdapter(this);
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ recyclerView.setAdapter(adapter);
+
+ fabAdd.setOnClickListener(v -> openAddTransport());
+
+ loadTransports();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ loadTransports();
+ }
+
+ private void loadTransports() {
+ Util.runOnBackground(() -> {
+ try {
+ List transports = rpc.listTransports(accId);
+ Util.runOnMain(() -> adapter.setTransports(transports));
+ } catch (RpcException e) {
+ Util.runOnMain(() -> adapter.setTransports(null));
+ }
+ });
+ }
+
+ private void openAddTransport() {
+ Intent intent = new Intent(this, EditTransportActivity.class);
+ startActivity(intent);
+ }
+
+ @Override
+ public void onTransportClick(EnteredLoginParam transport) {
+ Intent intent = new Intent(this, EditTransportActivity.class);
+ intent.putExtra(EXTRA_TRANSPORT_ADDR, transport.addr);
+ startActivity(intent);
+ }
+
+ @Override
+ public void onTransportDelete(EnteredLoginParam transport) {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.remove_transport)
+ .setMessage(getString(R.string.confirm_remove_transport, transport.addr))
+ .setPositiveButton(R.string.ok, (dialog, which) -> deleteTransport(transport))
+ .setNegativeButton(R.string.cancel, null)
+ .show();
+ }
+
+ private void deleteTransport(EnteredLoginParam transport) {
+ Util.runOnBackground(() -> {
+ try {
+ rpc.deleteTransport(accId, transport.addr);
+ Util.runOnMain(this::loadTransports);
+ } catch (RpcException e) {
+ Util.runOnMain(() -> {
+ new AlertDialog.Builder(this)
+ .setMessage(getString(R.string.error) + ": " + e.getMessage())
+ .setPositiveButton(R.string.ok, null)
+ .show();
+ });
+ }
+ });
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/src/main/java/org/thoughtcrime/securesms/TransportListAdapter.java b/src/main/java/org/thoughtcrime/securesms/TransportListAdapter.java
new file mode 100644
index 000000000..eb5dc6bd8
--- /dev/null
+++ b/src/main/java/org/thoughtcrime/securesms/TransportListAdapter.java
@@ -0,0 +1,90 @@
+package org.thoughtcrime.securesms;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import chat.delta.rpc.types.EnteredLoginParam;
+
+public class TransportListAdapter extends RecyclerView.Adapter {
+
+ private List transports = new ArrayList<>();
+ private final OnTransportClickListener listener;
+
+ public interface OnTransportClickListener {
+ void onTransportClick(EnteredLoginParam transport);
+ void onTransportDelete(EnteredLoginParam transport);
+ }
+
+ public TransportListAdapter(OnTransportClickListener listener) {
+ this.listener = listener;
+ }
+
+ public void setTransports(List transports) {
+ this.transports = transports != null ? transports : new ArrayList<>();
+ notifyDataSetChanged();
+ }
+
+ @NonNull
+ @Override
+ public TransportViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.transport_list_item, parent, false);
+ return new TransportViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull TransportViewHolder holder, int position) {
+ EnteredLoginParam transport = transports.get(position);
+ holder.bind(transport, listener);
+ }
+
+ @Override
+ public int getItemCount() {
+ return transports.size();
+ }
+
+ static class TransportViewHolder extends RecyclerView.ViewHolder {
+ private final TextView emailText;
+ private final TextView serverText;
+ private final ImageView deleteButton;
+
+ public TransportViewHolder(@NonNull View itemView) {
+ super(itemView);
+ emailText = itemView.findViewById(R.id.transport_email);
+ serverText = itemView.findViewById(R.id.transport_server);
+ deleteButton = itemView.findViewById(R.id.delete_button);
+ }
+
+ public void bind(EnteredLoginParam transport, OnTransportClickListener listener) {
+ emailText.setText(transport.addr);
+
+ String serverInfo = "";
+ if (transport.imapServer != null && !transport.imapServer.isEmpty()) {
+ serverInfo = transport.imapServer;
+ }
+ serverText.setText(serverInfo);
+ serverText.setVisibility(serverInfo.isEmpty() ? View.GONE : View.VISIBLE);
+
+ itemView.setOnClickListener(v -> {
+ if (listener != null) {
+ listener.onTransportClick(transport);
+ }
+ });
+
+ deleteButton.setOnClickListener(v -> {
+ if (listener != null) {
+ listener.onTransportDelete(transport);
+ }
+ });
+ }
+ }
+}
diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
index 2dba9d074..e33524966 100644
--- a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
@@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.LogViewActivity;
import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.EditTransportActivity;
+import org.thoughtcrime.securesms.TransportListActivity;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
@@ -166,7 +166,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
passwordAndAccount.setOnPreferenceClickListener(((preference) -> {
boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.edit_transport), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT);
if (!result) {
- openRegistrationActivity();
+ openTransportListActivity();
}
return true;
}));
@@ -203,7 +203,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT) {
- openRegistrationActivity();
+ openTransportListActivity();
}
}
@@ -270,8 +270,8 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
}
}
- private void openRegistrationActivity() {
- Intent intent = new Intent(requireActivity(), EditTransportActivity.class);
+ private void openTransportListActivity() {
+ Intent intent = new Intent(requireActivity(), TransportListActivity.class);
startActivity(intent);
}
diff --git a/src/main/res/layout/activity_transport_list.xml b/src/main/res/layout/activity_transport_list.xml
new file mode 100644
index 000000000..abe8a8500
--- /dev/null
+++ b/src/main/res/layout/activity_transport_list.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/res/layout/transport_list_item.xml b/src/main/res/layout/transport_list_item.xml
new file mode 100644
index 000000000..8ab42f2dd
--- /dev/null
+++ b/src/main/res/layout/transport_list_item.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+