Skip to content

Align Android UI with iOS client patterns#179

Open
pappz wants to merge 10 commits intomainfrom
ux/ios-style-redesign
Open

Align Android UI with iOS client patterns#179
pappz wants to merge 10 commits intomainfrom
ux/ios-style-redesign

Conversation

@pappz
Copy link
Copy Markdown
Collaborator

@pappz pappz commented May 10, 2026

Replace the side drawer + collapsible bottom-sheet pattern with a bottom navigation bar (4 tabs: Home, Peers, Resources, Settings) to mirror the iOS client's TabView. Sub-screens (Advanced, Profiles, Change Server, Troubleshoot, About) are reached from the Settings tab and use an iOS-style sectioned list layout.

  • New SettingsFragment (sectioned list mirroring iOSSettingsView)
  • Promote PeersFragment / NetworksFragment to top-level destinations; drop the modal BottomDialogFragment + PagerAdapter
  • Profile chip on Home opens a ProfilePickerSheet (one-tap switch + Manage profiles link), echoing the iOS ProfileBadge
  • Restyle AdvancedFragment + TroubleshootFragment as sectioned lists; Theme Mode now opens a bottom-sheet picker
  • Refresh menu icons to thinner outlined Material Symbols
  • NavigationRailView via layout-w960dp for large screens / TV
  • Toolbar hidden on top-level destinations; visible on sub-screens
  • Profile cards adopt PR Improve dark mode for profiles screen #137 dark-mode contrast fix
  • Treat the empty-profile-state JSON read as a normal first-launch case in ProfileManagerWrapper instead of logging at error level

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced bottom navigation bar for easier screen navigation.
    • Added theme picker for selecting system, light, or dark appearance.
    • Added profile picker sheet for quick profile switching.
    • New Settings page consolidating app configuration options.
  • UI Improvements

    • Redesigned Advanced Settings layout with improved organization.
    • Updated app icons across navigation and settings.
    • Enhanced visual styling with new colors and spacing for better consistency.

Review Change Stack

Replace the side drawer + collapsible bottom-sheet pattern with a
bottom navigation bar (4 tabs: Home, Peers, Resources, Settings) to
mirror the iOS client's TabView. Sub-screens (Advanced, Profiles,
Change Server, Troubleshoot, About) are reached from the Settings
tab and use an iOS-style sectioned list layout.

- New SettingsFragment (sectioned list mirroring iOSSettingsView)
- Promote PeersFragment / NetworksFragment to top-level destinations;
  drop the modal BottomDialogFragment + PagerAdapter
- Profile chip on Home opens a ProfilePickerSheet (one-tap switch +
  Manage profiles link), echoing the iOS ProfileBadge
- Restyle AdvancedFragment + TroubleshootFragment as sectioned lists;
  Theme Mode now opens a bottom-sheet picker
- Refresh menu icons to thinner outlined Material Symbols
- NavigationRailView via layout-w960dp for large screens / TV
- Toolbar hidden on top-level destinations; visible on sub-screens
- Profile cards adopt PR #137 dark-mode contrast fix
- Treat the empty-profile-state JSON read as a normal first-launch
  case in ProfileManagerWrapper instead of logging at error level
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 10, 2026

Warning

Rate limit exceeded

@pappz has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 42 minutes and 59 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 65ca9ea3-20c7-48d6-bfdf-0c72fa96b600

📥 Commits

Reviewing files that changed from the base of the PR and between a6614db and ab56499.

📒 Files selected for processing (18)
  • app/src/main/java/io/netbird/client/MainActivity.java
  • app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java
  • app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
  • app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
  • app/src/main/res/drawable/ic_add.xml
  • app/src/main/res/drawable/ic_arrow_drop_down.xml
  • app/src/main/res/drawable/ic_check.xml
  • app/src/main/res/drawable/ic_chevron_right.xml
  • app/src/main/res/drawable/ic_nav_home.xml
  • app/src/main/res/drawable/ic_nav_networks.xml
  • app/src/main/res/drawable/ic_nav_peers.xml
  • app/src/main/res/drawable/ic_nav_settings.xml
  • app/src/main/res/drawable/ic_open_in_new.xml
  • app/src/main/res/layout/list_item_profile_picker.xml
  • app/src/main/res/layout/list_item_setting_section.xml
  • app/src/main/res/values-w960dp/dimens.xml
  • app/src/main/res/values/strings.xml
  • tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
