Add TransportListActivity to list, edit, and remove transports

Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-11-24 18:49:45 +00:00
parent a42682e1fc
commit 57243b50aa
7 changed files with 312 additions and 6 deletions
+4
View File
@@ -240,6 +240,10 @@
android:exported="true">
</activity>
<activity android:name=".TransportListActivity"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".proxy.ProxySettingsActivity"
android:label="@string/proxy_settings"
android:windowSoftInputMode="stateHidden"
@@ -119,9 +119,20 @@ public class EditTransportActivity extends BaseActionBarActivity implements DcEv
});
EnteredLoginParam config = null;
String transportAddr = getIntent().getStringExtra(TransportListActivity.EXTRA_TRANSPORT_ADDR);
try {
List<EnteredLoginParam> 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();
@@ -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<EnteredLoginParam> 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);
}
}
@@ -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<TransportListAdapter.TransportViewHolder> {
private List<EnteredLoginParam> 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<EnteredLoginParam> 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);
}
});
}
}
}
@@ -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);
}
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="?android:attr/windowBackground">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/transport_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clipToPadding="false"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:scrollbars="vertical"
tools:listitem="@layout/transport_list_item" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_add_transport"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:contentDescription="@string/add_transport"
android:src="@drawable/ic_add_white_24dp" />
</LinearLayout>
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:background="?attr/selectableItemBackground"
android:minHeight="72dp"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/transport_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="16sp"
android:textColor="?android:attr/textColorPrimary"
tools:text="user@example.com" />
<TextView
android:id="@+id/transport_server"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary"
tools:text="imap.example.com" />
</LinearLayout>
<ImageView
android:id="@+id/delete_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/ic_delete_white_24dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/remove_transport"
android:tint="?android:attr/textColorSecondary" />
</LinearLayout>