diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 486980fcd..143c3e3ea 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -249,7 +249,7 @@
-
diff --git a/src/main/java/com/b44t/messenger/DcContext.java b/src/main/java/com/b44t/messenger/DcContext.java
index b02b4dc22..003f62dd3 100644
--- a/src/main/java/com/b44t/messenger/DcContext.java
+++ b/src/main/java/com/b44t/messenger/DcContext.java
@@ -56,6 +56,7 @@ public class DcContext {
public final static int DC_QR_BACKUP = 251;
public final static int DC_QR_BACKUP2 = 252;
public final static int DC_QR_WEBRTC = 260;
+ public final static int DC_QR_PROXY = 271;
public final static int DC_QR_ADDR = 320;
public final static int DC_QR_TEXT = 330;
public final static int DC_QR_URL = 332;
diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java b/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java
index 10844d728..c7ac6dc1a 100644
--- a/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java
@@ -20,7 +20,7 @@ import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
import static org.thoughtcrime.securesms.ConversationActivity.STARTING_POSITION_EXTRA;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_ADDRESS;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SERVER_FLAGS;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_ENABLED;
+import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_URL;
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.getDirectSharingChatId;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedTitle;
@@ -64,6 +64,7 @@ import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.connect.DirectShareUtil;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
+import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
import org.thoughtcrime.securesms.qr.QrActivity;
import org.thoughtcrime.securesms.qr.QrCodeHandler;
import org.thoughtcrime.securesms.recipients.Recipient;
@@ -361,7 +362,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
if (!isRelayingMessageContent(this)) {
inflater.inflate(R.menu.text_secure_normal, menu);
menu.findItem(R.id.menu_global_map).setVisible(Prefs.isLocationStreamingEnabled(this));
- menu.findItem(R.id.menu_proxy_settings).setVisible(DcHelper.getInt(this, CONFIG_SOCKS5_ENABLED) == 1);
+ menu.findItem(R.id.menu_proxy_settings).setVisible(!TextUtils.isEmpty(DcHelper.get(this, CONFIG_PROXY_URL)));
}
super.onPrepareOptionsMenu(menu);
diff --git a/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java b/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
index 7eee049ff..3adaf56e7 100644
--- a/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
@@ -48,6 +48,7 @@ import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints;
+import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
import org.thoughtcrime.securesms.qr.RegistrationQrActivity;
import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
import org.thoughtcrime.securesms.util.Prefs;
diff --git a/src/main/java/org/thoughtcrime/securesms/ProxySettingsActivity.java b/src/main/java/org/thoughtcrime/securesms/ProxySettingsActivity.java
deleted file mode 100644
index d88f66073..000000000
--- a/src/main/java/org/thoughtcrime/securesms/ProxySettingsActivity.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.thoughtcrime.securesms;
-
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_ENABLED;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_HOST;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_PASSWORD;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_PORT;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_USER;
-
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.Patterns;
-import android.view.MenuItem;
-import android.view.View;
-
-import androidx.annotation.IdRes;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.widget.SwitchCompat;
-import androidx.constraintlayout.widget.Group;
-
-import com.b44t.messenger.DcContext;
-import com.google.android.material.textfield.TextInputEditText;
-
-import org.thoughtcrime.securesms.connect.DcHelper;
-import org.thoughtcrime.securesms.util.DynamicTheme;
-
-public class ProxySettingsActivity extends BaseActionBarActivity {
-
- private enum VerificationType {
- SERVER,
- PORT,
- }
-
- private final DynamicTheme dynamicTheme = new DynamicTheme();
-
- private SwitchCompat proxySwitch;
- private Group proxyGroup;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- dynamicTheme.onCreate(this);
- setContentView(R.layout.proxy_settings_activity);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setTitle(R.string.proxy_settings);
- actionBar.setDisplayHomeAsUpEnabled(true);
- }
-
- proxyGroup = findViewById(R.id.proxy_group);
-
- proxySwitch = findViewById(R.id.proxy_switch);
- proxySwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
- proxyGroup.setVisibility(isChecked? View.VISIBLE : View.GONE);
- });
- proxySwitch.setChecked(DcHelper.getInt(this, CONFIG_SOCKS5_ENABLED) == 1);
-
- TextInputEditText proxyHostInput = findViewById(R.id.proxy_host_text);
- proxyHostInput.setOnFocusChangeListener((view, focused) -> focusListener(view, focused, VerificationType.SERVER));
- proxyHostInput.setText(DcHelper.get(this, CONFIG_SOCKS5_HOST));
-
- TextInputEditText proxyPortInput = findViewById(R.id.proxy_port_text);
- proxyPortInput.setOnFocusChangeListener((view, focused) -> focusListener(view, focused, VerificationType.PORT));
- proxyPortInput.setText(DcHelper.get(this, CONFIG_SOCKS5_PORT));
-
- TextInputEditText proxyUserInput = findViewById(R.id.proxy_user_text);
- proxyUserInput.setText(DcHelper.get(this, CONFIG_SOCKS5_USER));
-
- TextInputEditText proxyPasswordInput = findViewById(R.id.proxy_password_text);
- proxyPasswordInput.setText(DcHelper.get(this, CONFIG_SOCKS5_PASSWORD));
- }
-
- @Override
- public void onResume() {
- super.onResume();
- dynamicTheme.onResume(this);
- }
-
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
- if (id == android.R.id.home) {
- finish();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- saveConfig();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- saveConfig();
- }
-
- private void focusListener(View view, boolean focused, VerificationType type) {
-
- if (!focused) {
- TextInputEditText inputEditText = (TextInputEditText) view;
- switch (type) {
- case SERVER:
- verifyServer(inputEditText);
- break;
- case PORT:
- verifyPort(inputEditText);
- break;
- }
- }
- }
-
- private void verifyServer(TextInputEditText view) {
- String server = view.getText().toString();
- if (!TextUtils.isEmpty(server) && !Patterns.DOMAIN_NAME.matcher(server).matches()
- && !Patterns.IP_ADDRESS.matcher(server).matches()
- && !Patterns.WEB_URL.matcher(server).matches()
- && !"localhost".equals(server)) {
- view.setError(getString(R.string.login_error_server));
- }
- }
-
- private void verifyPort(TextInputEditText view) {
- String portString = view.getText().toString();
- if (!portString.isEmpty()) {
- String error = getString(R.string.login_error_port);
- try {
- int port = Integer.valueOf(portString);
- if (port < 1 || port > 65535) {
- view.setError(error);
- }
- } catch (NumberFormatException exception) {
- view.setError(error);
- }
- }
- }
-
- private void saveConfig() {
- DcContext dcContext = DcHelper.getContext(this);
- dcContext.setConfigInt(CONFIG_SOCKS5_ENABLED, proxySwitch.isChecked()? 1 : 0);
- setConfig(R.id.proxy_host_text, CONFIG_SOCKS5_HOST, true);
- setConfig(R.id.proxy_port_text, CONFIG_SOCKS5_PORT, true);
- setConfig(R.id.proxy_user_text, CONFIG_SOCKS5_USER, true);
- setConfig(R.id.proxy_password_text, CONFIG_SOCKS5_PASSWORD, false);
- dcContext.stopIo();
- dcContext.startIo();
- }
-
- private void setConfig(@IdRes int viewId, String configTarget, boolean doTrim) {
- TextInputEditText view = findViewById(viewId);
- String value = view.getText().toString();
- if(doTrim) {
- value = value.trim();
- }
- DcHelper.getContext(this).setConfig(configTarget, value.isEmpty()? null : value);
- }
-
-}
diff --git a/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java b/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java
index 8a5eb6f9e..f52eafffb 100644
--- a/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java
@@ -12,11 +12,7 @@ import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_SECURITY;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_SERVER;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_USER;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SERVER_FLAGS;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_ENABLED;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_HOST;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_PASSWORD;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_PORT;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SOCKS5_USER;
+import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
import static org.thoughtcrime.securesms.connect.DcHelper.getContext;
import static org.thoughtcrime.securesms.service.IPCAddAccountsService.ACCOUNT_DATA;
@@ -59,6 +55,7 @@ import com.google.android.material.textfield.TextInputEditText;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.permissions.Permissions;
+import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.IntentUtils;
import org.thoughtcrime.securesms.util.Util;
@@ -162,7 +159,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
String strVal;
int intVal;
- intVal = DcHelper.getInt(this, CONFIG_SOCKS5_ENABLED);
+ intVal = DcHelper.getInt(this, CONFIG_PROXY_ENABLED);
proxySwitch.setChecked(intVal == 1);
expandAdvanced = expandAdvanced || intVal == 1;
@@ -260,7 +257,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
- proxySwitch.setChecked(DcHelper.getInt(this, CONFIG_SOCKS5_ENABLED) == 1);
+ proxySwitch.setChecked(DcHelper.getInt(this, CONFIG_PROXY_ENABLED) == 1);
}
private void showLog() {
diff --git a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
index b3317dd7a..a6d50e324 100644
--- a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
+++ b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
@@ -72,11 +72,8 @@ public class DcHelper {
public static final String CONFIG_SHOW_EMAILS = "show_emails";
public static final String CONFIG_MEDIA_QUALITY = "media_quality";
public static final String CONFIG_WEBRTC_INSTANCE = "webrtc_instance";
- public static final String CONFIG_SOCKS5_ENABLED = "socks5_enabled";
- public static final String CONFIG_SOCKS5_HOST = "socks5_host";
- public static final String CONFIG_SOCKS5_PORT = "socks5_port";
- public static final String CONFIG_SOCKS5_USER = "socks5_user";
- public static final String CONFIG_SOCKS5_PASSWORD = "socks5_password";
+ public static final String CONFIG_PROXY_ENABLED = "proxy_enabled";
+ public static final String CONFIG_PROXY_URL = "proxy_url";
public static final String CONFIG_VERIFIED_ONE_ON_ONE_CHATS = "verified_one_on_one_chats";
public static final String CONFIG_WEBXDC_REALTIME_ENABLED = "webxdc_realtime_enabled";
diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
index fbcf11397..f5f095e4a 100644
--- a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
@@ -37,7 +37,7 @@ import com.b44t.messenger.rpc.RpcException;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.LogViewActivity;
-import org.thoughtcrime.securesms.ProxySettingsActivity;
+import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.RegistrationActivity;
import org.thoughtcrime.securesms.connect.DcEventCenter;
diff --git a/src/main/java/org/thoughtcrime/securesms/proxy/ProxyListAdapter.java b/src/main/java/org/thoughtcrime/securesms/proxy/ProxyListAdapter.java
new file mode 100644
index 000000000..01fe5c832
--- /dev/null
+++ b/src/main/java/org/thoughtcrime/securesms/proxy/ProxyListAdapter.java
@@ -0,0 +1,172 @@
+package org.thoughtcrime.securesms.proxy;
+
+import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.b44t.messenger.DcContext;
+import com.b44t.messenger.DcLot;
+
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.connect.DcHelper;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ProxyListAdapter extends BaseAdapter {
+ private enum ProxyState {
+ CONNECTED,
+ CONNECTING,
+ NOT_CONNECTED,
+ }
+
+ @NonNull private final Context context;
+ @NonNull private final DcContext dcContext;
+ @NonNull private final List proxies = new LinkedList<>();
+ @Nullable private ItemClickListener itemClickListener;
+ @Nullable private ProxyState proxyState;
+ @Nullable private String selectedProxy;
+
+ public ProxyListAdapter(@NonNull Context context)
+ {
+ this.context = context;
+ this.dcContext = DcHelper.getContext(context);
+ }
+
+ @Override
+ public int getCount() {
+ return proxies.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return proxies.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(final int position, View v, final ViewGroup parent) {
+ if (v == null) {
+ v = LayoutInflater.from(context).inflate(R.layout.proxy_list_item, parent, false);
+ }
+
+ TextView host = v.findViewById(R.id.host);
+ TextView protocol = v.findViewById(R.id.protocol);
+ ImageView checkmark = v.findViewById(R.id.checkmark);
+ TextView status = v.findViewById(R.id.status);
+
+ final String proxyUrl = (String)getItem(position);
+ final DcLot qrParsed = dcContext.checkQr(proxyUrl);
+ if (qrParsed.getState() == DcContext.DC_QR_PROXY) {
+ host.setText(qrParsed.getText1());
+ protocol.setText(proxyUrl.split(":", 2)[0]);
+ } else {
+ host.setText(proxyUrl);
+ protocol.setText(R.string.unknown);
+ }
+ if (proxyUrl.equals(selectedProxy)) {
+ checkmark.setVisibility(View.VISIBLE);
+ status.setVisibility(View.VISIBLE);
+ status.setText(getConnectivityString());
+ } else {
+ checkmark.setVisibility(View.GONE);
+ status.setVisibility(View.GONE);
+ }
+
+ v.setOnClickListener(view -> {
+ if (itemClickListener != null) {
+ itemClickListener.onItemClick(proxyUrl);
+ }
+ });
+ v.findViewById(R.id.share).setOnClickListener(view -> {
+ if (itemClickListener != null) {
+ itemClickListener.onItemShare(proxyUrl);
+ }
+ });
+ v.findViewById(R.id.delete).setOnClickListener(view -> {
+ if (itemClickListener != null) {
+ itemClickListener.onItemDelete(proxyUrl);
+ }
+ });
+
+ return v;
+ }
+
+ public void changeData(String newProxies) {
+ proxies.clear();
+ if (!TextUtils.isEmpty(newProxies)) {
+ Collections.addAll(proxies, newProxies.split("\n"));
+ }
+ selectedProxy = proxies.isEmpty()? null : proxies.get(0);
+ proxyState = null; // to force notifyDataSetChanged() in refreshConnectivity()
+ refreshConnectivity();
+ }
+
+ public void setSelectedProxy(String proxyUrl) {
+ selectedProxy = proxyUrl;
+ notifyDataSetChanged();
+ }
+
+ private String getConnectivityString() {
+ if (proxyState == ProxyState.CONNECTED) {
+ return context.getString(R.string.connectivity_connected);
+ }
+ if (proxyState == ProxyState.CONNECTING) {
+ return context.getString(R.string.connectivity_connecting);
+ }
+ return context.getString(R.string.connectivity_not_connected);
+ }
+
+ public void refreshConnectivity() {
+ if (DcHelper.getInt(context, CONFIG_PROXY_ENABLED) != 1) {
+ if (proxyState != ProxyState.NOT_CONNECTED) {
+ proxyState = ProxyState.NOT_CONNECTED;
+ notifyDataSetChanged();
+ }
+ return;
+ }
+
+ int connectivity = dcContext.getConnectivity();
+ if (connectivity >= DcContext.DC_CONNECTIVITY_WORKING) {
+ if (proxyState != ProxyState.CONNECTED) {
+ proxyState = ProxyState.CONNECTED;
+ notifyDataSetChanged();
+ }
+ } else if (connectivity >= DcContext.DC_CONNECTIVITY_CONNECTING) {
+ if (proxyState != ProxyState.CONNECTING) {
+ proxyState = ProxyState.CONNECTING;
+ notifyDataSetChanged();
+ }
+ } else if (proxyState != ProxyState.NOT_CONNECTED) {
+ proxyState = ProxyState.NOT_CONNECTED;
+ notifyDataSetChanged();
+ }
+ }
+
+ public void setItemClickListener(@Nullable ItemClickListener listener) {
+ itemClickListener = listener;
+ }
+
+ public interface ItemClickListener {
+ void onItemClick(String proxyUrl);
+ void onItemShare(String proxyUrl);
+ void onItemDelete(String proxyUrl);
+ }
+
+}
diff --git a/src/main/java/org/thoughtcrime/securesms/proxy/ProxySettingsActivity.java b/src/main/java/org/thoughtcrime/securesms/proxy/ProxySettingsActivity.java
new file mode 100644
index 000000000..3dcb023e3
--- /dev/null
+++ b/src/main/java/org/thoughtcrime/securesms/proxy/ProxySettingsActivity.java
@@ -0,0 +1,189 @@
+package org.thoughtcrime.securesms.proxy;
+
+import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
+import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_URL;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.SwitchCompat;
+
+import com.b44t.messenger.DcContext;
+import com.b44t.messenger.DcEvent;
+import com.b44t.messenger.DcLot;
+
+import org.thoughtcrime.securesms.BaseActionBarActivity;
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.connect.DcEventCenter;
+import org.thoughtcrime.securesms.connect.DcHelper;
+import org.thoughtcrime.securesms.util.DynamicTheme;
+import org.thoughtcrime.securesms.util.Util;
+
+import java.util.LinkedList;
+
+public class ProxySettingsActivity extends BaseActionBarActivity
+ implements ProxyListAdapter.ItemClickListener, DcEventCenter.DcEventDelegate {
+
+ private final DynamicTheme dynamicTheme = new DynamicTheme();
+ private SwitchCompat proxySwitch;
+ private ProxyListAdapter adapter;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ dynamicTheme.onCreate(this);
+ setContentView(R.layout.proxy_settings_activity);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setTitle(R.string.proxy_settings);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ adapter = new ProxyListAdapter(this);
+ adapter.setItemClickListener(this);
+
+ proxySwitch = findViewById(R.id.proxy_switch);
+ proxySwitch.setChecked(DcHelper.getInt(this, CONFIG_PROXY_ENABLED) == 1);
+ proxySwitch.setOnClickListener(l -> {
+ if (proxySwitch.isChecked() && adapter.getCount() == 0) {
+ showAddProxyDialog();
+ } else {
+ DcHelper.set(this, CONFIG_PROXY_ENABLED, proxySwitch.isChecked()? "1" : "0");
+ restartIO();
+ }
+ });
+
+ ListView proxyList = findViewById(R.id.proxy_list);
+ proxyList.setAdapter(adapter);
+ proxyList.addHeaderView(View.inflate(this, R.layout.proxy_list_header, null), null, false);
+ View footer = View.inflate(this, R.layout.proxy_list_footer, null);
+ footer.setOnClickListener(l -> showAddProxyDialog());
+ proxyList.addFooterView(footer);
+ adapter.changeData(DcHelper.get(this, CONFIG_PROXY_URL));
+ DcHelper.getEventCenter(this).addObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ dynamicTheme.onResume(this);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ DcHelper.getEventCenter(this).removeObservers(this);
+ }
+
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+ if (id == android.R.id.home) {
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onItemClick(String proxyUrl) {
+ if (DcHelper.getContext(this).setConfigFromQr(proxyUrl)) {
+ restartIO();
+ adapter.setSelectedProxy(proxyUrl);
+ proxySwitch.setChecked(DcHelper.getInt(this, CONFIG_PROXY_ENABLED) == 1);
+ } else {
+ Toast.makeText(this, R.string.proxy_invalid, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ @Override
+ public void onItemShare(String proxyUrl) {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("text/plain");
+ intent.putExtra(Intent.EXTRA_TEXT, proxyUrl);
+ startActivity(Intent.createChooser(intent, getString(R.string.chat_share_with_title)));
+ }
+
+ @Override
+ public void onItemDelete(String proxyUrl) {
+ String host = DcHelper.getContext(this).checkQr(proxyUrl).getText1();
+ AlertDialog dialog = new AlertDialog.Builder(this)
+ .setTitle(R.string.proxy_delete)
+ .setMessage(getString(R.string.proxy_delete_explain, host))
+ .setPositiveButton(R.string.delete, (dlg, btn) -> deleteProxy(proxyUrl))
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ Util.redPositiveButton(dialog);
+ }
+
+ private void deleteProxy(String proxyUrl) {
+ final LinkedList proxies = new LinkedList<>();
+ for (String proxy: DcHelper.get(this, CONFIG_PROXY_URL).split("\n")) {
+ if (!proxy.equals(proxyUrl)) {
+ proxies.add(proxy);
+ }
+ }
+ if (proxies.isEmpty()) {
+ DcHelper.set(this, CONFIG_PROXY_ENABLED, "0");
+ proxySwitch.setChecked(false);
+ }
+ String proxyUrls = String.join("\n", proxies);
+ DcHelper.set(this, CONFIG_PROXY_URL, proxyUrls);
+ restartIO();
+ adapter.changeData(proxyUrls);
+ }
+
+ private void showAddProxyDialog() {
+ View view = View.inflate(this, R.layout.single_line_input, null);
+ EditText inputField = view.findViewById(R.id.input_field);
+ inputField.setHint(R.string.proxy_add_url_hint);
+
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.proxy_add)
+ .setMessage(R.string.proxy_add_explain)
+ .setView(view)
+ .setPositiveButton(R.string.proxy_use_proxy, (dialog, whichButton) -> {
+ String newProxy = inputField.getText().toString().trim();
+ DcContext dcContext = DcHelper.getContext(this);
+ final DcLot qrParsed = dcContext.checkQr(newProxy);
+ if (qrParsed.getState() == DcContext.DC_QR_PROXY) {
+ dcContext.setConfigFromQr(newProxy);
+ restartIO();
+ adapter.changeData(DcHelper.get(this, CONFIG_PROXY_URL));
+ } else {
+ Toast.makeText(this, R.string.proxy_invalid, Toast.LENGTH_LONG).show();
+ }
+ proxySwitch.setChecked(DcHelper.getInt(this, CONFIG_PROXY_ENABLED) == 1);
+ })
+ .setNegativeButton(android.R.string.cancel, (dialog, whichButton) -> {
+ if (proxySwitch.isChecked() && adapter.getCount() == 0) {
+ // user enabled switch without having proxies yet, revert
+ proxySwitch.setChecked(false);
+ }
+ })
+ .setCancelable(false)
+ .show();
+ }
+
+ private void restartIO() {
+ DcContext dcContext = DcHelper.getContext(this);
+ dcContext.stopIo();
+ dcContext.startIo();
+ }
+
+ @Override
+ public void handleEvent(@NonNull DcEvent event) {
+ if (event.getId() == DcContext.DC_EVENT_CONNECTIVITY_CHANGED) {
+ adapter.refreshConnectivity();
+ }
+ }
+
+}
diff --git a/src/main/res/layout/proxy_list_footer.xml b/src/main/res/layout/proxy_list_footer.xml
new file mode 100644
index 000000000..159ec0eb4
--- /dev/null
+++ b/src/main/res/layout/proxy_list_footer.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
diff --git a/src/main/res/layout/proxy_list_header.xml b/src/main/res/layout/proxy_list_header.xml
new file mode 100644
index 000000000..1ec7175bb
--- /dev/null
+++ b/src/main/res/layout/proxy_list_header.xml
@@ -0,0 +1,13 @@
+
+
diff --git a/src/main/res/layout/proxy_list_item.xml b/src/main/res/layout/proxy_list_item.xml
new file mode 100644
index 000000000..fc6328587
--- /dev/null
+++ b/src/main/res/layout/proxy_list_item.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/res/layout/proxy_settings_activity.xml b/src/main/res/layout/proxy_settings_activity.xml
index d3660855e..4570f22f4 100644
--- a/src/main/res/layout/proxy_settings_activity.xml
+++ b/src/main/res/layout/proxy_settings_activity.xml
@@ -1,128 +1,23 @@
-
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ tools:context=".proxy.ProxySettingsActivity">
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 07ac2131b..c31bd6c1f 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -608,13 +608,22 @@
Proxy
Use Proxy
-
+ Add Proxy
+ Supported proxy types: HTTP(S), SOCKS5 and Shadowsocks.
+ Enter proxy URL here
+ Invalid or unsupported proxy URL
+ Connections
+ Delete Proxy
+ Are you sure you want to delete \"%1$s\"?
+
+
SOCKS5
Use SOCKS5
SOCKS5 Host
SOCKS5 Port
SOCKS5 User
SOCKS5 Password
+
Continue with simplified setup?
The entered e-mail address supports a simplified setup (OAuth 2.0).\n\nIn the next step, please allow Delta Chat to act as your Chat over E-mail app.\n\nDelta Chat does not collect user data, everything stays on your device.
Certificate Checks