Merge pull request #3277 from deltachat/adb/issue-3276

Add separate view for proxy settings
This commit is contained in:
Asiel Díaz Benítez 2024-09-10 20:40:54 +02:00 committed by GitHub
commit 30ac01a57e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 377 additions and 153 deletions

View file

@ -249,6 +249,11 @@
</intent-filter>
</activity>
<activity android:name=".ProxySettingsActivity"
android:label="@string/proxy_settings"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".LogViewActivity"
android:label="@string/pref_log_header"
android:windowSoftInputMode="stateHidden"

View file

@ -20,6 +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.util.RelayUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.getDirectSharingChatId;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedTitle;
@ -357,14 +358,8 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
if (!isRelayingMessageContent(this)) {
inflater.inflate(R.menu.text_secure_normal, menu);
MenuItem item = menu.findItem(R.id.menu_global_map);
if (Prefs.isLocationStreamingEnabled(this)) {
item.setVisible(true);
}
if (!Prefs.isLocationStreamingEnabled(this)) {
menu.findItem(R.id.menu_global_map).setVisible(false);
}
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);
}
super.onPrepareOptionsMenu(menu);
@ -430,6 +425,9 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
case R.id.menu_global_map:
WebxdcActivity.openMaps(this, 0);
return true;
case R.id.menu_proxy_settings:
startActivity(new Intent(this, ProxySettingsActivity.class));
return true;
case android.R.id.home:
onBackPressed();
return true;

View file

@ -13,6 +13,7 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.text.util.Linkify;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
@ -132,13 +133,29 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
handleIntent();
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.clear();
getMenuInflater().inflate(R.menu.instant_onboarding_menu, menu);
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
super.onOptionsItemSelected(item);
if (item.getItemId() == android.R.id.home) {
switch (item.getItemId()) {
case android.R.id.home:
getOnBackPressedDispatcher().onBackPressed();
return true;
case R.id.menu_proxy_settings:
startActivity(new Intent(this, ProxySettingsActivity.class));
return true;
case R.id.menu_view_log:
startActivity(new Intent(this, LogViewActivity.class));
return true;
}
return false;
}

View file

@ -0,0 +1,160 @@
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);
}
}

View file

