diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2bd60cf7..922e49af 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,7 +4,8 @@
android:noHistory="true"
tools:ignore="LockedOrientationActivity">
-
@@ -13,7 +14,8 @@
-
+
{
try {
resetSelectedServer();
diff --git a/app/src/main/java/org/fptn/vpn/utils/SharedPrefUtils.java b/app/src/main/java/org/fptn/vpn/utils/SharedPrefUtils.java
index 444f3b81..e9d17be6 100644
--- a/app/src/main/java/org/fptn/vpn/utils/SharedPrefUtils.java
+++ b/app/src/main/java/org/fptn/vpn/utils/SharedPrefUtils.java
@@ -108,6 +108,16 @@ public static void saveResetSelectedServerEnabled(Context context, boolean enabl
sharedPreferences.edit().putBoolean(Constants.RESET_SELECTED_SERVER_PREF_KEY, enabled).apply();
}
+ public static boolean getResetSelectedServerOnExceptionEnabled(Context context) {
+ SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.APPLICATION_SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ return sharedPreferences.getBoolean(Constants.RESET_SELECTED_SERVER_ON_EXCEPTION_PREF_KEY, false);
+ }
+
+ public static void saveResetSelectedServerOnExceptionEnabled(Context context, boolean enabled) {
+ SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.APPLICATION_SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ sharedPreferences.edit().putBoolean(Constants.RESET_SELECTED_SERVER_ON_EXCEPTION_PREF_KEY, enabled).apply();
+ }
+
public static BypassCensorshipMethod getBypassCensorshipMethod(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.APPLICATION_SHARED_PREFERENCES, Context.MODE_PRIVATE);
diff --git a/app/src/main/java/org/fptn/vpn/views/experimentalsettings/ExperimentalSettingsActivity.java b/app/src/main/java/org/fptn/vpn/views/experimentalsettings/ExperimentalSettingsActivity.java
new file mode 100644
index 00000000..77fb8a96
--- /dev/null
+++ b/app/src/main/java/org/fptn/vpn/views/experimentalsettings/ExperimentalSettingsActivity.java
@@ -0,0 +1,228 @@
+package org.fptn.vpn.views.experimentalsettings;
+
+import android.annotation.SuppressLint;
+import android.app.StatusBarManager;
+import android.content.ComponentName;
+import android.graphics.drawable.Icon;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.SwitchCompat;
+
+import org.fptn.vpn.R;
+import org.fptn.vpn.services.tile.FptnTileService;
+import org.fptn.vpn.utils.SharedPrefUtils;
+
+public class ExperimentalSettingsActivity extends AppCompatActivity {
+ private final String TAG = this.getClass().getSimpleName();
+
+ private SwitchCompat switchNetworkType;
+ private SwitchCompat switchIPAddress;
+ private SeekBar seekBarAttemptsCount;
+ private SeekBar seekBarDelayBetween;
+ private SwitchCompat resetServerAfterDisconnectSwitch;
+ private SwitchCompat resetServerAfterDisconnectOnException;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.experimental_settings_layout);
+
+ initializeVariable();
+ }
+
+ @SuppressLint("InlinedApi")
+ private void initializeVariable() {
+ switchNetworkType = findViewById(R.id.reconnect_on_change_network_type_switch);
+ switchNetworkType.setChecked(SharedPrefUtils.getReconnectOnChangeNetworkTypeEnabled(this));
+
+ switchIPAddress = findViewById(R.id.reconnect_on_change_ip_address_switch);
+ switchIPAddress.setChecked(SharedPrefUtils.getReconnectOnChangeIPEnabled(this));
+
+ // Reconnects attempts count
+ seekBarAttemptsCount = findViewById(R.id.seekBarAttemptsCount);
+ TextView textViewAttemptsCount = findViewById(R.id.textViewAttemptsCount);
+ seekBarAttemptsCount.setOnSeekBarChangeListener(new SimpleSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (progress == 3) {
+ textViewAttemptsCount.setText("∞");
+ } else {
+ String format = getString(R.string.reconnect_attempts_text);
+ textViewAttemptsCount.setText(String.format(format, progress * 5));
+ }
+ }
+ });
+
+ seekBarAttemptsCount.setProgress(0);
+ int reconnectAttemptsCount = SharedPrefUtils.getReconnectAttemptsCount(this);
+ if (reconnectAttemptsCount == Integer.MAX_VALUE) {
+ seekBarAttemptsCount.setProgress(3);
+ } else {
+ seekBarAttemptsCount.setProgress(reconnectAttemptsCount / 5);
+ }
+
+ // Reconnects delay between in seconds
+ seekBarDelayBetween = findViewById(R.id.seekBarDelayBetween);
+ TextView textViewDelayBetween = findViewById(R.id.textViewDelayBetween);
+ seekBarDelayBetween.setOnSeekBarChangeListener(new SimpleSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ String format = getString(R.string.delay_between_attempts_seconds);
+ textViewDelayBetween.setText(String.format(format, progress + 1));
+ }
+ });
+
+ int delayBetweenReconnect = SharedPrefUtils.getDelayBetweenReconnect(this);
+ seekBarDelayBetween.setProgress(0);
+ seekBarDelayBetween.setProgress(delayBetweenReconnect - 1);
+
+ // Quick tile request
+ View tileButtonLayout = findViewById(R.id.tile_layout);
+ Button buttonRequestTile = findViewById(R.id.quick_settings_tile_button);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ buttonRequestTile.setVisibility(View.VISIBLE);
+ buttonRequestTile.setEnabled(true);
+ buttonRequestTile.setOnClickListener(v -> requestQuickSettingsTile(buttonRequestTile));
+
+ tileButtonLayout.setVisibility(View.VISIBLE);
+ } else {
+ buttonRequestTile.setVisibility(View.GONE); // Use GONE to free up layout space
+
+ tileButtonLayout.setVisibility(View.GONE);
+ }
+
+ // Reset selected server on disconnect
+ resetServerAfterDisconnectSwitch = findViewById(R.id.reset_selected_server_after_disconnect_switch);
+ resetServerAfterDisconnectSwitch.setChecked(SharedPrefUtils.getResetSelectedServerEnabled(this));
+
+ // Reset selected server on disconnect with exception
+ resetServerAfterDisconnectOnException = findViewById(R.id.reset_selected_server_after_disconnect_with_exception);
+ resetServerAfterDisconnectOnException.setChecked(SharedPrefUtils.getResetSelectedServerEnabled(this));
+
+ resetServerAfterDisconnectOnException.setChecked(SharedPrefUtils.getResetSelectedServerOnExceptionEnabled(this));
+ updateExceptionVisibility(resetServerAfterDisconnectSwitch.isChecked());
+
+ // Toggle visibility on change
+ resetServerAfterDisconnectSwitch.setOnCheckedChangeListener(
+ (buttonView, isChecked) -> updateExceptionVisibility(isChecked));
+
+
+ // Save and Cancel buttons
+ Button cancelButton = findViewById(R.id.cancel_button);
+ cancelButton.setOnClickListener(v -> {
+ Log.d(TAG, "Cancel button clicked");
+ finish();
+ });
+
+ Button saveButton = findViewById(R.id.save_button);
+ saveButton.setOnClickListener(v -> saveAndFinish());
+ }
+
+ private void updateExceptionVisibility(boolean isVisible) {
+ resetServerAfterDisconnectOnException.setVisibility(isVisible ? View.GONE : View.VISIBLE);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
+ private void requestQuickSettingsTile(Button buttonRequestTile) {
+ StatusBarManager statusBarManager = getSystemService(StatusBarManager.class);
+ if (statusBarManager == null) return;
+
+ // Disable button to prevent double-clicks
+ buttonRequestTile.setEnabled(false);
+
+ try {
+ ComponentName componentName = new ComponentName(this, FptnTileService.class);
+ String label = getString(R.string.app_name); // Or specific tile label
+ Icon icon = Icon.createWithResource(this, R.drawable.ic_logo);
+ statusBarManager.requestAddTileService(
+ componentName,
+ label,
+ icon,
+ getMainExecutor(),
+ resultCode -> handleTileRequestResult(resultCode, buttonRequestTile)
+ );
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to request tile addition", e);
+ Toast.makeText(this, R.string.tile_addition_failed, Toast.LENGTH_SHORT).show();
+ buttonRequestTile.setEnabled(true);
+ }
+ }
+
+ private void handleTileRequestResult(int resultCode, Button button) {
+ // Re-enable button unless the tile was successfully added/exists
+ boolean shouldKeepDisabled = false;
+
+ switch (resultCode) {
+ case StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED:
+ Log.d(TAG, "Tile already added successfully.");
+ Toast.makeText(this, R.string.tile_already_added, Toast.LENGTH_SHORT).show();
+ button.setBackgroundResource(R.drawable.round_back_secondary_cancel_100);
+ shouldKeepDisabled = true;
+ break;
+
+ case StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ADDED:
+ Log.d(TAG, "Tile added successfully.");
+ Toast.makeText(this, R.string.tile_added_successfully, Toast.LENGTH_SHORT).show();
+ shouldKeepDisabled = true;
+ break;
+
+ case StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED:
+ Log.d(TAG, "User cancelled the request or it failed.");
+ button.setEnabled(true);
+ break;
+
+ default:
+ Log.d(TAG, "Unknown result code: " + resultCode);
+ button.setEnabled(true);
+ break;
+ }
+
+ if (shouldKeepDisabled) {
+ button.setEnabled(false);
+ button.setAlpha(0.5f); // Visual cue that it's no longer needed
+ }
+ }
+
+ private void saveAndFinish() {
+ Log.d(TAG, "Save button clicked");
+
+ SharedPrefUtils.saveReconnectOnChangeNetworkTypeEnabled(this, switchNetworkType.isChecked());
+ SharedPrefUtils.saveReconnectOnChangeIPEnabled(this, switchIPAddress.isChecked());
+ SharedPrefUtils.saveResetSelectedServerEnabled(this, resetServerAfterDisconnectSwitch.isChecked());
+ SharedPrefUtils.saveResetSelectedServerOnExceptionEnabled(this, resetServerAfterDisconnectOnException.isChecked());
+
+ int attemptsCountProgress = seekBarAttemptsCount.getProgress();
+ if (attemptsCountProgress == 3) {
+ SharedPrefUtils.saveReconnectAttemptsCount(this, Integer.MAX_VALUE);
+ } else {
+ SharedPrefUtils.saveReconnectAttemptsCount(this, attemptsCountProgress * 5);
+ }
+
+ int delayBetweenProgress = seekBarDelayBetween.getProgress();
+ SharedPrefUtils.saveDelayBetweenReconnect(this, delayBetweenProgress + 1);
+
+ finish();
+ }
+
+ // Helper to reduce boilerplate for SeekBars
+ private abstract static class SimpleSeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ }
+}
+
diff --git a/app/src/main/java/org/fptn/vpn/views/settings/SettingsActivity.java b/app/src/main/java/org/fptn/vpn/views/settings/SettingsActivity.java
index 8e3a1450..fd78ab3e 100644
--- a/app/src/main/java/org/fptn/vpn/views/settings/SettingsActivity.java
+++ b/app/src/main/java/org/fptn/vpn/views/settings/SettingsActivity.java
@@ -2,15 +2,10 @@
import android.annotation.SuppressLint;
import android.app.AlertDialog;
-import android.app.StatusBarManager;
-import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.graphics.drawable.Icon;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.text.Html;
@@ -18,12 +13,9 @@
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
-import android.widget.SeekBar;
import android.widget.TextView;
-import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@@ -33,10 +25,9 @@
import com.google.android.material.bottomnavigation.BottomNavigationView;
import org.fptn.vpn.R;
-import org.fptn.vpn.services.tile.FptnTileService;
import org.fptn.vpn.utils.PermissionsUtils;
-import org.fptn.vpn.utils.SharedPrefUtils;
import org.fptn.vpn.views.CustomBottomNavigationListener;
+import org.fptn.vpn.views.experimentalsettings.ExperimentalSettingsActivity;
import org.fptn.vpn.views.splash.SplashActivity;
import org.fptn.vpn.views.adapter.ServerEntityAdapter;
import org.fptn.vpn.views.bypassmethod.BypassMethodsActivity;
@@ -115,7 +106,7 @@ private void initializeVariable() {
updateTokenLayout.setOnClickListener(this::onUpdateToken);
View experimentalFeaturesLayout = findViewById(R.id.experimental_features_layout);
- experimentalFeaturesLayout.setOnClickListener(this::showExperimentalSettingsDialog);
+ experimentalFeaturesLayout.setOnClickListener(this::onExperimentalSettings);
View logoutLayout = findViewById(R.id.logout_layout);
logoutLayout.setOnClickListener(this::onLogout);
@@ -183,6 +174,11 @@ private void requestBackgroundDataTransferPermission() {
.show();
}
+ private void onExperimentalSettings(View view) {
+ Intent intent = new Intent(SettingsActivity.this, ExperimentalSettingsActivity.class);
+ startActivity(intent);
+ }
+
public void onLogout(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle(R.string.dialog_logout_title)
@@ -204,7 +200,6 @@ public void onUpdateToken(View v) {
startActivity(intent);
}
- // NEW: Bypass methods click handler
public void onBypassMethods(View v) {
Intent intent = new Intent(SettingsActivity.this, BypassMethodsActivity.class);
startActivity(intent);
@@ -233,145 +228,4 @@ private static void setListViewHeightBasedOnChildren(ListView listView) {
listView.setLayoutParams(params);
listView.requestLayout();
}
-
- public void showExperimentalSettingsDialog(View view) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.experimental_features_label);
- builder.setIcon(R.drawable.ic_experimental_features_24);
-
- View dialogView = getLayoutInflater().inflate(R.layout.experimental_settings_dialog, null);
- builder.setView(dialogView);
-
- /* Reconnect on change network type */
- SwitchCompat switchNetworkType = dialogView.findViewById(R.id.reconnect_on_change_network_type_switch);
- switchNetworkType.setChecked(SharedPrefUtils.getReconnectOnChangeNetworkTypeEnabled(this));
-
- /* Reconnect on change IP address */
- SwitchCompat switchIPAddress = dialogView.findViewById(R.id.reconnect_on_change_ip_address_switch);
- switchIPAddress.setChecked(SharedPrefUtils.getReconnectOnChangeIPEnabled(this));
-
- /* Quick tile request */
- Button buttonRequestTile = dialogView.findViewById(R.id.quick_settings_tile_button);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- buttonRequestTile.setOnClickListener(l -> {
- @SuppressLint("WrongConstant") StatusBarManager statusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
- try {
- // Request to add a custom tile service
- statusBarManager.requestAddTileService(
- new ComponentName(this, FptnTileService.class),
- "FPTN",
- Icon.createWithResource(this, R.drawable.ic_logo),
- this.getMainExecutor(),
- (resultCode) -> {
- if (resultCode == StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED) {
- Log.d(TAG, "Tile already added successfully. Nothing to do.");
- Toast.makeText(this, R.string.tile_already_added, Toast.LENGTH_SHORT)
- .show();
- } else if (resultCode == StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ADDED) {
- Log.d(TAG, "Tile added successfully.");
- Toast.makeText(this, R.string.tile_added_successfully, Toast.LENGTH_SHORT)
- .show();
- } else {
- Log.d(TAG, "User cancel request.");
- }
- }
- );
- } catch (Exception e) {
- Log.e(TAG, "Failed to request tile addition", e);
- Toast.makeText(this, R.string.tile_addition_failed, Toast.LENGTH_SHORT)
- .show();
- }
- });
- buttonRequestTile.setEnabled(true);
- buttonRequestTile.setVisibility(View.VISIBLE);
- } else {
- buttonRequestTile.setEnabled(false);
- buttonRequestTile.setVisibility(View.INVISIBLE);
- }
-
- /* Reconnects attempts count */
- SeekBar seekBarAttemptsCount = dialogView.findViewById(R.id.seekBarAttemptsCount);
- TextView textViewAttemptsCount = dialogView.findViewById(R.id.textViewAttemptsCount);
- seekBarAttemptsCount.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (progress == 3) {
- textViewAttemptsCount.setText("∞");
- } else {
- String format = getString(R.string.reconnect_attempts_text);
- textViewAttemptsCount.setText(String.format(format, progress * 5));
- }
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
-
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
-
- }
- });
-
- seekBarAttemptsCount.setProgress(0);
- int reconnectAttemptsCount = SharedPrefUtils.getReconnectAttemptsCount(this);
- if (reconnectAttemptsCount == Integer.MAX_VALUE) {
- seekBarAttemptsCount.setProgress(3);
- } else {
- seekBarAttemptsCount.setProgress(reconnectAttemptsCount / 5);
- }
-
- /* Reconnects delay between in seconds */
- SeekBar seekBarDelayBetween = dialogView.findViewById(R.id.seekBarDelayBetween);
- TextView textViewDelayBetween = dialogView.findViewById(R.id.textViewDelayBetween);
- seekBarDelayBetween.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- String format = getString(R.string.delay_between_attempts_seconds);
- textViewDelayBetween.setText(String.format(format, progress + 1));
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
-
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
-
- }
- });
-
- int delayBetweenReconnect = SharedPrefUtils.getDelayBetweenReconnect(this);
- seekBarDelayBetween.setProgress(0);
- seekBarDelayBetween.setProgress(delayBetweenReconnect - 1);
-
- /* Reset selected server on disconnect */
- SwitchCompat resetServerAfterDisconnectSwitch = dialogView.findViewById(R.id.reset_selected_server_after_disconnect_switch);
- resetServerAfterDisconnectSwitch.setChecked(SharedPrefUtils.getResetSelectedServerEnabled(this));
-
- builder.setPositiveButton(getString(R.string.save_button), (dialog, which) -> {
- Log.d(TAG, "experimentalFeaturesDialog: save");
- SharedPrefUtils.saveReconnectOnChangeNetworkTypeEnabled(this, switchNetworkType.isChecked());
- SharedPrefUtils.saveReconnectOnChangeIPEnabled(this, switchIPAddress.isChecked());
- SharedPrefUtils.saveResetSelectedServerEnabled(this, resetServerAfterDisconnectSwitch.isChecked());
-
- int attemptsCountProgress = seekBarAttemptsCount.getProgress();
- if (attemptsCountProgress == 3) {
- SharedPrefUtils.saveReconnectAttemptsCount(this, Integer.MAX_VALUE);
- } else {
- SharedPrefUtils.saveReconnectAttemptsCount(this, attemptsCountProgress * 5);
- }
-
- int delayBetweenProgress = seekBarDelayBetween.getProgress();
- SharedPrefUtils.saveDelayBetweenReconnect(this, delayBetweenProgress + 1);
- });
- builder.setNegativeButton(getString(R.string.cancel_button), (dialog, which) -> {
- Log.d(TAG, "experimentalFeaturesDialog: cancel");
- dialog.dismiss();
- });
-
- builder.create().show();
- }
}
diff --git a/app/src/main/res/layout/experimental_settings_dialog.xml b/app/src/main/res/layout/experimental_settings_dialog.xml
deleted file mode 100644
index b6ede063..00000000
--- a/app/src/main/res/layout/experimental_settings_dialog.xml
+++ /dev/null
@@ -1,212 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/experimental_settings_layout.xml b/app/src/main/res/layout/experimental_settings_layout.xml
new file mode 100644
index 00000000..21581fca
--- /dev/null
+++ b/app/src/main/res/layout/experimental_settings_layout.xml
@@ -0,0 +1,346 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/settings_layout.xml b/app/src/main/res/layout/settings_layout.xml
index 1bcdbc18..a59595d2 100644
--- a/app/src/main/res/layout/settings_layout.xml
+++ b/app/src/main/res/layout/settings_layout.xml
@@ -150,6 +150,7 @@
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -187,14 +186,13 @@
android:id="@+id/loading_apps_progress_bar"
style="?android:attr/progressBarStyle"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ android:layout_height="match_parent" />
-
diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa-rIR/strings.xml
index e65987ad..955fdd16 100644
--- a/app/src/main/res/values-fa-rIR/strings.xml
+++ b/app/src/main/res/values-fa-rIR/strings.xml
@@ -154,8 +154,8 @@ https://play.google.com/store/apps/details?id=org.fptn.vpn
کاشی تنظیمات سریع قبلاً اضافه شده است
کاشی تنظیمات سریع با موفقیت اضافه شد
افزودن کاشی تنظیمات سریع ناموفق بود!
- بازنشانی سرور انتخابشده پس از قطع اتصال؟
+ تنظیم مجدد سرور فقط در صورت بروز خطاهای اتصال
روشهای دور زدن محدودیتها
پیکربندی روشهای دور زدن فیلترینگ
@@ -176,5 +176,7 @@ https://play.google.com/store/apps/details?id=org.fptn.vpn
فقط برنامههای موجود در لیست از VPN استفاده میکنند
تمام برنامهها از VPN استفاده میکنند، مگر موارد انتخابی
تمام برنامهها از VPN استفاده میکنند، مگر موارد انتخابی
+ انتخاب سرور:
+ پس از قطع ارتباط، سرور انتخاب شده را بازنشانی کنید
diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml
index 60e344a9..becfbeaa 100644
--- a/app/src/main/res/values-ru-rRU/strings.xml
+++ b/app/src/main/res/values-ru-rRU/strings.xml
@@ -153,8 +153,8 @@ https://play.google.com/store/apps/details?id=org.fptn.vpn
Плитка быстрых настроек была добавлена ранее
Плитка быстрых настроек добавлена
Плитка быстрых настроек не добавлена!
- Сброс выбранного сервера после отключения?
+ Сброс на Auto только при ошибке
Методы обхода блокировок
Настройка методов обхода блокировок
@@ -173,5 +173,7 @@ https://play.google.com/store/apps/details?id=org.fptn.vpn
Только приложения из списка используют VPN
Все приложения используют VPN, кроме выбранных
Все приложения используют VPN, кроме выбранных
+ Выбор сервера:
+ Сброс на Auto после отключения
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a2f9da19..58748446 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -215,7 +215,11 @@ https://play.google.com/store/apps/details?id=org.fptn.vpn
Tile already added
Tile added successfully
Tile addition failed!
- Reset selected server after disconnect?
+
+
+ Server Selection:
+ Reset selected server after disconnect
+ Reset server only on connection errors
Bypass blocking methods
Configure bypass blocking methods
diff --git a/core/common/src/main/kotlin/org/fptn/vpn/core/common/Constants.kt b/core/common/src/main/kotlin/org/fptn/vpn/core/common/Constants.kt
index c4a38aa8..0bd3a1fe 100644
--- a/core/common/src/main/kotlin/org/fptn/vpn/core/common/Constants.kt
+++ b/core/common/src/main/kotlin/org/fptn/vpn/core/common/Constants.kt
@@ -24,6 +24,7 @@ object Constants {
// Shares preferences constants
const val CURRENT_SNI_SHARED_PREF_KEY: String = "CURRENT_SNI"
const val RESET_SELECTED_SERVER_PREF_KEY: String = "RESET_SELECTED_SERVER_PREF_KEY"
+ const val RESET_SELECTED_SERVER_ON_EXCEPTION_PREF_KEY: String = "RESET_SELECTED_SERVER_ON_EXCEPTION_PREF_KEY"
const val APPLICATION_SHARED_PREFERENCES = "fptnvpn-shared-preferences"
const val PERMISSIONS_REQUESTED_SHARED_PREF_KEY: String = "permissions_requested_previously"
const val RECONNECT_ON_CHANGE_IP_ENABLED_SHARED_PREF_KEY: String = "RECONNECT_ON_CHANGE_IP_ENABLED"