📝 Walkthrough

Walkthrough

The PR refactors the app's navigation architecture from a drawer-based model to bottom navigation, introduces profile management and theme selection via bottom sheets, and adds a dedicated settings screen. Navigation wiring, fragment implementations, and layouts are comprehensively updated to support the new structure.

Changes

Navigation Architecture & Profile Management Refactor

Layer / File(s) Summary
Navigation Structure & Bottom Navigation Setup
app/src/main/java/io/netbird/client/MainActivity.java, app/src/main/res/menu/bottom_nav.xml, app/src/main/res/navigation/mobile_navigation.xml
MainActivity refactored to wire BottomNavigationView with NavigationUI; bottom navigation menu defines four destinations (home, peers, networks, settings); navigation graph updated with new fragment destinations.
Theme Picker Sheet Implementation
app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java, app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
New ThemePickerSheet bottom sheet for runtime theme switching; AdvancedFragment refactored to use ThemePickerSheet instead of RadioGroup; OnThemeChangedListener callback pattern for theme change propagation; configureForceRelayConnectionSwitch helper added for force-relay toggle wiring.
Profile Picker & Management System
app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java, app/src/main/java/io/netbird/client/ui/home/ProfilePickerAdapter.java, app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
ProfilePickerSheet and ProfilePickerAdapter new components for profile listing/switching; HomeFragment wired with profile chip click handler; OnProfileSwitchedListener for profile switch notifications; peer-list refresh logic removed.
Settings Fragment & Navigation
app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
New SettingsFragment implementing centralized navigation hub with rows for profiles, advanced settings, troubleshoot, about, and documentation.
Fragment Refactoring & Cleanup
app/src/main/java/io/netbird/client/ui/home/BottomDialogFragment.java, app/src/main/java/io/netbird/client/ui/home/PagerAdapter.java
BottomDialogFragment and PagerAdapter removed; HomeFragment refactored to remove peers button and refresh executor logic; onPeersListChanged becomes intentional no-op.
Activity & Layout Refactoring
app/src/main/res/layout/activity_main.xml, app/src/main/res/layout-w960dp/activity_main.xml, app/src/main/res/layout/app_bar_main.xml, app/src/main/res/layout/content_main.xml
activity_main.xml refactored from DrawerLayout to CoordinatorLayout with BottomNavigationView; tablet variant added with NavigationRailView; included layouts app_bar_main and content_main removed.
Fragment Layouts Modernization
app/src/main/res/layout/fragment_*.xml
Layouts updated for bottom navigation inset (80dp bottom padding); HomeFragment profile chip UI added; AdvancedFragment, Troubleshoot layouts restructured as scrollable vertical lists with section headers; BottomDialog layout removed.
Reusable Row Layouts
app/src/main/res/layout/list_item_profile_picker.xml, app/src/main/res/layout/list_item_setting.xml, app/src/main/res/layout/list_item_setting_toggle.xml, app/src/main/res/layout/list_item_setting_section.xml, app/src/main/res/layout/list_item_setting_divider.xml
New reusable row layout templates for list items and sheet rows; profile list item updated with theme overlay and new avatar drawable.
Drawables, Colors, Themes & Strings
app/src/main/res/drawable/ic_nav_*.xml, app/src/main/res/drawable/ic_menu_*.xml, app/src/main/res/values/colors.xml, app/src/main/res/values/themes.xml, app/src/main/res/values/strings.xml, app/src/main/res/values/dimens.xml
Navigation icons added for bottom bar; menu icons refreshed; color resources for chip/profile styling; Theme.NetBird.Card and SettingsSectionHeader styles added; new string resources for profile picker, bottom navigation, and settings; bottom_nav_inset dimension (80dp) introduced.
Navigation Menu Cleanup
app/src/main/res/menu/activity_main_drawer.xml, app/src/main/res/layout/nav_header_main.xml, app/src/main/res/layout/nav_custom_bottom_item.xml
Drawer menu and header layout files removed; custom bottom navigation item layout removed; MainActivity onResume, openDocs, setVersionText, updateProfileMenuItem, and TV onKeyDown handlers removed.
Utility Updates
tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
getActiveProfile() updated to log fresh-install JSON error as debug message instead of error stack trace.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • netbirdio/android-client#115: Both PRs introduce and refactor profile management UI using ProfileManagerWrapper, adding profile picker components and updating MainActivity's navigation model.