@ -96,7 +96,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
Spinner certCheck;
private SwitchCompat proxySwitch;
private Group proxyGroup;
@Override
public void onCreate(Bundle bundle) {
@ -127,15 +126,11 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
authMethod = findViewById(R.id.auth_method);
certCheck = findViewById(R.id.cert_check);
proxyGroup = findViewById(R.id.socks5_group);
proxySwitch = findViewById(R.id.socks5_switch);
proxySwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
proxyGroup.setVisibility(isChecked? advancedGroup.getVisibility() : View.GONE);
proxySwitch = findViewById(R.id.proxy_settings);
proxySwitch.setOnClickListener(l -> {
proxySwitch.setChecked(!proxySwitch.isChecked()); // revert toggle
startActivity(new Intent(this, ProxySettingsActivity.class));
});
TextInputEditText proxyHostInput = findViewById(R.id.socks5_host_text);
TextInputEditText proxyPortInput = findViewById(R.id.socks5_port_text);
proxyHostInput.setOnFocusChangeListener((view, focused) -> focusListener(view, focused, VerificationType.SERVER));
proxyPortInput.setOnFocusChangeListener((view, focused) -> focusListener(view, focused, VerificationType.PORT));
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
@ -161,7 +156,16 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
advancedIcon.setOnClickListener(l -> onAdvancedSettings());
advancedIcon.setRotation(45);
viewLogText.setOnClickListener((view) -> showLog());
boolean isConfigured = DcHelper.isConfigured(getApplicationContext());
boolean expandAdvanced = false;
String strVal;
int intVal;
intVal = DcHelper.getInt(this, CONFIG_SOCKS5_ENABLED);
proxySwitch.setChecked(intVal == 1);
expandAdvanced = expandAdvanced || intVal == 1;
if (isConfigured) {
String email = DcHelper.get(this, CONFIG_ADDRESS);
emailInput.setText(email);
@ -170,10 +174,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
}
passwordInput.setText(DcHelper.get(this, CONFIG_MAIL_PASSWORD));
boolean expandAdvanced = false;
String strVal;
int intVal;
TextInputEditText imapLoginInput = findViewById(R.id.imap_login_text);
strVal = DcHelper.get(this, CONFIG_MAIL_USER);
imapLoginInput.setText(strVal);
@ -213,17 +213,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
smtpSecurity.setSelection(intVal);
expandAdvanced = expandAdvanced || intVal != 0;
intVal = DcHelper.getInt(this, CONFIG_SOCKS5_ENABLED);
proxySwitch.setChecked(intVal == 1);
expandAdvanced = expandAdvanced || intVal == 1;
proxyHostInput.setText(DcHelper.get(this, CONFIG_SOCKS5_HOST));
proxyPortInput.setText(DcHelper.get(this, CONFIG_SOCKS5_PORT));
TextInputEditText proxyUserInput = findViewById(R.id.socks5_user_text);
TextInputEditText proxyPasswordInput = findViewById(R.id.socks5_password_text);
proxyUserInput.setText(DcHelper.get(this, CONFIG_SOCKS5_USER));
proxyPasswordInput.setText(DcHelper.get(this, CONFIG_SOCKS5_PASSWORD));
int serverFlags = DcHelper.getInt(this, CONFIG_SERVER_FLAGS);
int sel = 0;
if((serverFlags&DcContext.DC_LP_AUTH_OAUTH2)!=0) {
@ -242,8 +231,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
int certCheckFlags = DcHelper.getInt(this, "imap_certificate_checks");
certCheck.setSelection(certCheckFlags);
expandAdvanced = expandAdvanced || certCheckFlags != 0;
if (expandAdvanced) { onAdvancedSettings(); }
} else if (getIntent() != null && getIntent().getBundleExtra(ACCOUNT_DATA) != null) {
// Companion app might have sent account data
Bundle b = getIntent().getBundleExtra(ACCOUNT_DATA);
@ -261,6 +248,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
}
}
if (expandAdvanced) { onAdvancedSettings(); }
registerForEvents();
}
@ -272,6 +260,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);
}
private void showLog() {
@ -574,12 +563,10 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
private void onAdvancedSettings() {
boolean advancedViewVisible = advancedGroup.getVisibility() == View.VISIBLE;
if (advancedViewVisible) {
proxyGroup.setVisibility(View.GONE);
advancedGroup.setVisibility(View.GONE);
advancedIcon.setRotation(45);
} else {
advancedGroup.setVisibility(View.VISIBLE);
if (proxySwitch.isChecked()) proxyGroup.setVisibility(View.VISIBLE);
advancedIcon.setRotation(0);
}
}
@ -621,15 +608,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
setConfig(R.id.smtp_port_text, CONFIG_SEND_PORT, true);
setConfig(R.id.smtp_login_text, CONFIG_SEND_USER, false);
setConfig(R.id.smtp_password_text, CONFIG_SEND_PASSWORD, false);
if (proxySwitch.isChecked()) {
DcHelper.getContext(this).setConfigInt(CONFIG_SOCKS5_ENABLED, 1);
setConfig(R.id.socks5_host_text, CONFIG_SOCKS5_HOST, true);
setConfig(R.id.socks5_port_text, CONFIG_SOCKS5_PORT, true);
setConfig(R.id.socks5_user_text, CONFIG_SOCKS5_USER, true);
setConfig(R.id.socks5_password_text, CONFIG_SOCKS5_PASSWORD, false);
} else {
DcHelper.getContext(this).setConfigInt(CONFIG_SOCKS5_ENABLED, 0);
}
DcHelper.getContext(this).setConfigInt(CONFIG_MAIL_SECURITY, imapSecurity.getSelectedItemPosition());
DcHelper.getContext(this).setConfigInt(CONFIG_SEND_SECURITY, smtpSecurity.getSelectedItemPosition());

View file

@ -37,6 +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.R;
import org.thoughtcrime.securesms.RegistrationActivity;
import org.thoughtcrime.securesms.connect.DcEventCenter;
@ -208,6 +209,11 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
return true;
}));
this.findPreference("proxy_settings_button").setOnPreferenceClickListener((preference) -> {
startActivity(new Intent(getActivity(), ProxySettingsActivity.class));
return true;
});
Preference passwordAndAccount = this.findPreference("password_account_settings_button");
passwordAndAccount.setOnPreferenceClickListener(((preference) -> {
boolean result = ScreenLockUtil.applyScreenLock(getActivity(), getString(R.string.pref_password_and_account_settings), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT);

View file

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context=".ProxySettingsActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_root_start_shifted"
android:layout_width="wrap_content"
android:layout_height="16dp"
android:orientation="vertical"
app:layout_constraintGuide_begin="14dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_root_start"
android:layout_width="wrap_content"
android:layout_height="16dp"
android:orientation="vertical"
app:layout_constraintGuide_begin="16dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_root_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="16dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/proxy_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="10dp"
android:text="@string/proxy_use_proxy"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Group
android:id="@+id/proxy_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible"
app:constraint_referenced_ids="proxy_host, proxy_port, proxy_user, proxy_password" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/proxy_host"
android:layout_width="0dp"
android:layout_height="58dp"
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/proxy_switch">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/proxy_host_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_socks5_host"
android:inputType="textUri|textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/proxy_port"
android:layout_width="0dp"
android:layout_height="58dp"
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/proxy_host">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/proxy_port_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_socks5_port"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/proxy_user"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/proxy_port">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/proxy_user_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:hint="@string/login_socks5_user" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/proxy_password"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/proxy_user"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/proxy_password_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_socks5_password"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View file

@ -123,7 +123,7 @@
android:visibility="gone"
tools:visibility="visible"
app:constraint_referenced_ids="inbox, imap_login, imap_server, imap_port, imap_security_label, imap_security, outbox_view_spacer_top,
outbox, smtp_login, smtp_password, smtp_server, smtp_port, smtp_security_label, smtp_security, auth_method_label, auth_method, cert_check_label, cert_check, view_log_button, socks5_switch" />
outbox, smtp_login, smtp_password, smtp_server, smtp_port, smtp_security_label, smtp_security, auth_method_label, auth_method, cert_check_label, cert_check, view_log_button, proxy_settings" />
<ImageView
android:id="@+id/advanced_icon"
@ -151,6 +151,17 @@
app:layout_constraintStart_toEndOf="@id/advanced_icon"
app:layout_constraintTop_toBottomOf="@id/no_servers_hint" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/proxy_settings"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:text="@string/proxy_use_proxy"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/advanced_text" />
<TextView
android:id="@+id/inbox"
android:layout_width="wrap_content"
@ -159,7 +170,7 @@
android:layout_marginTop="8dp"
android:text="@string/login_inbox"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/advanced_text" />
app:layout_constraintTop_toBottomOf="@id/proxy_settings" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/imap_login"
@ -378,110 +389,6 @@
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/cert_check_label" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/socks5_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="10dp"
android:text="@string/login_socks5_use_socks5"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/cert_check" />
<androidx.constraintlayout.widget.Group
android:id="@+id/socks5_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="gone"
app:constraint_referenced_ids="socks5_experimental_warning, socks5_host, socks5_port, socks5_user, socks5_password" />
<TextView
android:id="@+id/socks5_experimental_warning"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="left"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="1dp"
android:paddingBottom="10dp"
android:text="@string/login_socks5_experimental_warning"
android:textColor="@color/gray50"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/socks5_switch" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/socks5_host"
android:layout_width="0dp"
android:layout_height="58dp"
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/socks5_experimental_warning">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/socks5_host_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_socks5_host"
android:inputType="textUri|textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/socks5_port"
android:layout_width="0dp"
android:layout_height="58dp"
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/socks5_host">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/socks5_port_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_socks5_port"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/socks5_user"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/socks5_port">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/socks5_user_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:hint="@string/login_socks5_user" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/socks5_password"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/socks5_user"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/socks5_password_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_socks5_password"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/view_log_button"
android:layout_width="0dp"
@ -495,7 +402,7 @@
android:paddingBottom="32dp"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/socks5_password" />
app:layout_constraintTop_toBottomOf="@id/cert_check" />
<TextView
android:id="@+id/sub_header"

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:title="@string/proxy_settings"
android:id="@+id/menu_proxy_settings"
app:showAsAction="never"/>
<item android:title="@string/pref_view_log"
android:id="@+id/menu_view_log"
app:showAsAction="never"/>
</menu>

View file

@ -7,6 +7,11 @@
android:icon="@drawable/baseline_qr_code_24"
app:showAsAction="always"/>
<item android:title="@string/proxy_settings"
android:id="@+id/menu_proxy_settings"
android:visible="false"
/>
<item android:title="@string/invite_friends"
android:id="@+id/menu_invite_friends" />

View file

@ -604,6 +604,8 @@
<string name="login_smtp_port">SMTP Port</string>
<string name="login_smtp_security">SMTP Security</string>
<string name="login_auth_method">Authorization Method</string>
<string name="proxy_settings">Proxy Settings</string>
<string name="proxy_use_proxy">Use Proxy</string>
<!-- the word "SOCKS5" here and in the following strings should not be translated in most cases -->
<string name="login_socks5">SOCKS5</string>
<string name="login_socks5_use_socks5">Use SOCKS5</string>

View file

@ -90,6 +90,9 @@
<PreferenceCategory android:title="@string/pref_server">
<Preference android:key="proxy_settings_button"
android:title="@string/proxy_settings"/>
<Preference android:key="password_account_settings_button"
android:title="@string/pref_password_and_account_settings"/>