From 2a0e6a5b03ed8545ab4848e41e4758b72e4ab35e Mon Sep 17 00:00:00 2001
From: Diego Romar <18450339+doromaraujo@users.noreply.github.com>
Date: Thu, 18 Dec 2025 18:30:09 -0300
Subject: [PATCH 1/6] Add dialog_simple_edit_text layout for dialogs
It has a title, a description for an input field,
an input field, a cancel and a OK button
---
.../res/layout/dialog_simple_edit_text.xml | 81 +++++++++++++++++++
1 file changed, 81 insertions(+)
create mode 100644 app/src/main/res/layout/dialog_simple_edit_text.xml
diff --git a/app/src/main/res/layout/dialog_simple_edit_text.xml b/app/src/main/res/layout/dialog_simple_edit_text.xml
new file mode 100644
index 0000000..6de6019
--- /dev/null
+++ b/app/src/main/res/layout/dialog_simple_edit_text.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
From af65f33438b396d35e3088a423524e8c4981a43c Mon Sep 17 00:00:00 2001
From: Diego Romar <18450339+doromaraujo@users.noreply.github.com>
Date: Fri, 19 Dec 2025 10:47:43 -0300
Subject: [PATCH 2/6] Use dialog_simple_edit_text in Add Profile
---
.../client/ui/profile/ProfilesFragment.java | 34 ++++++++++++-------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java b/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
index 202f8b9..d5fceac 100644
--- a/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
@@ -1,5 +1,6 @@
package io.netbird.client.ui.profile;
+import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.os.Bundle;
import android.util.Log;
@@ -7,6 +8,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
+import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -15,6 +17,7 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import com.google.android.material.button.MaterialButton;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
@@ -26,11 +29,10 @@
public class ProfilesFragment extends Fragment {
private static final String TAG = "ProfilesFragment";
-
private RecyclerView recyclerView;
private ProfilesAdapter adapter;
private ProfileManagerWrapper profileManager;
- private List profiles = new ArrayList<>();
+ private final List profiles = new ArrayList<>();
@Nullable
@Override
@@ -76,23 +78,27 @@ private void loadProfiles() {
adapter.notifyDataSetChanged();
}
+ @SuppressLint("InflateParams")
private void showAddDialog() {
- View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_simple_alert_message, null);
- final EditText input = new EditText(requireContext());
+ View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_simple_edit_text, null);
+
+ TextView txtTitle = dialogView.findViewById(R.id.text_title_dialog);
+ TextView txtLabel = dialogView.findViewById(R.id.text_label_dialog);
+ EditText input = dialogView.findViewById(R.id.edit_text_dialog);
+ MaterialButton btnCancel = dialogView.findViewById(R.id.btn_cancel_dialog);
+ MaterialButton btnOk = dialogView.findViewById(R.id.btn_ok_dialog);
+
+ txtTitle.setText(R.string.profiles_dialog_add_title);
+ txtLabel.setText(R.string.profiles_dialog_add_message);
input.setHint(R.string.profiles_dialog_add_hint);
- final AlertDialog dialog = new AlertDialog.Builder(requireContext())
- .setTitle(R.string.profiles_dialog_add_title)
- .setMessage(R.string.profiles_dialog_add_message)
- .setView(input)
- .setPositiveButton(android.R.string.ok, null)
- .setNegativeButton(android.R.string.cancel, null)
+ final AlertDialog dialog = new AlertDialog.Builder(requireContext(), R.style.AlertDialogTheme)
+ .setView(dialogView)
.create();
- dialog.show();
+ btnCancel.setOnClickListener(v -> dialog.dismiss());
- // Set click listener after show() to prevent auto-dismiss on validation failure
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
+ btnOk.setOnClickListener(v -> {
String profileName = input.getText().toString().trim();
if (profileName.isEmpty()) {
Toast.makeText(requireContext(), R.string.profiles_error_empty_name, Toast.LENGTH_SHORT).show();
@@ -111,6 +117,8 @@ private void showAddDialog() {
addProfile(profileName);
dialog.dismiss();
});
+
+ dialog.show();
}
/**
From ff7d72db50e2888b80f1de2eb79986275180780e Mon Sep 17 00:00:00 2001
From: Diego Romar <18450339+doromaraujo@users.noreply.github.com>
Date: Fri, 19 Dec 2025 10:48:11 -0300
Subject: [PATCH 3/6] Adjust focus highlight corners to 2dp
---
app/src/main/res/drawable/focus_highlight.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/src/main/res/drawable/focus_highlight.xml b/app/src/main/res/drawable/focus_highlight.xml
index 2aa541a..2cb9f79 100644
--- a/app/src/main/res/drawable/focus_highlight.xml
+++ b/app/src/main/res/drawable/focus_highlight.xml
@@ -8,7 +8,7 @@
-
+
@@ -16,7 +16,7 @@
-
-
+
From 1fc61bdf1ebcbdc2b827b6511c128c18855f2820 Mon Sep 17 00:00:00 2001
From: Diego Romar <18450339+doromaraujo@users.noreply.github.com>
Date: Fri, 19 Dec 2025 12:16:17 -0300
Subject: [PATCH 4/6] Add createDialog method to ProfilesFragment
Centralizes layout inflation and dialog
creation. Receives a title, a message and an
optional hint to be displayed in the dialog's
EditText view; if the hint is sent as null, the
dialog won't display its EditText.
DialogCallback interface defines an
onConfirm method that receives a nullable input
text to be used as the confirmation button's
action; its return value indicates whether the
dialog should be dismissed or not after its
execution.
---
.../client/ui/profile/ProfilesFragment.java | 41 ++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java b/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
index d5fceac..d06c08c 100644
--- a/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
@@ -1,5 +1,7 @@
package io.netbird.client.ui.profile;
+import static android.view.View.GONE;
+
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.os.Bundle;
@@ -17,7 +19,6 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.google.android.material.button.MaterialButton;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
@@ -78,7 +79,45 @@ private void loadProfiles() {
adapter.notifyDataSetChanged();
}
+ interface DialogCallback {
+ // Return true to dismiss dialog.
+ boolean onConfirm(@Nullable String inputText);
+ }
+
@SuppressLint("InflateParams")
+ private AlertDialog createDialog(String title, String message, @Nullable String inputHint, DialogCallback callback) {
+ boolean hasInput = inputHint != null;
+
+ View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_simple_edit_text, null);
+
+ TextView txtTitle = dialogView.findViewById(R.id.text_title_dialog);
+ txtTitle.setText(title);
+
+ TextView txtMessage = dialogView.findViewById(R.id.text_label_dialog);
+ txtMessage.setText(message);
+
+ EditText input = dialogView.findViewById(R.id.edit_text_dialog);
+ if (hasInput) {
+ input.setHint(inputHint);
+ } else {
+ input.setVisibility(GONE);
+ }
+
+ AlertDialog dialog = new AlertDialog.Builder(requireContext(), R.style.AlertDialogTheme)
+ .setView(dialogView)
+ .create();
+
+ dialogView.findViewById(R.id.btn_cancel_dialog).setOnClickListener(v -> dialog.dismiss());
+ dialogView.findViewById(R.id.btn_ok_dialog).setOnClickListener(v -> {
+ String inputText = hasInput ? input.getText().toString().trim() : null;
+ if (callback.onConfirm(inputText)) {
+ dialog.dismiss();
+ }
+ });
+
+ return dialog;
+ }
+
private void showAddDialog() {
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_simple_edit_text, null);
From 15edb399369bb0732fb1f59191687c7f90ef4266 Mon Sep 17 00:00:00 2001
From: Diego Romar <18450339+doromaraujo@users.noreply.github.com>
Date: Fri, 19 Dec 2025 12:17:31 -0300
Subject: [PATCH 5/6] Use createDialog in show dialog methods
showAddDialog, showSwitchDialog, showLogoutDialog
and showRemoveDialog were changed to make use of
createDialog.
---
.../client/ui/profile/ProfilesFragment.java | 109 ++++++++----------
1 file changed, 49 insertions(+), 60 deletions(-)
diff --git a/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java b/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
index d06c08c..9296657 100644
--- a/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
@@ -119,45 +119,28 @@ private AlertDialog createDialog(String title, String message, @Nullable String
}
private void showAddDialog() {
- View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_simple_edit_text, null);
-
- TextView txtTitle = dialogView.findViewById(R.id.text_title_dialog);
- TextView txtLabel = dialogView.findViewById(R.id.text_label_dialog);
- EditText input = dialogView.findViewById(R.id.edit_text_dialog);
- MaterialButton btnCancel = dialogView.findViewById(R.id.btn_cancel_dialog);
- MaterialButton btnOk = dialogView.findViewById(R.id.btn_ok_dialog);
-
- txtTitle.setText(R.string.profiles_dialog_add_title);
- txtLabel.setText(R.string.profiles_dialog_add_message);
- input.setHint(R.string.profiles_dialog_add_hint);
-
- final AlertDialog dialog = new AlertDialog.Builder(requireContext(), R.style.AlertDialogTheme)
- .setView(dialogView)
- .create();
-
- btnCancel.setOnClickListener(v -> dialog.dismiss());
-
- btnOk.setOnClickListener(v -> {
- String profileName = input.getText().toString().trim();
- if (profileName.isEmpty()) {
- Toast.makeText(requireContext(), R.string.profiles_error_empty_name, Toast.LENGTH_SHORT).show();
- return;
- }
-
- // Validate profile name based on go client sanitization rules
- String sanitizedName = sanitizeProfileName(profileName);
- if (sanitizedName.isEmpty()) {
- Toast.makeText(requireContext(),
- "Profile name must contain at least one letter, digit, underscore or hyphen",
- Toast.LENGTH_LONG).show();
- return;
- }
-
- addProfile(profileName);
- dialog.dismiss();
- });
-
- dialog.show();
+ createDialog(
+ getString(R.string.profiles_dialog_add_title),
+ getString(R.string.profiles_dialog_add_message),
+ getString(R.string.profiles_dialog_add_hint),
+ profileName -> {
+ if (profileName == null || profileName.isEmpty()) {
+ Toast.makeText(requireContext(), R.string.profiles_error_empty_name, Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
+ // Validate profile name based on go client sanitization rules
+ String sanitizedName = sanitizeProfileName(profileName);
+ if (sanitizedName.isEmpty()) {
+ Toast.makeText(requireContext(),
+ "Profile name must contain at least one letter, digit, underscore or hyphen",
+ Toast.LENGTH_LONG).show();
+ return false;
+ }
+
+ addProfile(profileName);
+ return true;
+ }).show();
}
/**
@@ -177,33 +160,39 @@ private String sanitizeProfileName(String name) {
}
private void showSwitchDialog(Profile profile) {
- String message = getString(R.string.profiles_dialog_switch_message, profile.getName());
- new AlertDialog.Builder(requireContext())
- .setTitle(R.string.profiles_dialog_switch_title)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok, (d, which) -> switchProfile(profile))
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ createDialog(
+ getString(R.string.profiles_dialog_switch_title),
+ getString(R.string.profiles_dialog_switch_message, profile.getName()),
+ null,
+ ignored -> {
+ switchProfile(profile);
+ return true;
+ }
+ ).show();
}
private void showLogoutDialog(Profile profile) {
- String message = getString(R.string.profiles_dialog_logout_message, profile.getName());
- new AlertDialog.Builder(requireContext())
- .setTitle(R.string.profiles_dialog_logout_title)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok, (d, which) -> logoutProfile(profile))
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ createDialog(
+ getString(R.string.profiles_dialog_logout_title),
+ getString(R.string.profiles_dialog_logout_message, profile.getName()),
+ null,
+ ignored -> {
+ logoutProfile(profile);
+ return true;
+ }
+ ).show();
}
private void showRemoveDialog(Profile profile) {
- String message = getString(R.string.profiles_dialog_remove_message, profile.getName());
- new AlertDialog.Builder(requireContext())
- .setTitle(R.string.profiles_dialog_remove_title)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok, (d, which) -> removeProfile(profile))
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ createDialog(
+ getString(R.string.profiles_dialog_remove_title),
+ getString(R.string.profiles_dialog_remove_message, profile.getName()),
+ null,
+ ignored -> {
+ removeProfile(profile);
+ return true;
+ }
+ ).show();
}
private void addProfile(String profileName) {
From 31283d3cbb557f1f46f96a964ec930c60410d90a Mon Sep 17 00:00:00 2001
From: Diego Romar <18450339+doromaraujo@users.noreply.github.com>
Date: Fri, 19 Dec 2025 12:31:59 -0300
Subject: [PATCH 6/6] Replace deprecated call to navigate back to Home
---
.../java/io/netbird/client/ui/profile/ProfilesFragment.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java b/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
index 9296657..f06b75d 100644
--- a/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
@@ -229,7 +229,7 @@ private void switchProfile(Profile profile) {
loadProfiles();
// Navigate back to home
- requireActivity().onBackPressed();
+ requireActivity().getOnBackPressedDispatcher().onBackPressed();
} catch (Exception e) {
Log.e(TAG, "Failed to switch profile", e);
Toast.makeText(requireContext(),