Suggested reviewers

  • doromaraujo

Poem

🐰 Beneath the code, a navigation gleams,
From drawer dreams to bottom-bar streams,
Profiles now picked with sheets so fine,
Themes shift smoothly, settings align,
Clean refactored paths—the way forward shines!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Align Android UI with iOS client patterns' clearly summarizes the main objective of the changeset—refactoring the Android UI to mirror iOS patterns—which is the primary focus of all the modifications across navigation, layout, and component styling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ux/ios-style-redesign

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (4)
app/src/main/res/layout/list_item_profile_picker.xml (1)

21-29: ⚡ Quick win

Constrain profile name to a single line for stable row layout.

At Line 21-29, long names can wrap and push row height unexpectedly. Add maxLines="1" and ellipsize="end" to keep picker rows consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/res/layout/list_item_profile_picker.xml` around lines 21 - 29,
The TextView with id profile_picker_name can wrap long names and change row
height; update the element (profile_picker_name) to constrain it to a single
line by adding maxLines="1" and ellipsize="end" so overflowing text is truncated
with an ellipsis and picker rows remain a stable height.
app/src/main/res/drawable/ic_nav_settings.xml (1)

7-8: ⚡ Quick win

Avoid hardcoded white fill for navigation icons.

Line 7 uses #FFFFFFFF, which makes this asset less theme-adaptive. Prefer a theme color (or rely on menu/icon tint) so the icon works across light/dark and future palette changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/res/drawable/ic_nav_settings.xml` around lines 7 - 8, The vector
drawable currently hardcodes android:fillColor="#FFFFFFFF" which prevents
theming; update the path element in ic_nav_settings.xml to use a theme attribute
instead (e.g. replace android:fillColor="#FFFFFFFF" with
android:fillColor="?attr/colorControlNormal" or another appropriate theme attr
like ?attr/colorOnSurface), or remove the fillColor so the menu/icon tint can
apply; ensure the path element with android:pathData remains unchanged.
tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java (1)

56-64: ⚡ Quick win

Consider improving error detection robustness for first-launch profile state handling.

The code currently detects empty profile state files by matching the error message "unexpected end of JSON input". While this message originates from Go's standard encoding/json package (making it inherently stable), relying on message text remains fragile as a detection pattern. For improved maintainability, consider checking for the underlying exception type or implementing a more explicit state-check approach (e.g., attempting to detect empty/missing state files before calling getActiveProfile(), or requesting gomobile expose a dedicated error code or exception type for this scenario).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java` around
lines 56 - 64, The code in ProfileManagerWrapper is brittle because it detects
the first-launch empty profile by matching the error message text from
getActiveProfile; instead, detect the empty/missing state more robustly before
parsing (e.g., check the profile state file exists and its length/content is
empty) or catch a specific exception type if gomobile exposes one; update
getActiveProfile call-site to first inspect the profile state file (or wrap the
parsing call and inspect the underlying cause) and only treat the empty-file
case as a benign fallback (log via TAG) while letting other exceptions be logged
as errors.
app/src/main/res/layout/list_item_setting_section.xml (1)

4-12: ⚡ Quick win

Use the shared SettingsSectionHeader style here to avoid style drift.

This layout duplicates the same header attributes now defined in @style/SettingsSectionHeader. Reusing the style keeps section headers consistent across screens.

Suggested diff
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:paddingStart="20dp"
-    android:paddingEnd="20dp"
-    android:paddingTop="24dp"
-    android:paddingBottom="8dp"
-    android:textAllCaps="true"
-    android:textColor="@color/nb_txt_light"
-    android:textSize="13sp"
+    style="@style/SettingsSectionHeader"
     tools:text="Connection" />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/res/layout/list_item_setting_section.xml` around lines 4 - 12,
The TextView in this layout duplicates header attributes that are already
captured by the shared style; replace the inline attributes by applying
style="@style/SettingsSectionHeader" on the TextView (remove duplicated
android:textAllCaps, android:textColor, android:textSize and any padding/text
attributes that the style covers) so the view uses the single source of truth
(SettingsSectionHeader) and avoid style drift; ensure any attributes not in the
style that are specific to this layout remain, and verify the TextView ID/text
content is unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/java/io/netbird/client/MainActivity.java`:
- Around line 129-142: The first-install onboarding only hides bottomNav but
still falls through to compute isTopLevel and shows the toolbar; update the
navController.addOnDestinationChangedListener handler so that when
destination.getId() == R.id.firstInstallFragment you both set
bottomNav.setVisibility(View.GONE) and call setToolbarVisible(false) (and then
skip the top-level logic, e.g., return or an else) so the onboarding screen
bypasses both bottom navigation and the toolbar; reference the listener,
firstInstallFragment, bottomNav, setToolbarVisible, and topLevelDestinations
when making the change.

