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 @@ + + + + + + + + + + + + + +