mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
hide relays from contacts (unpublish relays) (#4289)
* show 'remove relay' items in red * show concrete meaning of 'default' or 'main' * prepare for showing 'unpublished' state * rework 'remove relay' dialog * fix RPC building doc and remove temp. file * add hint to be shown below relay list * adapt to new core api * use listTransportsEx() * use rpc.setTransportUnpublished() * keep hidden * tweak remove dialog in case the relay is already hidden * adapt to chat.delta.rpc.types.TransportListEntry classname * remove outdated autogenerated file * update CHANGELOG * simplify deletion * make spotless happy * change button order so hide/delete are not together usually; this matches also more the gist of positive/negative/neutral * Update src/main/res/values/strings.xml Co-authored-by: Hocuri <hocuri@gmx.de> * the dialog wording fits better when already hidden now * move similar strings together, make translation easier * actions are 'Title Case', however, this usually applies to nouns, verbs, adjectives, first and last word only, not to prepositions as 'from' --------- Co-authored-by: Hocuri <hocuri@gmx.de>
This commit is contained in:
@@ -289,6 +289,7 @@ public class Rpc {
|
||||
* from a server encoded in a QR code.
|
||||
* - [Self::list_transports()] to get a list of all configured transports.
|
||||
* - [Self::delete_transport()] to remove a transport.
|
||||
* - [Self::set_transport_unpublished()] to set whether contacts see this transport.
|
||||
*/
|
||||
public void addOrUpdateTransport(Integer accountId, EnteredLoginParam param) throws RpcException {
|
||||
transport.call("add_or_update_transport", mapper.valueToTree(accountId), mapper.valueToTree(param));
|
||||
@@ -312,11 +313,22 @@ public class Rpc {
|
||||
* Returns the list of all email accounts that are used as a transport in the current profile.
|
||||
* Use [Self::add_or_update_transport()] to add or change a transport
|
||||
* and [Self::delete_transport()] to delete a transport.
|
||||
* Use [Self::list_transports_ex()] to additionally query
|
||||
* whether the transports are marked as 'unpublished'.
|
||||
*/
|
||||
public java.util.List<EnteredLoginParam> listTransports(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<EnteredLoginParam>>(){}, "list_transports", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all email accounts that are used as a transport in the current profile.
|
||||
* Use [Self::add_or_update_transport()] to add or change a transport
|
||||
* and [Self::delete_transport()] to delete a transport.
|
||||
*/
|
||||
public java.util.List<TransportListEntry> listTransportsEx(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<TransportListEntry>>(){}, "list_transports_ex", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the transport with the specified email address
|
||||
* (i.e. [EnteredLoginParam::addr]).
|
||||
@@ -325,6 +337,22 @@ public class Rpc {
|
||||
transport.call("delete_transport", mapper.valueToTree(accountId), mapper.valueToTree(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Change whether the transport is unpublished.
|
||||
* <p>
|
||||
* Unpublished transports are not advertised to contacts,
|
||||
* and self-sent messages are not sent there,
|
||||
* so that we don't cause extra messages to the corresponding inbox,
|
||||
* but can still receive messages from contacts who don't know our new transport addresses yet.
|
||||
* <p>
|
||||
* The default is false, but when the user updates from a version that didn't have this flag,
|
||||
* existing secondary transports are set to unpublished,
|
||||
* so that an existing transport address doesn't suddenly get spammed with a lot of messages.
|
||||
*/
|
||||
public void setTransportUnpublished(Integer accountId, String addr, Boolean unpublished) throws RpcException {
|
||||
transport.call("set_transport_unpublished", mapper.valueToTree(accountId), mapper.valueToTree(addr), mapper.valueToTree(unpublished));
|
||||
}
|
||||
|
||||
/** Signal an ongoing process to stop. */
|
||||
public void stopOngoingProcess(Integer accountId) throws RpcException {
|
||||
transport.call("stop_ongoing_process", mapper.valueToTree(accountId));
|
||||
@@ -410,14 +438,6 @@ public class Rpc {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "estimate_auto_deletion_count", mapper.valueToTree(accountId), mapper.valueToTree(fromServer), mapper.valueToTree(seconds));
|
||||
}
|
||||
|
||||
public String initiateAutocryptKeyTransfer(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "initiate_autocrypt_key_transfer", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
public void continueAutocryptKeyTransfer(Integer accountId, Integer messageId, String setupCode) throws RpcException {
|
||||
transport.call("continue_autocrypt_key_transfer", mapper.valueToTree(accountId), mapper.valueToTree(messageId), mapper.valueToTree(setupCode));
|
||||
}
|
||||
|
||||
public java.util.List<Integer> getChatlistEntries(Integer accountId, Integer listFlags, String queryString, Integer queryContactId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<Integer>>(){}, "get_chatlist_entries", mapper.valueToTree(accountId), mapper.valueToTree(listFlags), mapper.valueToTree(queryString), mapper.valueToTree(queryContactId));
|
||||
}
|
||||
|
||||
@@ -387,6 +387,8 @@ public abstract class EventType {
|
||||
public static class IncomingCallAccepted extends EventType {
|
||||
/** ID of the chat which the message belongs to. */
|
||||
public Integer chat_id;
|
||||
/** The call was accepted from this device (process). */
|
||||
public Boolean from_this_device;
|
||||
/** ID of the info message referring to the call. */
|
||||
public Integer msg_id;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ public class Message {
|
||||
public Boolean isEdited;
|
||||
public Boolean isForwarded;
|
||||
public Boolean isInfo;
|
||||
public Boolean isSetupmessage;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer originalMsgId;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
@@ -47,8 +46,6 @@ public class Message {
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer savedMessageId;
|
||||
public Contact sender;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String setupCodeBegin;
|
||||
/**
|
||||
* True if the message was correctly encrypted&signed, false otherwise. Historically, UIs showed a small padlock on the message then.
|
||||
* <p>
|
||||
|
||||
@@ -42,7 +42,6 @@ public abstract class MessageLoadResult {
|
||||
public Boolean isEdited;
|
||||
public Boolean isForwarded;
|
||||
public Boolean isInfo;
|
||||
public Boolean isSetupmessage;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer originalMsgId;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
@@ -57,8 +56,6 @@ public abstract class MessageLoadResult {
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer savedMessageId;
|
||||
public Contact sender;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String setupCodeBegin;
|
||||
/**
|
||||
* True if the message was correctly encrypted&signed, false otherwise. Historically, UIs showed a small padlock on the message then.
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
public class TransportListEntry {
|
||||
/** Whether this transport is set to 'unpublished'. See `set_transport_unpublished` / `setTransportUnpublished` for details. */
|
||||
public Boolean isUnpublished;
|
||||
/** The login data entered by the user. */
|
||||
public EnteredLoginParam param;
|
||||
}
|
||||
@@ -171,8 +171,6 @@ public class DcContext {
|
||||
|
||||
public native String getConnectivityHtml();
|
||||
|
||||
public native String initiateKeyTransfer();
|
||||
|
||||
public native void imex(int what, String dir);
|
||||
|
||||
public native String imexHasBackup(String dir);
|
||||
|
||||
@@ -25,7 +25,6 @@ public class DcMsg {
|
||||
public static final int DC_INFO_GROUP_IMAGE_CHANGED = 3;
|
||||
public static final int DC_INFO_MEMBER_ADDED_TO_GROUP = 4;
|
||||
public static final int DC_INFO_MEMBER_REMOVED_FROM_GROUP = 5;
|
||||
public static final int DC_INFO_AUTOCRYPT_SETUP_MESSAGE = 6;
|
||||
public static final int DC_INFO_SECURE_JOIN_MESSAGE = 7;
|
||||
public static final int DC_INFO_LOCATIONSTREAMING_ENABLED = 8;
|
||||
public static final int DC_INFO_LOCATION_ONLY = 9;
|
||||
@@ -187,8 +186,6 @@ public class DcMsg {
|
||||
|
||||
public native boolean hasHtml();
|
||||
|
||||
public native String getSetupCodeBegin();
|
||||
|
||||
public native void setText(String text);
|
||||
|
||||
public native void setFileAndDeduplicate(String file, String name, String filemime);
|
||||
|
||||
@@ -16,7 +16,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.EnteredLoginParam;
|
||||
import chat.delta.rpc.types.TransportListEntry;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
@@ -53,7 +53,7 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
private ActivityResultLauncher<Intent> qrScannerLauncher;
|
||||
|
||||
/** Relay selected for context menu via onRelayLongClick() */
|
||||
private EnteredLoginParam contextMenuRelay = null;
|
||||
private TransportListEntry contextMenuRelay = null;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -162,7 +162,7 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
String finalMainRelayAddr = mainRelayAddr;
|
||||
|
||||
try {
|
||||
List<EnteredLoginParam> relays = rpc.listTransports(accId);
|
||||
List<TransportListEntry> relays = rpc.listTransportsEx(accId);
|
||||
|
||||
Util.runOnMain(() -> adapter.setRelays(relays, finalMainRelayAddr));
|
||||
} catch (RpcException e) {
|
||||
@@ -173,12 +173,12 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelayClick(EnteredLoginParam relay) {
|
||||
if (relay.addr != null && !relay.addr.equals(adapter.getMainRelay())) {
|
||||
public void onRelayClick(TransportListEntry relay) {
|
||||
if (relay.param.addr != null && !relay.param.addr.equals(adapter.getMainRelay())) {
|
||||
Util.runOnAnyBackgroundThread(
|
||||
() -> {
|
||||
try {
|
||||
rpc.setConfig(accId, DcHelper.CONFIG_CONFIGURED_ADDRESS, relay.addr);
|
||||
rpc.setConfig(accId, DcHelper.CONFIG_CONFIGURED_ADDRESS, relay.param.addr);
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "RPC.setConfig() failed", e);
|
||||
}
|
||||
@@ -189,7 +189,7 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelayLongClick(View view, EnteredLoginParam relay) {
|
||||
public void onRelayLongClick(View view, TransportListEntry relay) {
|
||||
contextMenuRelay = relay;
|
||||
registerForContextMenu(view);
|
||||
openContextMenu(view);
|
||||
@@ -201,8 +201,10 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
getMenuInflater().inflate(R.menu.relay_item_context, menu);
|
||||
|
||||
boolean nonNullAddr = contextMenuRelay != null && contextMenuRelay.addr != null;
|
||||
boolean isMain = nonNullAddr && contextMenuRelay.addr.equals(adapter.getMainRelay());
|
||||
boolean nonNullAddr = contextMenuRelay != null && contextMenuRelay.param.addr != null;
|
||||
boolean isMain = nonNullAddr && contextMenuRelay.param.addr.equals(adapter.getMainRelay());
|
||||
|
||||
Util.redMenuItem(menu, R.id.menu_delete_relay);
|
||||
menu.findItem(R.id.menu_delete_relay).setVisible(!isMain);
|
||||
}
|
||||
|
||||
@@ -230,28 +232,40 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
private void onRelayEdit(EnteredLoginParam relay) {
|
||||
private void onRelayEdit(TransportListEntry relay) {
|
||||
Intent intent = new Intent(this, EditRelayActivity.class);
|
||||
intent.putExtra(EditRelayActivity.EXTRA_ADDR, relay.addr);
|
||||
intent.putExtra(EditRelayActivity.EXTRA_ADDR, relay.param.addr);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void onRelayDelete(EnteredLoginParam relay) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.remove_transport)
|
||||
.setMessage(getString(R.string.confirm_remove_transport, relay.addr))
|
||||
.setPositiveButton(
|
||||
R.string.ok,
|
||||
(dialog, which) -> {
|
||||
try {
|
||||
rpc.deleteTransport(accId, relay.addr);
|
||||
loadRelays();
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "RPC.deleteTransport() failed", e);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
private void onRelayDelete(TransportListEntry relay) {
|
||||
AlertDialog dialog =
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.remove_transport)
|
||||
.setMessage(getString(R.string.confirm_remove_or_hide_transport_x, relay.param.addr))
|
||||
.setPositiveButton(
|
||||
R.string.remove_transport,
|
||||
(d, which) -> {
|
||||
try {
|
||||
rpc.deleteTransport(accId, relay.param.addr);
|
||||
loadRelays();
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "RPC.deleteTransport() failed", e);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setNeutralButton(
|
||||
R.string.hide_from_contacts,
|
||||
(d, which) -> {
|
||||
try {
|
||||
rpc.setTransportUnpublished(accId, relay.param.addr, true);
|
||||
loadRelays();
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "cannot unpublish relay: ", e);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
Util.redPositiveButton(dialog);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.relay;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -8,21 +9,21 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import chat.delta.rpc.types.EnteredLoginParam;
|
||||
import chat.delta.rpc.types.TransportListEntry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.RelayViewHolder> {
|
||||
|
||||
private List<EnteredLoginParam> relays = new ArrayList<>();
|
||||
private List<TransportListEntry> relays = new ArrayList<>();
|
||||
private final OnRelayClickListener listener;
|
||||
private String mainRelayAddr;
|
||||
|
||||
public interface OnRelayClickListener {
|
||||
void onRelayClick(EnteredLoginParam relay);
|
||||
void onRelayClick(TransportListEntry relay);
|
||||
|
||||
void onRelayLongClick(View view, EnteredLoginParam relay);
|
||||
void onRelayLongClick(View view, TransportListEntry relay);
|
||||
}
|
||||
|
||||
public RelayListAdapter(OnRelayClickListener listener) {
|
||||
@@ -33,7 +34,7 @@ public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.Rela
|
||||
return mainRelayAddr;
|
||||
}
|
||||
|
||||
public void setRelays(@Nullable List<EnteredLoginParam> relays, String mainRelayAddr) {
|
||||
public void setRelays(@Nullable List<TransportListEntry> relays, String mainRelayAddr) {
|
||||
this.relays = relays != null ? relays : new ArrayList<>();
|
||||
this.mainRelayAddr = mainRelayAddr;
|
||||
notifyDataSetChanged();
|
||||
@@ -49,8 +50,8 @@ public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.Rela
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RelayViewHolder holder, int position) {
|
||||
EnteredLoginParam relay = relays.get(position);
|
||||
boolean isMain = relay.addr != null && relay.addr.equals(mainRelayAddr);
|
||||
TransportListEntry relay = relays.get(position);
|
||||
boolean isMain = relay.param.addr != null && relay.param.addr.equals(mainRelayAddr);
|
||||
holder.bind(relay, isMain, listener);
|
||||
}
|
||||
|
||||
@@ -71,10 +72,20 @@ public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.Rela
|
||||
mainIndicator = itemView.findViewById(R.id.main_indicator);
|
||||
}
|
||||
|
||||
public void bind(EnteredLoginParam relay, boolean isMain, OnRelayClickListener listener) {
|
||||
String[] parts = relay.addr.split("@");
|
||||
public void bind(TransportListEntry relay, boolean isMain, OnRelayClickListener listener) {
|
||||
Context context = itemView.getContext();
|
||||
String[] parts = relay.param.addr.split("@");
|
||||
titleText.setText(parts.length == 2 ? parts[1] : parts[0]);
|
||||
subtitleText.setText(parts.length == 2 ? parts[0] : "");
|
||||
|
||||
String subtitle = parts.length == 2 ? parts[0] : "";
|
||||
if (isMain) {
|
||||
subtitle += " · " + context.getString(R.string.used_for_sending);
|
||||
}
|
||||
if (relay.isUnpublished) {
|
||||
subtitle += " · " + context.getString(R.string.hidden_from_contacts);
|
||||
}
|
||||
subtitleText.setText(subtitle);
|
||||
|
||||
mainIndicator.setVisibility(isMain ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
itemView.setOnClickListener(
|
||||
|
||||
Reference in New Issue
Block a user