In `@app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java`:
- Around line 133-143: The validation uses sanitizeProfileName(profileName) but
the code still calls profileManager.addProfile(profileName), so invalid
characters get written; change the write to use the sanitized value instead. In
ProfilePickerSheet.replace the call to profileManager.addProfile(profileName)
should be profileManager.addProfile(sanitized) (and likewise use sanitized in
the success Toast/getString call) so the persisted profile and user feedback
match the validated name.

In `@app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java`:
- Around line 56-58: The click handler for binding.rowDocumentation creates an
ACTION_VIEW Intent with DOCS_URL and directly calls startActivity, which can
crash if no browser-capable handler exists; update the lambda that handles
binding.rowDocumentation.setOnClickListener to first query the PackageManager
(e.g., via requireContext().getPackageManager()) and use
intent.resolveActivity(packageManager) or packageManager.queryIntentActivities
to ensure there's at least one handler before calling startActivity, and if none
is found fail gracefully (e.g., show a toast or disable the action).

In `@app/src/main/res/drawable/ic_add.xml`:
- Line 7: The vector path in ic_add.xml hardcodes android:fillColor="#FFFFFFFF";
remove that literal and make the icon theme-tintable by replacing the hardcoded
value with a neutral theme attribute (e.g. ?attr/colorControlNormal or
?attr/colorOnBackground) or a named color resource, so the host view/menu can
apply tinting; update the android:fillColor attribute accordingly (and ensure
ImageView/MenuItem usage applies tint if needed).

In `@app/src/main/res/layout/activity_main.xml`:
- Around line 27-45: The root ConstraintLayout in fragment_home.xml is missing
the bottom navigation inset padding; open fragment_home.xml, locate the root
ConstraintLayout element and add the attribute
android:paddingBottom="@dimen/bottom_nav_inset" so it matches other top-level
fragments (e.g., fragment_peers, fragment_networks) and prevents content from
being hidden behind the BottomNavigationView; ensure you reference the existing
dimen resource bottom_nav_inset (no other changes needed).

In `@app/src/main/res/layout/sheet_theme_picker.xml`:
- Around line 21-116: The theme rows (theme_row_system, theme_row_light,
theme_row_dark) don't expose selection state to TalkBack; update each row to set
an accessible role and dynamic state by adding a contentDescription or
stateDescription that reflects whether its associated check ImageView
(theme_check_system, theme_check_light, theme_check_dark) is visible/selected,
and update that description whenever selection changes; additionally, after
changing selection call announceForAccessibility with a short message (e.g.
"Light theme selected") or attach a custom AccessibilityDelegate on the row
views to send TYPE_VIEW_SELECTED/STATE_CHANGED events so screen readers announce
the new selection.

In `@app/src/main/res/values/dimens.xml`:
- Around line 11-12: The bottom_nav_inset resource is set universally to 80dp
but large-screen rail layouts shouldn't have that bottom inset; add a
configuration-specific override by creating a w960dp-qualified values dimen
resource (e.g., values with qualifier w960dp) that defines bottom_nav_inset as
0dp (or another rail-appropriate value) while keeping the existing default 80dp
in the base dimens.xml so large screens won't get unnecessary bottom padding.

---

Nitpick comments:
In `@app/src/main/res/drawable/ic_nav_settings.xml`:
- Around line 7-8: The vector drawable currently hardcodes
android:fillColor="#FFFFFFFF" which prevents theming; update the path element in
ic_nav_settings.xml to use a theme attribute instead (e.g. replace
android:fillColor="#FFFFFFFF" with android:fillColor="?attr/colorControlNormal"
or another appropriate theme attr like ?attr/colorOnSurface), or remove the
fillColor so the menu/icon tint can apply; ensure the path element with
android:pathData remains unchanged.

In `@app/src/main/res/layout/list_item_profile_picker.xml`:
- Around line 21-29: The TextView with id profile_picker_name can wrap long
names and change row height; update the element (profile_picker_name) to
constrain it to a single line by adding maxLines="1" and ellipsize="end" so
overflowing text is truncated with an ellipsis and picker rows remain a stable
height.

In `@app/src/main/res/layout/list_item_setting_section.xml`:
- Around line 4-12: The TextView in this layout duplicates header attributes
that are already captured by the shared style; replace the inline attributes by
applying style="@style/SettingsSectionHeader" on the TextView (remove duplicated
android:textAllCaps, android:textColor, android:textSize and any padding/text
attributes that the style covers) so the view uses the single source of truth
(SettingsSectionHeader) and avoid style drift; ensure any attributes not in the
style that are specific to this layout remain, and verify the TextView ID/text
content is unchanged.

In `@tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java`:
- Around line 56-64: The code in ProfileManagerWrapper is brittle because it
detects the first-launch empty profile by matching the error message text from
getActiveProfile; instead, detect the empty/missing state more robustly before
parsing (e.g., check the profile state file exists and its length/content is
empty) or catch a specific exception type if gomobile exposes one; update
getActiveProfile call-site to first inspect the profile state file (or wrap the
parsing call and inspect the underlying cause) and only treat the empty-file
case as a benign fallback (log via TAG) while letting other exceptions be logged
as errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 411e484a-8e49-4f4f-b6b3-3b442e3b8742

📥 Commits

Reviewing files that changed from the base of the PR and between 590b73d and a6614db.

📒 Files selected for processing (62)
  • app/src/main/java/io/netbird/client/MainActivity.java
  • app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
  • app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java
  • app/src/main/java/io/netbird/client/ui/home/BottomDialogFragment.java
  • app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
  • app/src/main/java/io/netbird/client/ui/home/PagerAdapter.java
  • app/src/main/java/io/netbird/client/ui/home/ProfilePickerAdapter.java
  • app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
  • app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
  • app/src/main/res/drawable/ic_add.xml
  • app/src/main/res/drawable/ic_arrow_drop_down.xml
  • app/src/main/res/drawable/ic_check.xml
  • app/src/main/res/drawable/ic_chevron_right.xml
  • app/src/main/res/drawable/ic_menu_about.xml
  • app/src/main/res/drawable/ic_menu_advanced.xml
  • app/src/main/res/drawable/ic_menu_change_server.xml
  • app/src/main/res/drawable/ic_menu_docs.xml
  • app/src/main/res/drawable/ic_menu_profile.xml
  • app/src/main/res/drawable/ic_menu_troubleshoot.xml
  • app/src/main/res/drawable/ic_nav_home.xml
  • app/src/main/res/drawable/ic_nav_networks.xml
  • app/src/main/res/drawable/ic_nav_peers.xml
  • app/src/main/res/drawable/ic_nav_settings.xml
  • app/src/main/res/drawable/ic_open_in_new.xml
  • app/src/main/res/drawable/ic_profile_avatar.xml
  • app/src/main/res/drawable/profile_chip_bg.xml
  • app/src/main/res/drawable/settings_row_bg.xml
  • app/src/main/res/drawable/sheet_row_bg.xml
  • app/src/main/res/layout-w960dp/activity_main.xml
  • app/src/main/res/layout/activity_main.xml
  • app/src/main/res/layout/app_bar_main.xml
  • app/src/main/res/layout/content_main.xml
  • app/src/main/res/layout/fragment_about.xml
  • app/src/main/res/layout/fragment_advanced.xml
  • app/src/main/res/layout/fragment_bottom_dialog.xml
  • app/src/main/res/layout/fragment_home.xml
  • app/src/main/res/layout/fragment_networks.xml
  • app/src/main/res/layout/fragment_peers.xml
  • app/src/main/res/layout/fragment_profiles.xml
  • app/src/main/res/layout/fragment_server.xml
  • app/src/main/res/layout/fragment_settings.xml
  • app/src/main/res/layout/fragment_troubleshoot.xml
  • app/src/main/res/layout/list_item_profile.xml
  • app/src/main/res/layout/list_item_profile_picker.xml
  • app/src/main/res/layout/list_item_setting.xml
  • app/src/main/res/layout/list_item_setting_divider.xml
  • app/src/main/res/layout/list_item_setting_section.xml
  • app/src/main/res/layout/list_item_setting_toggle.xml
  • app/src/main/res/layout/nav_custom_bottom_item.xml
  • app/src/main/res/layout/nav_header_main.xml
  • app/src/main/res/layout/sheet_profile_picker.xml
  • app/src/main/res/layout/sheet_theme_picker.xml
  • app/src/main/res/menu/activity_main_drawer.xml
  • app/src/main/res/menu/bottom_nav.xml
  • app/src/main/res/navigation/mobile_navigation.xml
  • app/src/main/res/values-night/colors.xml
  • app/src/main/res/values-night/themes.xml
  • app/src/main/res/values/colors.xml
  • app/src/main/res/values/dimens.xml
  • app/src/main/res/values/strings.xml
  • app/src/main/res/values/themes.xml
  • tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
💤 Files with no reviewable changes (8)
  • app/src/main/res/layout/nav_custom_bottom_item.xml
  • app/src/main/res/layout/fragment_bottom_dialog.xml
  • app/src/main/res/layout/nav_header_main.xml
  • app/src/main/java/io/netbird/client/ui/home/PagerAdapter.java
  • app/src/main/res/layout/app_bar_main.xml
  • app/src/main/res/menu/activity_main_drawer.xml
  • app/src/main/res/layout/content_main.xml
  • app/src/main/java/io/netbird/client/ui/home/BottomDialogFragment.java

Comment thread app/src/main/java/io/netbird/client/MainActivity.java
Comment thread app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java Outdated
Comment thread app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java Outdated
Comment thread app/src/main/res/drawable/ic_add.xml Outdated
Comment thread app/src/main/res/layout/activity_main.xml
Comment thread app/src/main/res/layout/sheet_theme_picker.xml
Comment thread app/src/main/res/values/dimens.xml
pappz added 9 commits May 10, 2026 16:27
The destination listener was hiding the bottom nav on the first-launch
fragment but still falling through to the top-level toolbar logic, so
the toolbar stayed visible. Treat firstInstallFragment as a full-screen
take-over and bypass the rest of the listener.
ProfilePickerSheet validated the input via sanitizeProfileName() but
still wrote the raw user string, so disallowed characters (anything
outside [A-Za-z0-9_-]) made it into the engine. Pass the sanitized
value to addProfile() and the success/duplicate toasts so what the
user sees matches what was stored.
On a TV or stripped-down build there may not be an Activity that
handles ACTION_VIEW for an https URL. Catch ActivityNotFoundException
and surface a toast instead of crashing the app.
Hardcoded #FFFFFFFF prevents these icons from adapting to theme
overlays (e.g. dark mode, focus inversions on TV). Switch to
?attr/colorControlNormal so each icon picks up the correct tint
from its host theme.

Affects ic_nav_home, ic_nav_peers, ic_nav_networks, ic_nav_settings,
ic_add, ic_check, ic_chevron_right, ic_arrow_drop_down,
ic_open_in_new — all custom icons introduced in this branch.
Theme picker rows now expose:
- contentDescription with the theme label
- stateDescription "Selected" on the active row (Android R+)
- isSelected=true on the active row for accessibility services
After picking, announce "<theme> theme selected" on the sheet root
so TalkBack confirms the change before the sheet dismisses.
On large screens the bottom navigation moves to a side rail
(layout-w960dp/activity_main.xml). The 80dp bottom padding fragments
add to clear the bottom bar is therefore wasted vertical space — set
the dimen to 0dp at the same qualifier so layouts pick the right
value automatically without per-layout overrides.
A long profile name was wrapping and pushing the picker row taller
than the others, breaking the row rhythm. maxLines=1 + ellipsize=end
truncates the overflow with "…" so picker rows stay uniform.
list_item_setting_section.xml duplicated the same padding / text size
/ caps attributes already defined in @style/SettingsSectionHeader,
which the section headers inside fragment_settings.xml etc. already
apply via the style. Replace the inline attributes with a single
style= reference so the section template is the same source of truth.
CodeRabbit suggested catching a typed exception or pre-checking the
state file length. The gomobile binding flattens the Go error chain
into go.Universe$proxyerror without surfacing the underlying type,
and the state-file path is a Go-side constant not exposed to Java,
so neither approach is available without a gomobile API change.
Expand the comment to make that trade-off explicit so the next
reader doesn't try the same refactor.
@pappz pappz requested a review from lixmal May 10, 2026 18:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant