From a6614dbf056e6ba4e73ac5d34668eeab2e025bb3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:15:59 +0200
Subject: [PATCH 001/140] ux: align Android UI with iOS client patterns
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
---
.../java/io/netbird/client/MainActivity.java | 235 ++----
.../client/ui/advanced/AdvancedFragment.java | 100 +--
.../client/ui/advanced/ThemePickerSheet.java | 76 ++
.../client/ui/home/BottomDialogFragment.java | 185 -----
.../netbird/client/ui/home/HomeFragment.java | 89 +--
.../netbird/client/ui/home/PagerAdapter.java | 48 --
.../client/ui/home/ProfilePickerAdapter.java | 67 ++
.../client/ui/home/ProfilePickerSheet.java | 175 +++++
.../client/ui/settings/SettingsFragment.java | 99 +++
app/src/main/res/drawable/ic_add.xml | 9 +
.../main/res/drawable/ic_arrow_drop_down.xml | 9 +
app/src/main/res/drawable/ic_check.xml | 9 +
.../main/res/drawable/ic_chevron_right.xml | 9 +
app/src/main/res/drawable/ic_menu_about.xml | 4 +-
.../main/res/drawable/ic_menu_advanced.xml | 4 +-
.../res/drawable/ic_menu_change_server.xml | 4 +-
app/src/main/res/drawable/ic_menu_docs.xml | 4 +-
app/src/main/res/drawable/ic_menu_profile.xml | 8 +-
.../res/drawable/ic_menu_troubleshoot.xml | 2 +-
app/src/main/res/drawable/ic_nav_home.xml | 9 +
app/src/main/res/drawable/ic_nav_networks.xml | 9 +
app/src/main/res/drawable/ic_nav_peers.xml | 9 +
app/src/main/res/drawable/ic_nav_settings.xml | 9 +
app/src/main/res/drawable/ic_open_in_new.xml | 9 +
.../main/res/drawable/ic_profile_avatar.xml | 11 +
app/src/main/res/drawable/profile_chip_bg.xml | 17 +
app/src/main/res/drawable/settings_row_bg.xml | 14 +
app/src/main/res/drawable/sheet_row_bg.xml | 9 +
.../main/res/layout-w960dp/activity_main.xml | 53 ++
app/src/main/res/layout/activity_main.xml | 83 +-
app/src/main/res/layout/app_bar_main.xml | 26 -
app/src/main/res/layout/content_main.xml | 20 -
app/src/main/res/layout/fragment_about.xml | 2 +-
app/src/main/res/layout/fragment_advanced.xml | 743 +++++++++---------
.../res/layout/fragment_bottom_dialog.xml | 66 --
app/src/main/res/layout/fragment_home.xml | 115 ++-
app/src/main/res/layout/fragment_networks.xml | 7 +
app/src/main/res/layout/fragment_peers.xml | 7 +
app/src/main/res/layout/fragment_profiles.xml | 5 +-
app/src/main/res/layout/fragment_server.xml | 4 +-
app/src/main/res/layout/fragment_settings.xml | 302 +++++++
.../main/res/layout/fragment_troubleshoot.xml | 142 ++--
app/src/main/res/layout/list_item_profile.xml | 12 +-
.../res/layout/list_item_profile_picker.xml | 41 +
app/src/main/res/layout/list_item_setting.xml | 53 ++
.../res/layout/list_item_setting_divider.xml | 6 +
.../res/layout/list_item_setting_section.xml | 13 +
.../res/layout/list_item_setting_toggle.xml | 51 ++
.../res/layout/nav_custom_bottom_item.xml | 14 -
app/src/main/res/layout/nav_header_main.xml | 25 -
.../main/res/layout/sheet_profile_picker.xml | 110 +++
.../main/res/layout/sheet_theme_picker.xml | 118 +++
.../main/res/menu/activity_main_drawer.xml | 35 -
app/src/main/res/menu/bottom_nav.xml | 24 +
.../main/res/navigation/mobile_navigation.xml | 20 +-
app/src/main/res/values-night/colors.xml | 4 +
app/src/main/res/values-night/themes.xml | 7 +-
app/src/main/res/values/colors.xml | 4 +
app/src/main/res/values/dimens.xml | 2 +
app/src/main/res/values/strings.xml | 34 +-
app/src/main/res/values/themes.xml | 22 +
.../client/tool/ProfileManagerWrapper.java | 10 +-
62 files changed, 2090 insertions(+), 1322 deletions(-)
create mode 100644 app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java
delete mode 100644 app/src/main/java/io/netbird/client/ui/home/BottomDialogFragment.java
delete mode 100644 app/src/main/java/io/netbird/client/ui/home/PagerAdapter.java
create mode 100644 app/src/main/java/io/netbird/client/ui/home/ProfilePickerAdapter.java
create mode 100644 app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
create mode 100644 app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
create mode 100644 app/src/main/res/drawable/ic_add.xml
create mode 100644 app/src/main/res/drawable/ic_arrow_drop_down.xml
create mode 100644 app/src/main/res/drawable/ic_check.xml
create mode 100644 app/src/main/res/drawable/ic_chevron_right.xml
create mode 100644 app/src/main/res/drawable/ic_nav_home.xml
create mode 100644 app/src/main/res/drawable/ic_nav_networks.xml
create mode 100644 app/src/main/res/drawable/ic_nav_peers.xml
create mode 100644 app/src/main/res/drawable/ic_nav_settings.xml
create mode 100644 app/src/main/res/drawable/ic_open_in_new.xml
create mode 100644 app/src/main/res/drawable/ic_profile_avatar.xml
create mode 100644 app/src/main/res/drawable/profile_chip_bg.xml
create mode 100644 app/src/main/res/drawable/settings_row_bg.xml
create mode 100644 app/src/main/res/drawable/sheet_row_bg.xml
create mode 100644 app/src/main/res/layout-w960dp/activity_main.xml
delete mode 100644 app/src/main/res/layout/app_bar_main.xml
delete mode 100644 app/src/main/res/layout/content_main.xml
delete mode 100644 app/src/main/res/layout/fragment_bottom_dialog.xml
create mode 100644 app/src/main/res/layout/fragment_settings.xml
create mode 100644 app/src/main/res/layout/list_item_profile_picker.xml
create mode 100644 app/src/main/res/layout/list_item_setting.xml
create mode 100644 app/src/main/res/layout/list_item_setting_divider.xml
create mode 100644 app/src/main/res/layout/list_item_setting_section.xml
create mode 100644 app/src/main/res/layout/list_item_setting_toggle.xml
delete mode 100644 app/src/main/res/layout/nav_custom_bottom_item.xml
delete mode 100644 app/src/main/res/layout/nav_header_main.xml
create mode 100644 app/src/main/res/layout/sheet_profile_picker.xml
create mode 100644 app/src/main/res/layout/sheet_theme_picker.xml
delete mode 100644 app/src/main/res/menu/activity_main_drawer.xml
create mode 100644 app/src/main/res/menu/bottom_nav.xml
diff --git a/app/src/main/java/io/netbird/client/MainActivity.java b/app/src/main/java/io/netbird/client/MainActivity.java
index c7fb0b54..524a87d8 100644
--- a/app/src/main/java/io/netbird/client/MainActivity.java
+++ b/app/src/main/java/io/netbird/client/MainActivity.java
@@ -12,29 +12,28 @@
import android.os.IBinder;
import android.text.Html;
import android.util.Log;
-import android.view.KeyEvent;
+import android.util.TypedValue;
import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
-import com.google.android.material.navigation.NavigationView;
+import com.google.android.material.navigation.NavigationBarView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
-import androidx.core.view.GravityCompat;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
-import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.AppCompatActivity;
import io.netbird.client.databinding.ActivityMainBinding;
@@ -48,7 +47,7 @@
import io.netbird.gomobile.android.URLOpener;
-public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, ServiceAccessor, StateListenerRegistry {
+public class MainActivity extends AppCompatActivity implements ServiceAccessor, StateListenerRegistry {
private StateListAnimator stateAnim;
@@ -103,7 +102,7 @@ protected void onCreate(Bundle savedInstanceState) {
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
- setSupportActionBar(binding.appBarMain.toolbar);
+ setSupportActionBar(binding.toolbar);
isRunningOnTV = PlatformUtils.isAndroidTV(this);
useDeviceCodeFlow = PlatformUtils.requiresDeviceCodeFlow(this);
@@ -114,69 +113,36 @@ protected void onCreate(Bundle savedInstanceState) {
Log.i(LOGTAG, "Running on ChromeOS - using device code flow for authentication");
}
- setVersionText();
+ NavigationBarView bottomNav = (NavigationBarView) binding.bottomNav;
- DrawerLayout drawer = binding.drawerLayout;
- NavigationView navigationView = binding.navView;
-
- // Set the listener for menu item selections
- navigationView.setNavigationItemSelectedListener(this);
-
- // Update profile menu item with active profile name
- updateProfileMenuItem(navigationView);
-
- // On TV, request focus when drawer opens so D-pad navigation works
- if (isRunningOnTV) {
- drawer.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
- @Override
- public void onDrawerOpened(View drawerView) {
- // Request focus on the drawer when it opens
- navigationView.postDelayed(() -> {
- navigationView.setFocusable(true);
- navigationView.setFocusableInTouchMode(false);
-
- if (!navigationView.requestFocus()) {
- Log.d(LOGTAG, "NavigationView couldn't get focus, trying menu items");
- }
-
- // Try to find and focus the first visible menu item
- View menuView = navigationView.getChildAt(0);
- if (menuView != null) {
- View firstFocusable = menuView.findFocus();
- if (firstFocusable == null) {
- menuView.requestFocus();
- }
- }
- }, 100); // Delay to let drawer animation finish
- }
-
- @Override
- public void onDrawerClosed(View drawerView) {
- // Return focus to main content when drawer closed
- View mainContent = findViewById(R.id.nav_host_fragment_content_main);
- if (mainContent != null) {
- mainContent.requestFocus();
- }
- }
- });
- }
-
- // Passing each menu ID as a set of Ids because each
- // menu should be considered as top level destinations.
- mAppBarConfiguration = new AppBarConfiguration.Builder(
- R.id.nav_home)
- .setOpenableLayout(drawer)
- .build();
+ // All four bottom-nav destinations are top-level — no Up arrow on those.
+ final Set topLevelDestinations = new HashSet<>();
+ topLevelDestinations.add(R.id.nav_home);
+ topLevelDestinations.add(R.id.nav_peers);
+ topLevelDestinations.add(R.id.nav_networks);
+ topLevelDestinations.add(R.id.nav_settings);
+ mAppBarConfiguration = new AppBarConfiguration.Builder(topLevelDestinations).build();
navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
+ NavigationUI.setupWithNavController(bottomNav, navController);
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
- if (destination.getId() == R.id.nav_home) {
+ int destId = destination.getId();
+
+ // Hide bottom nav on first-launch onboarding so the screen is clean.
+ if (destId == R.id.firstInstallFragment) {
+ bottomNav.setVisibility(View.GONE);
+ } else {
+ bottomNav.setVisibility(View.VISIBLE);
+ }
+
+ // Top-level destinations (Home, Peers, Networks, Settings) don't need a toolbar —
+ // bottom nav already identifies the screen. Sub-screens keep the toolbar with title + Up arrow.
+ boolean isTopLevel = topLevelDestinations.contains(destId);
+ setToolbarVisible(!isTopLevel);
+
+ if (destId == R.id.nav_home) {
removeToolbarShadow();
- // Update profile menu item when returning to home (e.g., after profile switch)
- if (binding != null && binding.navView != null) {
- updateProfileMenuItem(binding.navView);
- }
} else {
resetToolbar();
}
@@ -271,15 +237,6 @@ public void onStart() {
startService();
}
- @Override
- protected void onResume() {
- super.onResume();
- // Update profile menu item when returning to MainActivity
- if (binding != null && binding.navView != null) {
- updateProfileMenuItem(binding.navView);
- }
- }
-
@Override
protected void onPause() {
super.onPause();
@@ -321,23 +278,6 @@ public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
- @Override
- public boolean onNavigationItemSelected(@NonNull MenuItem item) {
- int id = item.getItemId();
- if (id == R.id.nav_docs) {
- item.setCheckable(false);
- binding.drawerLayout.closeDrawers();
- openDocs();
- return true;
- }
-
- // Use NavigationUI which handles launchSingleTop and saveState/restoreState
- // This prevents fragment recreation and preserves state when alternating between destinations
- boolean isHandled = NavigationUI.onNavDestinationSelected(item, navController);
- binding.drawerLayout.closeDrawers();
- return isHandled;
- }
-
@Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
@@ -480,12 +420,6 @@ public void unregisterServiceStateListener(StateListener listener) {
serviceStateListeners.remove(listener);
}
- private void openDocs() {
- String url = "https://docs.netbird.io"; // Replace with the desired URL
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(intent);
- }
-
private void startService() {
Log.i(LOGTAG, "start VPN service");
Intent intent = new Intent(this, VPNService.class);
@@ -504,21 +438,43 @@ private void showFirstInstallFragment() {
}
}
+ private void setToolbarVisible(boolean visible) {
+ ViewGroup.LayoutParams lp = binding.toolbar.getLayoutParams();
+ int targetHeight;
+ if (visible) {
+ TypedValue tv = new TypedValue();
+ if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
+ targetHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
+ } else {
+ targetHeight = (int) (56 * getResources().getDisplayMetrics().density);
+ }
+ } else {
+ targetHeight = 0;
+ }
+ if (lp.height == targetHeight) {
+ return;
+ }
+ lp.height = targetHeight;
+ binding.toolbar.setLayoutParams(lp);
+ // Ensure AppBarLayout re-measures itself so the content below shifts up correctly.
+ binding.appbar.requestLayout();
+ }
+
private void removeToolbarShadow() {
- stateAnim = binding.appBarMain.appbar.getStateListAnimator();
- binding.appBarMain.appbar.setStateListAnimator(null);
- binding.appBarMain.appbar.setElevation(0f);
- binding.appBarMain.toolbar.setElevation(0);
- binding.appBarMain.toolbar.setBackground(new ColorDrawable(ContextCompat.getColor(this, R.color.nb_bg_home)));
+ stateAnim = binding.appbar.getStateListAnimator();
+ binding.appbar.setStateListAnimator(null);
+ binding.appbar.setElevation(0f);
+ binding.toolbar.setElevation(0);
+ binding.toolbar.setBackground(new ColorDrawable(ContextCompat.getColor(this, R.color.nb_bg_home)));
}
private void resetToolbar() {
if(stateAnim!=null) {
- binding.appBarMain.appbar.setStateListAnimator(stateAnim);
+ binding.appbar.setStateListAnimator(stateAnim);
}
- binding.appBarMain.appbar.setElevation(10f);
- binding.appBarMain.toolbar.setElevation(0);
- binding.appBarMain.toolbar.setBackground(new ColorDrawable(ContextCompat.getColor(this, R.color.nb_bg)));
+ binding.appbar.setElevation(10f);
+ binding.toolbar.setElevation(0);
+ binding.toolbar.setBackground(new ColorDrawable(ContextCompat.getColor(this, R.color.nb_bg)));
}
private void showAlwaysOnDialog(Runnable onDismissAction) {
@@ -542,19 +498,6 @@ private void showAlwaysOnDialog(Runnable onDismissAction) {
alertDialog.show();
}
- private void setVersionText() {
- try {
- try {
- String packageName = getPackageName();
- String versionName = getPackageManager().getPackageInfo(packageName, 0).versionName;
- binding.navVersion.setText(versionName);
- } catch (Exception e) {
- binding.navVersion.setText("");
- }
- } catch (Exception e) {
- }
- }
-
ConnectionListener connectionListener = new ConnectionListener() {
@Override
public synchronized void onAddressChanged(String fqdn, String ip) {
@@ -634,56 +577,4 @@ public void onError(String msg) {
});
}
};
-
- private void updateProfileMenuItem(NavigationView navigationView) {
- try {
- // Get active profile from ProfileManager instead of reading file
- io.netbird.client.tool.ProfileManagerWrapper profileManager =
- new io.netbird.client.tool.ProfileManagerWrapper(this);
- String activeProfile = profileManager.getActiveProfile();
- Menu menu = navigationView.getMenu();
- MenuItem profileItem = menu.findItem(R.id.nav_profiles);
- if (profileItem != null && activeProfile != null) {
- profileItem.setTitle(activeProfile);
- }
- } catch (Exception e) {
- Log.e(LOGTAG, "Failed to update profile menu item", e);
- }
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (!isRunningOnTV) {
- return super.onKeyDown(keyCode, event);
- }
- else {
- Log.d(LOGTAG, "Key pressed: " + keyCode + " (" + KeyEvent.keyCodeToString(keyCode) + "), repeat: " + event.getRepeatCount());
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
- boolean isOnHomeScreen = navController != null &&
- navController.getCurrentDestination() != null &&
- navController.getCurrentDestination().getId() == R.id.nav_home;
-
- if (event.getRepeatCount() == 0 && isOnHomeScreen && !binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
- Toast.makeText(this, R.string.tv_menu_hint, Toast.LENGTH_SHORT).show();
- }
-
- // drawer is not selectable on Android 16+, so we open via a long press of the left d-pad button instead
- if (event.getRepeatCount() > 0 && !binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
- Log.d(LOGTAG, "Long press LEFT detected - opening drawer");
- binding.drawerLayout.openDrawer(GravityCompat.START);
- binding.navView.requestFocus();
- return true;
- }
- }
-
- if (keyCode == KeyEvent.KEYCODE_BACK && binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
- Log.d(LOGTAG, "Closing drawer with BACK");
- binding.drawerLayout.closeDrawer(GravityCompat.START);
- return true;
- }
- }
-
- return super.onKeyDown(keyCode, event);
- }
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java b/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
index 3f1e2a7c..6488385f 100644
--- a/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
@@ -7,7 +7,6 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
@@ -17,13 +16,12 @@
import androidx.fragment.app.Fragment;
import io.netbird.client.R;
-import io.netbird.client.databinding.ComponentSwitchBinding;
import io.netbird.client.databinding.FragmentAdvancedBinding;
import io.netbird.client.tool.Preferences;
import io.netbird.client.tool.ProfileManagerWrapper;
-public class AdvancedFragment extends Fragment {
+public class AdvancedFragment extends Fragment implements ThemePickerSheet.OnThemeChangedListener {
private static final String hiddenKey = "********";
private static final String LOGTAG = "AdvancedFragment";
@@ -42,12 +40,9 @@ private void showReconnectionNeededWarningDialog() {
alertDialog.show();
}
- private void configureForceRelayConnectionSwitch(@NonNull ComponentSwitchBinding binding, @NonNull Preferences preferences) {
- binding.switchTitle.setText(R.string.advanced_force_relay_conn);
- binding.switchDescription.setText(R.string.advanced_force_relay_conn_desc);
-
- binding.switchControl.setChecked(preferences.isConnectionForceRelayed());
- binding.switchControl.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ private void configureForceRelayConnectionSwitch(@NonNull Preferences preferences) {
+ binding.switchForceRelayConnection.setChecked(preferences.isConnectionForceRelayed());
+ binding.switchForceRelayConnection.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
preferences.enableForcedRelayConnection();
} else {
@@ -56,11 +51,8 @@ private void configureForceRelayConnectionSwitch(@NonNull ComponentSwitchBinding
showReconnectionNeededWarningDialog();
});
-
- // Make parent layout clickable to toggle switch (for TV remote)
- binding.getRoot().setOnClickListener(v -> {
- binding.switchControl.toggle();
- });
+
+ binding.layoutForceRelayConnection.setOnClickListener(v -> binding.switchForceRelayConnection.toggle());
}
public View onCreateView(@NonNull LayoutInflater inflater,
@@ -137,11 +129,8 @@ public View onCreateView(@NonNull LayoutInflater inflater,
Toast.makeText(inflater.getContext(), "Error: " + e.toString(), Toast.LENGTH_SHORT).show();
}
});
-
- // Make parent layout clickable to toggle switch (for TV remote)
- binding.layoutRosenpas.setOnClickListener(v -> {
- binding.switchRosenpass.toggle();
- });
+
+ binding.layoutRosenpas.setOnClickListener(v -> binding.switchRosenpass.toggle());
binding.switchRosenpassPermissive.setOnCheckedChangeListener((buttonView, isChecked) -> {
goPreferences.setRosenpassPermissive(isChecked);
@@ -152,42 +141,34 @@ public View onCreateView(@NonNull LayoutInflater inflater,
Toast.makeText(inflater.getContext(), "Error: " + e, Toast.LENGTH_SHORT).show();
}
});
-
- // Make parent layout clickable to toggle switch (for TV remote)
- binding.layoutRosenpassPermissive.setOnClickListener(v -> {
- binding.switchRosenpassPermissive.toggle();
- });
- configureForceRelayConnectionSwitch(binding.layoutForceRelayConnection, preferences);
+ binding.layoutRosenpassPermissive.setOnClickListener(v -> binding.switchRosenpassPermissive.toggle());
+
+ configureForceRelayConnectionSwitch(preferences);
// Initialize engine config switches (your settings)
initializeEngineConfigSwitches();
- // Theme-picker initialisieren
+ // Theme picker row
SharedPreferences sharedPreferences = inflater.getContext().getSharedPreferences("settings", Context.MODE_PRIVATE);
int themeMode = sharedPreferences.getInt("theme_mode", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
- RadioGroup radioGroup = binding.radioGroupTheme;
- if (themeMode == AppCompatDelegate.MODE_NIGHT_NO) {
- radioGroup.check(binding.radioThemeLight.getId());
- } else if (themeMode == AppCompatDelegate.MODE_NIGHT_YES) {
- radioGroup.check(binding.radioThemeDark.getId());
- } else {
- radioGroup.check(binding.radioThemeSystem.getId());
- }
- radioGroup.setOnCheckedChangeListener((group, checkedId) -> {
- int mode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
- if (checkedId == binding.radioThemeLight.getId()) {
- mode = AppCompatDelegate.MODE_NIGHT_NO;
- } else if (checkedId == binding.radioThemeDark.getId()) {
- mode = AppCompatDelegate.MODE_NIGHT_YES;
- }
- sharedPreferences.edit().putInt("theme_mode", mode).apply();
- AppCompatDelegate.setDefaultNightMode(mode);
+ binding.themeValue.setText(ThemePickerSheet.labelFor(requireContext(), themeMode));
+
+ binding.rowTheme.setOnClickListener(v -> {
+ ThemePickerSheet sheet = new ThemePickerSheet();
+ sheet.show(getChildFragmentManager(), "ThemePickerSheet");
});
return root;
}
+ @Override
+ public void onThemeChanged(int mode) {
+ if (binding != null) {
+ binding.themeValue.setText(ThemePickerSheet.labelFor(requireContext(), mode));
+ }
+ }
+
private void initializeEngineConfigSwitches() {
try {
// Load current values from config
@@ -252,31 +233,14 @@ private void initializeEngineConfigSwitches() {
Log.e(LOGTAG, "Failed to set block inbound", e);
}
});
-
- // Make parent layouts clickable to toggle switches (for TV remote)
- binding.layoutAllowSsh.setOnClickListener(v -> {
- binding.switchAllowSsh.toggle();
- });
-
- binding.layoutBlockInbound.setOnClickListener(v -> {
- binding.switchBlockInbound.toggle();
- });
-
- binding.layoutDisableClientRoutes.setOnClickListener(v -> {
- binding.switchDisableClientRoutes.toggle();
- });
-
- binding.layoutDisableServerRoutes.setOnClickListener(v -> {
- binding.switchDisableServerRoutes.toggle();
- });
-
- binding.layoutDisableDns.setOnClickListener(v -> {
- binding.switchDisableDns.toggle();
- });
-
- binding.layoutDisableFirewall.setOnClickListener(v -> {
- binding.switchDisableFirewall.toggle();
- });
+
+ // Make parent rows clickable to toggle switches (for TV remote)
+ binding.layoutAllowSsh.setOnClickListener(v -> binding.switchAllowSsh.toggle());
+ binding.layoutBlockInbound.setOnClickListener(v -> binding.switchBlockInbound.toggle());
+ binding.layoutDisableClientRoutes.setOnClickListener(v -> binding.switchDisableClientRoutes.toggle());
+ binding.layoutDisableServerRoutes.setOnClickListener(v -> binding.switchDisableServerRoutes.toggle());
+ binding.layoutDisableDns.setOnClickListener(v -> binding.switchDisableDns.toggle());
+ binding.layoutDisableFirewall.setOnClickListener(v -> binding.switchDisableFirewall.toggle());
} catch (Exception e) {
Log.e(LOGTAG, "Failed to initialize engine config switches", e);
diff --git a/app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java b/app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java
new file mode 100644
index 00000000..02d5c65b
--- /dev/null
+++ b/app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java
@@ -0,0 +1,76 @@
+package io.netbird.client.ui.advanced;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatDelegate;
+
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
+
+import io.netbird.client.databinding.SheetThemePickerBinding;
+
+public class ThemePickerSheet extends BottomSheetDialogFragment {
+
+ public interface OnThemeChangedListener {
+ void onThemeChanged(int mode);
+ }
+
+ private SheetThemePickerBinding binding;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = SheetThemePickerBinding.inflate(inflater, container, false);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ SharedPreferences prefs = requireContext().getSharedPreferences("settings", 0);
+ int currentMode = prefs.getInt("theme_mode", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
+ renderChecks(currentMode);
+
+ binding.themeRowSystem.setOnClickListener(v -> pick(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM));
+ binding.themeRowLight.setOnClickListener(v -> pick(AppCompatDelegate.MODE_NIGHT_NO));
+ binding.themeRowDark.setOnClickListener(v -> pick(AppCompatDelegate.MODE_NIGHT_YES));
+ }
+
+ private void renderChecks(int mode) {
+ binding.themeCheckSystem.setVisibility(mode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM ? View.VISIBLE : View.INVISIBLE);
+ binding.themeCheckLight.setVisibility(mode == AppCompatDelegate.MODE_NIGHT_NO ? View.VISIBLE : View.INVISIBLE);
+ binding.themeCheckDark.setVisibility(mode == AppCompatDelegate.MODE_NIGHT_YES ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ private void pick(int mode) {
+ SharedPreferences prefs = requireContext().getSharedPreferences("settings", 0);
+ prefs.edit().putInt("theme_mode", mode).apply();
+ AppCompatDelegate.setDefaultNightMode(mode);
+ if (getParentFragment() instanceof OnThemeChangedListener) {
+ ((OnThemeChangedListener) getParentFragment()).onThemeChanged(mode);
+ }
+ dismiss();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ }
+
+ static String labelFor(@NonNull android.content.Context ctx, int mode) {
+ if (mode == AppCompatDelegate.MODE_NIGHT_NO) {
+ return ctx.getString(io.netbird.client.R.string.advanced_theme_light);
+ }
+ if (mode == AppCompatDelegate.MODE_NIGHT_YES) {
+ return ctx.getString(io.netbird.client.R.string.advanced_theme_dark);
+ }
+ return ctx.getString(io.netbird.client.R.string.advanced_theme_system);
+ }
+}
diff --git a/app/src/main/java/io/netbird/client/ui/home/BottomDialogFragment.java b/app/src/main/java/io/netbird/client/ui/home/BottomDialogFragment.java
deleted file mode 100644
index a0ed1ceb..00000000
--- a/app/src/main/java/io/netbird/client/ui/home/BottomDialogFragment.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package io.netbird.client.ui.home;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.Insets;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowMetrics;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.google.android.material.bottomsheet.BottomSheetBehavior;
-import com.google.android.material.bottomsheet.BottomSheetDialog;
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-
-import io.netbird.client.PlatformUtils;
-import io.netbird.client.R;
-import io.netbird.client.databinding.FragmentBottomDialogBinding;
-
-
-public class BottomDialogFragment extends com.google.android.material.bottomsheet.BottomSheetDialogFragment {
-
- private FragmentBottomDialogBinding binding;
- private boolean isRunningOnTV;
-
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- isRunningOnTV = PlatformUtils.isAndroidTV(requireContext());
-
- // Apply transparent background theme to the dialog
- BottomSheetDialog dialog = new BottomSheetDialog(requireContext(), R.style.BottomSheetDialogTheme);
- dialog.setOnShowListener(dialogInterface -> {
- // Check if the fragment is still attached to avoid IllegalStateException
- if (getActivity() == null || !isAdded()) {
- return;
- }
-
- FrameLayout bottomSheet = dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
- if (bottomSheet != null) {
- // Set the bottom sheet to be full screen
- BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
-
- behavior.setFitToContents(false);
-
- behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
- behavior.setSkipCollapsed(true);
- behavior.setPeekHeight(0);
-
- ViewGroup.LayoutParams params = bottomSheet.getLayoutParams();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- WindowMetrics windowMetrics = requireActivity().getWindowManager().getCurrentWindowMetrics();
- WindowInsets windowInsets = windowMetrics.getWindowInsets();
- Insets insets = windowInsets.getInsetsIgnoringVisibility(
- WindowInsets.Type.systemBars()
- );
- params.height = windowMetrics.getBounds().height() - insets.top;
- } else {
- DisplayMetrics displayMetrics = new DisplayMetrics();
- requireActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
- int screenHeight = displayMetrics.heightPixels;
- params.height = (int) (screenHeight * 0.91f);
- }
-
- bottomSheet.setLayoutParams(params);
-
- // Set the background to transparent
- bottomSheet.setBackground(new ColorDrawable(Color.TRANSPARENT));
- bottomSheet.requestLayout();
-
- // Restore dim to create overlay and enable proper touch handling
- if (dialog.getWindow() != null) {
- dialog.getWindow().setDimAmount(0.5f);
- }
- }
- });
-
- return dialog;
- }
-
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- binding = FragmentBottomDialogBinding.inflate(inflater, container, false);
- return binding.getRoot();
- }
-
-
- @SuppressLint("NonConstantResourceId")
- @Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- // Set rounded corners background on your sheet content
- view.setBackground(ContextCompat.getDrawable(requireContext(), R.drawable.rounded_top_corners));
-
- // Hide close button on TV (users will use the back button to exit)
- if (isRunningOnTV) {
- binding.buttonClose.setVisibility(View.GONE);
-
- // Make the root view focusable to prevent focus from going to elements behind it
- view.setFocusable(true);
- view.setFocusableInTouchMode(false);
-
- binding.separator.setFocusable(false);
- binding.separator.setFocusableInTouchMode(false);
- }
-
- binding.buttonClose.setOnClickListener(v -> dismiss());
-
- setupViewPager();
- }
-
- private void setupViewPager() {
- ViewPager2 viewPager = binding.peersViewPager;
- TabLayout tabLayout = binding.peersTabLayout;
-
- PagerAdapter adapter = new PagerAdapter(this, isRunningOnTV);
- viewPager.setAdapter(adapter);
-
- new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
- switch (position) {
- case 0:
- tab.setText("Peers");
- tab.setIcon(R.drawable.peers);
- break;
- case 1:
- tab.setText("Networks");
- tab.setIcon(R.drawable.networks);
- break;
- default:
- tab.setText("Tab " + position);
- }
- }).attach();
-
- if (isRunningOnTV) {
- viewPager.setFocusable(false);
- viewPager.setFocusableInTouchMode(false);
-
- tabLayout.setFocusable(true);
- tabLayout.setFocusableInTouchMode(false);
-
- tabLayout.postDelayed(() -> {
- if (!tabLayout.requestFocus()) {
- for (int i = 0; i < tabLayout.getTabCount(); i++) {
- View tabView = tabLayout.getTabAt(i).view;
- if (tabView != null && tabView.requestFocus()) {
- break;
- }
- }
- }
- }, 100);
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- WindowMetrics windowMetrics = requireActivity().getWindowManager().getCurrentWindowMetrics();
- WindowInsets windowInsets = windowMetrics.getWindowInsets();
- Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars());
- tabLayout.setPadding(
- tabLayout.getPaddingLeft(),
- tabLayout.getPaddingTop(),
- tabLayout.getPaddingRight(),
- insets.bottom
- );
- }
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- binding = null;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java b/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
index e91a725b..794e011e 100644
--- a/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
@@ -3,11 +3,10 @@
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
-import android.text.Html;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -15,19 +14,14 @@
import com.airbnb.lottie.LottieAnimationView;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
import io.netbird.client.PlatformUtils;
-import io.netbird.client.R;
import io.netbird.client.ServiceAccessor;
import io.netbird.client.StateListener;
import io.netbird.client.StateListenerRegistry;
import io.netbird.client.databinding.FragmentHomeBinding;
-import io.netbird.gomobile.android.PeerInfo;
-import io.netbird.gomobile.android.PeerInfoArray;
+import io.netbird.client.tool.ProfileManagerWrapper;
-public class HomeFragment extends Fragment implements StateListener {
+public class HomeFragment extends Fragment implements StateListener, ProfilePickerSheet.OnProfileSwitchedListener {
private FragmentHomeBinding binding;
private ServiceAccessor serviceAccessor;
@@ -40,10 +34,6 @@ public class HomeFragment extends Fragment implements StateListener {
private ButtonAnimation buttonAnimation;
private boolean isConnected;
- // serializes peer-list refreshes off the UI thread; serviceAccessor.getPeersList()
- // is a JNI call into Go that can take seconds during engine bootstrap/teardown
- private ExecutorService refreshExecutor;
-
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
@@ -68,8 +58,6 @@ public View onCreateView(@NonNull LayoutInflater inflater,
textNetworkAddress = binding.textNetworkAddress;
TextView textConnStatus = binding.textConnectionStatus;
- updatePeerCount(0,0);
-
buttonConnect = binding.btnConnect;
// Try to load the correct Lottie file for dark/light mode, fallback to light if dark is missing
boolean isDarkMode = (requireContext().getResources().getConfiguration().uiMode
@@ -104,16 +92,13 @@ public View onCreateView(@NonNull LayoutInflater inflater,
}
});
- // peers button
- FrameLayout openPanelCardView = binding.peersBtn;
- openPanelCardView.setOnClickListener(v -> {
- // Clear focus from the button to remove highlight
- v.clearFocus();
-
- BottomDialogFragment fragment = new BottomDialogFragment();
- fragment.show(getParentFragmentManager(), fragment.getTag());
+ binding.profileChip.setOnClickListener(v -> {
+ ProfilePickerSheet sheet = new ProfilePickerSheet();
+ sheet.show(getChildFragmentManager(), "ProfilePickerSheet");
});
+ updateProfileChip();
+
if (PlatformUtils.isAndroidTV(requireContext())) {
root.postDelayed(() -> {
if (buttonConnect != null && buttonConnect.isEnabled()) {
@@ -122,22 +107,38 @@ public View onCreateView(@NonNull LayoutInflater inflater,
}, 200);
}
- refreshExecutor = Executors.newSingleThreadExecutor();
stateListenerRegistry.registerServiceStateListener(this);
return root;
}
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateProfileChip();
+ }
+
+ @Override
+ public void onProfileSwitched(String newActiveName) {
+ updateProfileChip();
+ }
+
+ private void updateProfileChip() {
+ if (binding == null) return;
+ try {
+ ProfileManagerWrapper profileManager = new ProfileManagerWrapper(requireContext());
+ String activeProfile = profileManager.getActiveProfile();
+ binding.profileChipText.setText(activeProfile != null ? activeProfile : "");
+ } catch (Exception e) {
+ Log.e("HomeFragment", "Failed to read active profile", e);
+ binding.profileChipText.setText("");
+ }
+ }
+
@Override
public void onDestroyView() {
super.onDestroyView();
buttonAnimation.destroy();
stateListenerRegistry.unregisterServiceStateListener(this);
- if (refreshExecutor != null) {
- refreshExecutor.shutdown();
- refreshExecutor = null;
- }
- FrameLayout openPanelCardView = binding.peersBtn;
- openPanelCardView.setOnClickListener(null);
binding = null;
}
@@ -193,7 +194,6 @@ public void onDisconnected() {
buttonAnimation.disconnected();
buttonConnect.setEnabled(true);
});
- updatePeerCount(0, 0);
}
@Override
@@ -203,29 +203,6 @@ public void onDisconnecting() {
@Override
public void onPeersListChanged(long numberOfPeers) {
- ExecutorService executor = refreshExecutor;
- if (executor == null) {
- return;
- }
- executor.execute(() -> {
- PeerInfoArray peersList = serviceAccessor.getPeersList();
- int connected = 0;
- for (int i = 0; i < peersList.size(); i++) {
- PeerInfo peer = peersList.get(i);
- if(Status.fromLong(peer.getConnStatus()) == Status.CONNECTED) {
- connected++;
- }
- }
- updatePeerCount(connected, peersList.size());
- });
- }
-
- private void updatePeerCount(int connectedPeers, long totalPeers) {
- if(binding==null) return;
- TextView textPeersCount = binding.textOpenPanel;
- String text = getString(R.string.peers_connected, connectedPeers, totalPeers);
- textPeersCount.post(() ->
- textPeersCount.setText(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY))
- );
+ // peer count badge moved to bottom navigation; intentionally noop here
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/netbird/client/ui/home/PagerAdapter.java b/app/src/main/java/io/netbird/client/ui/home/PagerAdapter.java
deleted file mode 100644
index 8f2cf337..00000000
--- a/app/src/main/java/io/netbird/client/ui/home/PagerAdapter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package io.netbird.client.ui.home;
-
-import android.os.Bundle;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-
-public class PagerAdapter extends FragmentStateAdapter {
-
- private boolean isRunningOnTV;
-
- private static final String ARG_IS_RUNNING_ON_TV = "isRunningOnTV";
-
- public PagerAdapter(@NonNull Fragment fragment, boolean isRunningOnTV) {
- super(fragment);
- this.isRunningOnTV = isRunningOnTV;
- }
-
- @NonNull
- @Override
- public Fragment createFragment(int position) {
- Fragment fragment;
- switch (position) {
- case 0:
- fragment = new PeersFragment();
- break;
- case 1:
- fragment = new NetworksFragment();
- break;
- default:
- fragment = new PeersFragment();
- break;
- }
-
- // Pass TV flag to fragments
- Bundle args = new Bundle();
- args.putBoolean(ARG_IS_RUNNING_ON_TV, isRunningOnTV);
- fragment.setArguments(args);
-
- return fragment;
- }
-
- @Override
- public int getItemCount() {
- return 2;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/io/netbird/client/ui/home/ProfilePickerAdapter.java b/app/src/main/java/io/netbird/client/ui/home/ProfilePickerAdapter.java
new file mode 100644
index 00000000..d3665e37
--- /dev/null
+++ b/app/src/main/java/io/netbird/client/ui/home/ProfilePickerAdapter.java
@@ -0,0 +1,67 @@
+package io.netbird.client.ui.home;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+import io.netbird.client.R;
+import io.netbird.client.tool.Profile;
+
+class ProfilePickerAdapter extends RecyclerView.Adapter {
+
+ interface OnPickListener {
+ void onPick(Profile profile);
+ }
+
+ private final List profiles;
+ private final OnPickListener listener;
+
+ ProfilePickerAdapter(List profiles, OnPickListener listener) {
+ this.profiles = profiles;
+ this.listener = listener;
+ }
+
+ @NonNull
+ @Override
+ public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.list_item_profile_picker, parent, false);
+ return new VH(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull VH holder, int position) {
+ Profile profile = profiles.get(position);
+ holder.name.setText(profile.getName());
+ holder.check.setVisibility(profile.isActive() ? View.VISIBLE : View.INVISIBLE);
+ holder.dot.setBackgroundResource(profile.isActive()
+ ? R.drawable.peer_status_connected
+ : R.drawable.peer_status_disconnected);
+ holder.itemView.setOnClickListener(v -> listener.onPick(profile));
+ }
+
+ @Override
+ public int getItemCount() {
+ return profiles.size();
+ }
+
+ static class VH extends RecyclerView.ViewHolder {
+ final View dot;
+ final TextView name;
+ final ImageView check;
+
+ VH(@NonNull View itemView) {
+ super(itemView);
+ dot = itemView.findViewById(R.id.profile_picker_dot);
+ name = itemView.findViewById(R.id.profile_picker_name);
+ check = itemView.findViewById(R.id.profile_picker_check);
+ }
+ }
+}
diff --git a/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java b/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
new file mode 100644
index 00000000..e40268c9
--- /dev/null
+++ b/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
@@ -0,0 +1,175 @@
+package io.netbird.client.ui.home;
+
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.navigation.fragment.NavHostFragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.netbird.client.R;
+import io.netbird.client.databinding.SheetProfilePickerBinding;
+import io.netbird.client.tool.Profile;
+import io.netbird.client.tool.ProfileManagerWrapper;
+
+public class ProfilePickerSheet extends BottomSheetDialogFragment {
+
+ public interface OnProfileSwitchedListener {
+ void onProfileSwitched(String newActiveName);
+ }
+
+ private static final String TAG = "ProfilePickerSheet";
+
+ private SheetProfilePickerBinding binding;
+ private ProfileManagerWrapper profileManager;
+ private final List profiles = new ArrayList<>();
+ private ProfilePickerAdapter adapter;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = SheetProfilePickerBinding.inflate(inflater, container, false);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ profileManager = new ProfileManagerWrapper(requireContext());
+
+ adapter = new ProfilePickerAdapter(profiles, this::handlePickProfile);
+ RecyclerView list = binding.profilePickerList;
+ list.setLayoutManager(new LinearLayoutManager(requireContext()));
+ list.setAdapter(adapter);
+
+ binding.profilePickerAdd.setOnClickListener(v -> showAddDialog());
+
+ binding.profilePickerManage.setOnClickListener(v -> {
+ dismiss();
+ // Navigate the host activity's NavController to the manage-profiles destination.
+ NavHostFragment.findNavController(requireParentFragment())
+ .navigate(R.id.nav_profiles);
+ });
+
+ loadProfiles();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ }
+
+ private void loadProfiles() {
+ profiles.clear();
+ profiles.addAll(profileManager.listProfiles());
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+
+ private void handlePickProfile(Profile profile) {
+ if (profile.isActive()) {
+ dismiss();
+ return;
+ }
+ try {
+ profileManager.switchProfile(profile.getName());
+ Toast.makeText(requireContext(),
+ getString(R.string.profiles_success_switched, profile.getName()),
+ Toast.LENGTH_SHORT).show();
+
+ if (getParentFragment() instanceof OnProfileSwitchedListener) {
+ ((OnProfileSwitchedListener) getParentFragment()).onProfileSwitched(profile.getName());
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to switch profile", e);
+ Toast.makeText(requireContext(),
+ "Failed to switch profile: " + e.getMessage(),
+ Toast.LENGTH_SHORT).show();
+ }
+ dismiss();
+ }
+
+ 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);
+ txtTitle.setText(R.string.profiles_dialog_add_title);
+
+ TextView txtMessage = dialogView.findViewById(R.id.text_label_dialog);
+ txtMessage.setText(R.string.profiles_dialog_add_message);
+
+ EditText input = dialogView.findViewById(R.id.edit_text_dialog);
+ input.setHint(R.string.profiles_dialog_add_hint);
+
+ 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 profileName = input.getText().toString().trim();
+ if (profileName.isEmpty()) {
+ Toast.makeText(requireContext(), R.string.profiles_error_empty_name, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ String sanitized = sanitizeProfileName(profileName);
+ if (sanitized.isEmpty()) {
+ Toast.makeText(requireContext(),
+ "Profile name must contain at least one letter, digit, underscore or hyphen",
+ Toast.LENGTH_LONG).show();
+ return;
+ }
+ try {
+ profileManager.addProfile(profileName);
+ Toast.makeText(requireContext(),
+ getString(R.string.profiles_success_added, profileName),
+ Toast.LENGTH_SHORT).show();
+ loadProfiles();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to add profile", e);
+ String msg = e.getMessage();
+ if (msg != null && msg.contains("already exists")) {
+ Toast.makeText(requireContext(),
+ getString(R.string.profiles_error_already_exists, profileName),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(requireContext(),
+ "Failed to add profile: " + msg,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ dialog.dismiss();
+ });
+
+ dialog.show();
+ }
+
+ private static String sanitizeProfileName(String name) {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ if (Character.isLetterOrDigit(c) || c == '_' || c == '-') {
+ result.append(c);
+ }
+ }
+ return result.toString();
+ }
+}
diff --git a/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java b/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
new file mode 100644
index 00000000..ea0f268e
--- /dev/null
+++ b/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
@@ -0,0 +1,99 @@
+package io.netbird.client.ui.settings;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.navigation.NavController;
+import androidx.navigation.fragment.NavHostFragment;
+
+import io.netbird.client.R;
+import io.netbird.client.databinding.FragmentSettingsBinding;
+import io.netbird.client.tool.ProfileManagerWrapper;
+
+public class SettingsFragment extends Fragment {
+
+ private static final String LOGTAG = "NBSettingsFragment";
+ private static final String DOCS_URL = "https://docs.netbird.io";
+
+ private FragmentSettingsBinding binding;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = FragmentSettingsBinding.inflate(inflater, container, false);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ NavController navController = NavHostFragment.findNavController(this);
+
+ binding.rowProfiles.setOnClickListener(v ->
+ navController.navigate(R.id.nav_profiles));
+
+ binding.rowChangeServer.setOnClickListener(v ->
+ navController.navigate(R.id.nav_change_server));
+
+ binding.rowAdvanced.setOnClickListener(v ->
+ navController.navigate(R.id.nav_advanced));
+
+ binding.rowTroubleshoot.setOnClickListener(v ->
+ navController.navigate(R.id.nav_troubleshoot));
+
+ binding.rowAbout.setOnClickListener(v ->
+ navController.navigate(R.id.nav_about));
+
+ binding.rowDocumentation.setOnClickListener(v -> {
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(DOCS_URL));
+ startActivity(intent);
+ });
+
+ setVersionText();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateActiveProfileName();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ }
+
+ private void updateActiveProfileName() {
+ if (binding == null) return;
+ try {
+ ProfileManagerWrapper profileManager = new ProfileManagerWrapper(requireContext());
+ String activeProfile = profileManager.getActiveProfile();
+ binding.activeProfileName.setText(activeProfile != null ? activeProfile : "");
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Failed to read active profile", e);
+ binding.activeProfileName.setText("");
+ }
+ }
+
+ private void setVersionText() {
+ if (binding == null) return;
+ try {
+ String packageName = requireContext().getPackageName();
+ String versionName = requireContext().getPackageManager()
+ .getPackageInfo(packageName, 0).versionName;
+ binding.versionText.setText(getString(R.string.about_version) + versionName);
+ } catch (Exception e) {
+ binding.versionText.setText("");
+ }
+ }
+}
diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml
new file mode 100644
index 00000000..38d89a46
--- /dev/null
+++ b/app/src/main/res/drawable/ic_add.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_arrow_drop_down.xml b/app/src/main/res/drawable/ic_arrow_drop_down.xml
new file mode 100644
index 00000000..4a0c0a73
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_drop_down.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml
new file mode 100644
index 00000000..a82e4ad8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_check.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_chevron_right.xml b/app/src/main/res/drawable/ic_chevron_right.xml
new file mode 100644
index 00000000..fe7ffeb0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_chevron_right.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_menu_about.xml b/app/src/main/res/drawable/ic_menu_about.xml
index 8f674e76..23f72e3c 100644
--- a/app/src/main/res/drawable/ic_menu_about.xml
+++ b/app/src/main/res/drawable/ic_menu_about.xml
@@ -4,8 +4,8 @@
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
-
+
+ android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
diff --git a/app/src/main/res/drawable/ic_menu_advanced.xml b/app/src/main/res/drawable/ic_menu_advanced.xml
index 37563dd5..21651e70 100644
--- a/app/src/main/res/drawable/ic_menu_advanced.xml
+++ b/app/src/main/res/drawable/ic_menu_advanced.xml
@@ -4,8 +4,8 @@
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
-
+
+ android:pathData="M3,17v2h6v-2H3zM3,5v2h10V5H3zM13,21v-2h8v-2h-8v-2h-2v6h2zM7,9v2H3v2h4v2h2V9H7zM21,13v-2H11v2h10zM15,9h2V7h4V5h-4V3h-2v6z"/>
diff --git a/app/src/main/res/drawable/ic_menu_change_server.xml b/app/src/main/res/drawable/ic_menu_change_server.xml
index b0bc26ea..e6ee0b1e 100644
--- a/app/src/main/res/drawable/ic_menu_change_server.xml
+++ b/app/src/main/res/drawable/ic_menu_change_server.xml
@@ -4,8 +4,8 @@
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
-
+
+ android:pathData="M19,15v4H5v-4H19M19,13H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2L19,13zM7,18.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5S7.83,18.5 7,18.5zM19,5v4H5L5,5h14M19,3H5C3.9,3 3,3.9 3,5v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM7,8.5C6.17,8.5 5.5,7.83 5.5,7s0.67,-1.5 1.5,-1.5S8.5,6.17 8.5,7 7.83,8.5 7,8.5z"/>
diff --git a/app/src/main/res/drawable/ic_menu_docs.xml b/app/src/main/res/drawable/ic_menu_docs.xml
index 7173201c..1d4fc890 100644
--- a/app/src/main/res/drawable/ic_menu_docs.xml
+++ b/app/src/main/res/drawable/ic_menu_docs.xml
@@ -4,8 +4,8 @@
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
-
+
+ android:pathData="M14,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8L14,2zM18,20H6V4h7v5h5V20zM8,15h8v2H8zM8,11h8v2H8z"/>
diff --git a/app/src/main/res/drawable/ic_menu_profile.xml b/app/src/main/res/drawable/ic_menu_profile.xml
index 114cef05..524bed40 100644
--- a/app/src/main/res/drawable/ic_menu_profile.xml
+++ b/app/src/main/res/drawable/ic_menu_profile.xml
@@ -2,8 +2,10 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
- android:viewportHeight="24">
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+
+ android:fillColor="#000000"
+ android:pathData="M12,5.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S9.9,9.16 9.9,8s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1H5.9V17c0,-0.64 3.13,-2.1 6.1,-2.1M12,4C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,13c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4z"/>
diff --git a/app/src/main/res/drawable/ic_menu_troubleshoot.xml b/app/src/main/res/drawable/ic_menu_troubleshoot.xml
index 9856cc1e..45fac82c 100644
--- a/app/src/main/res/drawable/ic_menu_troubleshoot.xml
+++ b/app/src/main/res/drawable/ic_menu_troubleshoot.xml
@@ -7,5 +7,5 @@
+ android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5s-0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8H4v2h2.09C6.04,10.33 6,10.66 6,11v1H4v2h2v1c0,0.34 0.04,0.67 0.09,1H4v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3H20v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1H20V8zM16,15c0,0.22 -0.03,0.47 -0.07,0.7l-0.1,0.65 -0.37,0.65c-0.72,1.24 -2.04,2 -3.46,2s-2.74,-0.77 -3.46,-2l-0.37,-0.64 -0.1,-0.65C8.03,15.48 8,15.23 8,15v-4c0,-0.21 0.03,-0.47 0.07,-0.7l0.1,-0.65 0.37,-0.65c0.3,-0.52 0.72,-0.97 1.21,-1.31l0.57,-0.39 0.74,-0.18C11.39,7.04 11.7,7 12,7s0.62,0.04 0.95,0.12l0.68,0.16 0.61,0.42c0.5,0.34 0.91,0.78 1.21,1.31l0.38,0.65 0.1,0.65C15.97,10.53 16,10.78 16,11v4zM10,14h4v2h-4zM10,10h4v2h-4z"/>
diff --git a/app/src/main/res/drawable/ic_nav_home.xml b/app/src/main/res/drawable/ic_nav_home.xml
new file mode 100644
index 00000000..f6217a52
--- /dev/null
+++ b/app/src/main/res/drawable/ic_nav_home.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_nav_networks.xml b/app/src/main/res/drawable/ic_nav_networks.xml
new file mode 100644
index 00000000..3b2c9f15
--- /dev/null
+++ b/app/src/main/res/drawable/ic_nav_networks.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_nav_peers.xml b/app/src/main/res/drawable/ic_nav_peers.xml
new file mode 100644
index 00000000..26faa73f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_nav_peers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_nav_settings.xml b/app/src/main/res/drawable/ic_nav_settings.xml
new file mode 100644
index 00000000..8a97d126
--- /dev/null
+++ b/app/src/main/res/drawable/ic_nav_settings.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_open_in_new.xml b/app/src/main/res/drawable/ic_open_in_new.xml
new file mode 100644
index 00000000..b705126d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_open_in_new.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_profile_avatar.xml b/app/src/main/res/drawable/ic_profile_avatar.xml
new file mode 100644
index 00000000..5d2556c3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_profile_avatar.xml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/profile_chip_bg.xml b/app/src/main/res/drawable/profile_chip_bg.xml
new file mode 100644
index 00000000..b9c31083
--- /dev/null
+++ b/app/src/main/res/drawable/profile_chip_bg.xml
@@ -0,0 +1,17 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/settings_row_bg.xml b/app/src/main/res/drawable/settings_row_bg.xml
new file mode 100644
index 00000000..f2c8465c
--- /dev/null
+++ b/app/src/main/res/drawable/settings_row_bg.xml
@@ -0,0 +1,14 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
diff --git a/app/src/main/res/drawable/sheet_row_bg.xml b/app/src/main/res/drawable/sheet_row_bg.xml
new file mode 100644
index 00000000..85afe650
--- /dev/null
+++ b/app/src/main/res/drawable/sheet_row_bg.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+
+
+
diff --git a/app/src/main/res/layout-w960dp/activity_main.xml b/app/src/main/res/layout-w960dp/activity_main.xml
new file mode 100644
index 00000000..447a6190
--- /dev/null
+++ b/app/src/main/res/layout-w960dp/activity_main.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 1e23e1dc..8c82b039 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,62 +1,47 @@
-
+ tools:context=".MainActivity">
-
+ android:layout_height="wrap_content"
+ android:theme="@style/Theme.NetBird.AppBarOverlay">
-
-
-
-
-
+ android:layout_height="?attr/actionBarSize"
+ android:background="@color/nb_bg"
+ app:popupTheme="@style/Theme.NetBird.PopupOverlay" />
-
+
-
-
+
+
+
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml
deleted file mode 100644
index 7fd9cfdb..00000000
--- a/app/src/main/res/layout/app_bar_main.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
deleted file mode 100644
index 6e0ea390..00000000
--- a/app/src/main/res/layout/content_main.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml
index 508fad19..9fb6b4ac 100644
--- a/app/src/main/res/layout/fragment_about.xml
+++ b/app/src/main/res/layout/fragment_about.xml
@@ -73,7 +73,7 @@
android:id="@+id/text_rights"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="32dp"
+ android:layout_marginBottom="112dp"
android:textAlignment="center"
android:text="@string/about_rights"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/app/src/main/res/layout/fragment_advanced.xml b/app/src/main/res/layout/fragment_advanced.xml
index ad46aea4..9675626a 100644
--- a/app/src/main/res/layout/fragment_advanced.xml
+++ b/app/src/main/res/layout/fragment_advanced.xml
@@ -5,47 +5,37 @@
android:id="@+id/scr_vw_advanced"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@color/nb_bg"
+ android:clipToPadding="false"
android:fillViewport="true"
+ android:paddingBottom="@dimen/bottom_nav_inset"
tools:context=".ui.advanced.AdvancedFragment">
+ android:orientation="vertical"
+ android:paddingBottom="32dp">
-
+
+
+
-
-
-
-
+ android:background="@color/nb_bg_peers"
+ android:orientation="vertical"
+ android:paddingStart="20dp"
+ android:paddingEnd="20dp"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp">
+ android:textSize="14sp" />
+ android:textAllCaps="false" />
-
-
-
+ android:layout_marginTop="8dp"
+ android:text="@string/advanced_details"
+ android:textColor="@color/nb_txt_light"
+ android:textSize="12sp" />
+
-
+
+
-
-
+
-
+ android:layout_weight="1"
+ android:text="@string/advanced_rosenpass"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
-
+
+
-
-
+
-
+
+
+
+ android:layout_marginStart="16dp"
+ android:clickable="false"
+ android:focusable="false" />
+
+
+
+
+
+
+ android:layout_weight="1"
+ android:orientation="vertical">
-
-
-
-
-
-
-
+ android:text="@string/advanced_allow_ssh"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
-
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ android:orientation="vertical">
-
-
-
-
-
-
-
+ android:text="@string/advanced_block_inbound"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
-
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ android:orientation="vertical">
-
-
-
-
-
-
-
+ android:text="@string/advanced_disable_client_routes"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
-
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ android:orientation="vertical">
-
-
-
-
-
-
-
+ android:text="@string/advanced_disable_server_routes"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
-
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ android:orientation="vertical">
-
-
-
-
-
-
-
+ android:text="@string/advanced_disable_dns"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
-
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ android:orientation="vertical">
-
-
-
-
-
-
-
+ android:text="@string/advanced_disable_firewall"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
-
-
+ android:layout_marginStart="16dp"
+ android:clickable="false"
+ android:focusable="false" />
+
+
+
+
+
+ android:layout_weight="1"
+ android:orientation="vertical">
+ android:textSize="16sp" />
-
-
-
-
-
-
-
-
-
+ android:layout_marginTop="2dp"
+ android:text="@string/advanced_force_relay_conn_desc"
+ android:textColor="@color/nb_txt_light"
+ android:textSize="12sp" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_bottom_dialog.xml b/app/src/main/res/layout/fragment_bottom_dialog.xml
deleted file mode 100644
index 87a57a17..00000000
--- a/app/src/main/res/layout/fragment_bottom_dialog.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 2c5411e4..91a8318f 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -25,15 +25,15 @@
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="@id/bg_mask_container"
+ app:layout_constraintEnd_toEndOf="@id/bg_mask_container" />
-
+
+
+
+
+
+
+
+
@@ -144,54 +173,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
-
-
-
-
-
-
-
-
-
-
-
+ app:layout_constraintGuide_percent="0.25" />
diff --git a/app/src/main/res/layout/fragment_networks.xml b/app/src/main/res/layout/fragment_networks.xml
index 96208d1b..4c9377b9 100644
--- a/app/src/main/res/layout/fragment_networks.xml
+++ b/app/src/main/res/layout/fragment_networks.xml
@@ -4,13 +4,18 @@
android:id="@+id/fragment_peers"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@color/nb_bg_peers"
tools:context=".ui.home.NetworksFragment">
+ android:clipToPadding="false"
+ android:fillViewport="true"
+ android:paddingBottom="@dimen/bottom_nav_inset">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_troubleshoot.xml b/app/src/main/res/layout/fragment_troubleshoot.xml
index 4e04220c..d19e6a96 100644
--- a/app/src/main/res/layout/fragment_troubleshoot.xml
+++ b/app/src/main/res/layout/fragment_troubleshoot.xml
@@ -4,98 +4,112 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@color/nb_bg"
+ android:clipToPadding="false"
android:fillViewport="true"
+ android:paddingBottom="@dimen/bottom_nav_inset"
tools:context=".ui.troubleshoot.TroubleshootFragment">
+ android:orientation="vertical"
+ android:paddingBottom="32dp">
-
+
+
+
+ android:background="@drawable/settings_row_bg"
+ android:clickable="true"
+ android:focusable="true"
+ android:gravity="center_vertical"
+ android:minHeight="56dp"
+ android:orientation="horizontal"
+ android:paddingStart="20dp"
+ android:paddingEnd="16dp">
-
+ android:layout_weight="1"
+ android:text="@string/advanced_tracelog"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
+
+
+
-
+
-
-
+
-
+ android:layout_weight="1"
+ android:text="@string/troubleshoot_anonymize"
+ android:textColor="@color/nb_txt"
+ android:textSize="16sp" />
-
+
+
-
-
+
+
+
+
-
-
+ android:textAllCaps="false" />
+
diff --git a/app/src/main/res/layout/list_item_profile.xml b/app/src/main/res/layout/list_item_profile.xml
index 4233931c..a7e39dbf 100644
--- a/app/src/main/res/layout/list_item_profile.xml
+++ b/app/src/main/res/layout/list_item_profile.xml
@@ -5,6 +5,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
+ android:theme="@style/Theme.NetBird.Card"
+ app:cardBackgroundColor="@color/profile_card_background"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
@@ -17,7 +19,7 @@
android:id="@+id/icon_profile"
android:layout_width="40dp"
android:layout_height="40dp"
- android:src="@drawable/ic_menu_profile"
+ android:src="@drawable/ic_profile_avatar"
android:contentDescription="@string/menu_profiles"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -29,18 +31,16 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
- android:textSize="18sp"
- android:textStyle="bold"
- android:textColor="@color/nb_txt"
android:ellipsize="end"
android:maxLines="1"
- tools:text="default"
+ android:textAppearance="@style/TextAppearance.NetBird.ProfileName"
app:layout_constraintTop_toTopOf="@id/icon_profile"
app:layout_constraintBottom_toBottomOf="@id/icon_profile"
app:layout_constraintStart_toEndOf="@id/icon_profile"
app:layout_constraintEnd_toStartOf="@id/badge_active"
app:layout_constraintHorizontal_bias="0"
- app:layout_constraintHorizontal_chainStyle="packed" />
+ app:layout_constraintHorizontal_chainStyle="packed"
+ tools:text="default" />
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_item_setting.xml b/app/src/main/res/layout/list_item_setting.xml
new file mode 100644
index 00000000..93eb3fa0
--- /dev/null
+++ b/app/src/main/res/layout/list_item_setting.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_item_setting_divider.xml b/app/src/main/res/layout/list_item_setting_divider.xml
new file mode 100644
index 00000000..6ce558f9
--- /dev/null
+++ b/app/src/main/res/layout/list_item_setting_divider.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/app/src/main/res/layout/list_item_setting_section.xml b/app/src/main/res/layout/list_item_setting_section.xml
new file mode 100644
index 00000000..d561040c
--- /dev/null
+++ b/app/src/main/res/layout/list_item_setting_section.xml
@@ -0,0 +1,13 @@
+
+
diff --git a/app/src/main/res/layout/list_item_setting_toggle.xml b/app/src/main/res/layout/list_item_setting_toggle.xml
new file mode 100644
index 00000000..247284fd
--- /dev/null
+++ b/app/src/main/res/layout/list_item_setting_toggle.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/nav_custom_bottom_item.xml b/app/src/main/res/layout/nav_custom_bottom_item.xml
deleted file mode 100644
index e2d7feac..00000000
--- a/app/src/main/res/layout/nav_custom_bottom_item.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml
deleted file mode 100644
index 78fe4942..00000000
--- a/app/src/main/res/layout/nav_header_main.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/sheet_profile_picker.xml b/app/src/main/res/layout/sheet_profile_picker.xml
new file mode 100644
index 00000000..c22be548
--- /dev/null
+++ b/app/src/main/res/layout/sheet_profile_picker.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/sheet_theme_picker.xml b/app/src/main/res/layout/sheet_theme_picker.xml
new file mode 100644
index 00000000..d7e1b8f3
--- /dev/null
+++ b/app/src/main/res/layout/sheet_theme_picker.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml
deleted file mode 100644
index bcbd34d0..00000000
--- a/app/src/main/res/menu/activity_main_drawer.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_nav.xml b/app/src/main/res/menu/bottom_nav.xml
new file mode 100644
index 00000000..ec436a2e
--- /dev/null
+++ b/app/src/main/res/menu/bottom_nav.xml
@@ -0,0 +1,24 @@
+
+
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
index 3f749393..22ece133 100644
--- a/app/src/main/res/navigation/mobile_navigation.xml
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -12,6 +12,24 @@
android:label=""
tools:layout="@layout/fragment_home" />
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index 87a9a849..d359b8ee 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -17,7 +17,9 @@
#1C1E21
#32363D
#545961
+ #545961
#F68330
+ #26F68330
#FEFEFE
#7E858F
#545961
@@ -26,4 +28,6 @@
#545961
#F6833080
#32363D
+ @color/nb_bg
+ @color/nb_gray_light
\ No newline at end of file
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
index f4d5aa1d..58e582d2 100644
--- a/app/src/main/res/values-night/themes.xml
+++ b/app/src/main/res/values-night/themes.xml
@@ -37,9 +37,10 @@
-
-
@@ -57,4 +58,6 @@
- @color/switch_thumb_color
- @color/switch_track_color
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 8fad634b..f5bcec78 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -17,7 +17,9 @@
#eeeeee
#dadada
#ececec
+ #cfcfcf
#F58431
+ #26F58431
#454545
#7c7c7c
#4E4E4E
@@ -26,4 +28,6 @@
#FFFFFF
#89F58431
#40000000
+ #F2F2F2
+ @color/white
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index f43b7b53..dcb90e0a 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -8,4 +8,6 @@
16dp
560dp
500dp
+
+ 80dp
\ 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 d6b1f51b..be447dea 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,20 +1,27 @@
NetBird
- Open navigation drawer
- Close navigation drawer
- Android Studio
- android.studio@android.com
- Navigation header
- Settings
NetBird
Advanced
About
- Docs
Change Server
Profiles
Troubleshoot
+ Active profile
+ Add profile
+ Manage profiles
+
+ Home
+ Peers
+ Resources
+ Settings
+
+ Connection
+ Settings
+ Information
+ Documentation
+
Disconnected
background mask
connect-disconnect
@@ -70,16 +77,19 @@
Success icon
- Add a pre-shared key
+ Pre-shared key
+ Rosenpass
+ Appearance
You will only communicate with peers that use the same key.
Add a pre-shared key
Save
Pre-shared key saved successfully
Failed to save pre-shared key
Enable trace log level.
- Share logs
Upload debug bundle
Anonymize sensitive data
+ Logging
+ Debug bundle
Enable Rosenpass
Enable Rosenpass permissive mode.
Network & Security
@@ -108,7 +118,6 @@
Theme Mode
Dark
Light
- Choose the app appearance mode.
Force relay connection
Forces usage of relay when connecting to peers
exclamation mark
@@ -116,12 +125,8 @@
Using setup keys for user devices is not recommended. SSO with MFA provides stronger security, proper user-device association, and periodic re-authentication.
Invalid URL format
Device Code: %s
- Hold left directional button to open the menu
- Profile: default
- Tap to manage profiles
- Profiles
Active
Add Profile
Switch
@@ -137,7 +142,6 @@
Remove Profile
Are you sure you want to remove profile \'%s\'?\n\nThis action cannot be undone.
Profile name cannot be empty
- Profile name can only contain letters, numbers, hyphens, and underscores
Profile \'%s\' already exists
Cannot remove the active profile. Switch to another profile first.
Cannot remove the default profile
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 5a24308d..431fb430 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -61,4 +61,26 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java b/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
index abbd4699..daa51fd0 100644
--- a/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
+++ b/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
@@ -53,7 +53,15 @@ public String getActiveProfile() {
try {
return profileManager.getActiveProfile();
} catch (Exception e) {
- Log.e(TAG, "Failed to get active profile", e);
+ // First-launch / fresh install: the profile state file is empty, so the
+ // engine returns "unexpected end of JSON input". Treat this as the
+ // implicit "default" profile and don't pollute the log with stack traces.
+ String msg = e.getMessage();
+ if (msg != null && msg.contains("unexpected end of JSON input")) {
+ Log.d(TAG, "Active profile not initialised yet; falling back to default");
+ } else {
+ Log.e(TAG, "Failed to get active profile", e);
+ }
return "default";
}
}
From 5e7198c9289b16bf132eaac7c87a97b72b4c31f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:27:02 +0200
Subject: [PATCH 002/140] Hide toolbar on first-install onboarding screen
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.
---
app/src/main/java/io/netbird/client/MainActivity.java | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/io/netbird/client/MainActivity.java b/app/src/main/java/io/netbird/client/MainActivity.java
index 524a87d8..43fb935d 100644
--- a/app/src/main/java/io/netbird/client/MainActivity.java
+++ b/app/src/main/java/io/netbird/client/MainActivity.java
@@ -129,12 +129,13 @@ protected void onCreate(Bundle savedInstanceState) {
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
int destId = destination.getId();
- // Hide bottom nav on first-launch onboarding so the screen is clean.
+ // First-launch onboarding takes the whole screen — hide both nav surfaces.
if (destId == R.id.firstInstallFragment) {
bottomNav.setVisibility(View.GONE);
- } else {
- bottomNav.setVisibility(View.VISIBLE);
+ setToolbarVisible(false);
+ return;
}
+ bottomNav.setVisibility(View.VISIBLE);
// Top-level destinations (Home, Peers, Networks, Settings) don't need a toolbar —
// bottom nav already identifies the screen. Sub-screens keep the toolbar with title + Up arrow.
From 45049279aae99d9a4db000792e808c925776d8a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:27:31 +0200
Subject: [PATCH 003/140] Persist sanitized profile name when adding from
picker
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.
---
.../java/io/netbird/client/ui/home/ProfilePickerSheet.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java b/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
index e40268c9..019253af 100644
--- a/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
+++ b/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
@@ -138,9 +138,9 @@ private void showAddDialog() {
return;
}
try {
- profileManager.addProfile(profileName);
+ profileManager.addProfile(sanitized);
Toast.makeText(requireContext(),
- getString(R.string.profiles_success_added, profileName),
+ getString(R.string.profiles_success_added, sanitized),
Toast.LENGTH_SHORT).show();
loadProfiles();
} catch (Exception e) {
@@ -148,7 +148,7 @@ private void showAddDialog() {
String msg = e.getMessage();
if (msg != null && msg.contains("already exists")) {
Toast.makeText(requireContext(),
- getString(R.string.profiles_error_already_exists, profileName),
+ getString(R.string.profiles_error_already_exists, sanitized),
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(requireContext(),
From 3031950cc14dda54d14bf28ebcf290b823c1557b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:27:59 +0200
Subject: [PATCH 004/140] Guard Documentation row against missing browser
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.
---
.../netbird/client/ui/settings/SettingsFragment.java | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java b/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
index ea0f268e..0b7f673a 100644
--- a/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
@@ -1,5 +1,6 @@
package io.netbird.client.ui.settings;
+import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -7,6 +8,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -55,7 +57,14 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
binding.rowDocumentation.setOnClickListener(v -> {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(DOCS_URL));
- startActivity(intent);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(LOGTAG, "No browser available to open documentation URL", e);
+ Toast.makeText(requireContext(),
+ "No browser app available to open " + DOCS_URL,
+ Toast.LENGTH_LONG).show();
+ }
});
setVersionText();
From 628b8ae9cac7d2cdd35646ac038cc74f3633c46a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:28:45 +0200
Subject: [PATCH 005/140] Use theme attr for fill color on app-local vector
icons
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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.
---
app/src/main/res/drawable/ic_add.xml | 2 +-
app/src/main/res/drawable/ic_arrow_drop_down.xml | 2 +-
app/src/main/res/drawable/ic_check.xml | 2 +-
app/src/main/res/drawable/ic_chevron_right.xml | 2 +-
app/src/main/res/drawable/ic_nav_home.xml | 2 +-
app/src/main/res/drawable/ic_nav_networks.xml | 2 +-
app/src/main/res/drawable/ic_nav_peers.xml | 2 +-
app/src/main/res/drawable/ic_nav_settings.xml | 2 +-
app/src/main/res/drawable/ic_open_in_new.xml | 2 +-
9 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml
index 38d89a46..fc449a5b 100644
--- a/app/src/main/res/drawable/ic_add.xml
+++ b/app/src/main/res/drawable/ic_add.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/drawable/ic_arrow_drop_down.xml b/app/src/main/res/drawable/ic_arrow_drop_down.xml
index 4a0c0a73..01994684 100644
--- a/app/src/main/res/drawable/ic_arrow_drop_down.xml
+++ b/app/src/main/res/drawable/ic_arrow_drop_down.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml
index a82e4ad8..a0e2a89e 100644
--- a/app/src/main/res/drawable/ic_check.xml
+++ b/app/src/main/res/drawable/ic_check.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/drawable/ic_chevron_right.xml b/app/src/main/res/drawable/ic_chevron_right.xml
index fe7ffeb0..00d2ee4f 100644
--- a/app/src/main/res/drawable/ic_chevron_right.xml
+++ b/app/src/main/res/drawable/ic_chevron_right.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/drawable/ic_nav_home.xml b/app/src/main/res/drawable/ic_nav_home.xml
index f6217a52..723556f0 100644
--- a/app/src/main/res/drawable/ic_nav_home.xml
+++ b/app/src/main/res/drawable/ic_nav_home.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/drawable/ic_nav_networks.xml b/app/src/main/res/drawable/ic_nav_networks.xml
index 3b2c9f15..b67b7cd9 100644
--- a/app/src/main/res/drawable/ic_nav_networks.xml
+++ b/app/src/main/res/drawable/ic_nav_networks.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/drawable/ic_nav_peers.xml b/app/src/main/res/drawable/ic_nav_peers.xml
index 26faa73f..88706b97 100644
--- a/app/src/main/res/drawable/ic_nav_peers.xml
+++ b/app/src/main/res/drawable/ic_nav_peers.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/drawable/ic_nav_settings.xml b/app/src/main/res/drawable/ic_nav_settings.xml
index 8a97d126..26fb02ce 100644
--- a/app/src/main/res/drawable/ic_nav_settings.xml
+++ b/app/src/main/res/drawable/ic_nav_settings.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/drawable/ic_open_in_new.xml b/app/src/main/res/drawable/ic_open_in_new.xml
index b705126d..aea94f52 100644
--- a/app/src/main/res/drawable/ic_open_in_new.xml
+++ b/app/src/main/res/drawable/ic_open_in_new.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
From cca9cd07e40bdeb37f1622ca87538f4e225ebb5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:29:51 +0200
Subject: [PATCH 006/140] Announce theme picker selection to screen readers
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 selected" on the sheet root
so TalkBack confirms the change before the sheet dismisses.
---
.../client/ui/advanced/ThemePickerSheet.java | 19 +++++++++++++++++++
app/src/main/res/values/strings.xml | 3 +++
2 files changed, 22 insertions(+)
diff --git a/app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java b/app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java
index 02d5c65b..9efc41d0 100644
--- a/app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java
+++ b/app/src/main/java/io/netbird/client/ui/advanced/ThemePickerSheet.java
@@ -46,12 +46,31 @@ private void renderChecks(int mode) {
binding.themeCheckSystem.setVisibility(mode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM ? View.VISIBLE : View.INVISIBLE);
binding.themeCheckLight.setVisibility(mode == AppCompatDelegate.MODE_NIGHT_NO ? View.VISIBLE : View.INVISIBLE);
binding.themeCheckDark.setVisibility(mode == AppCompatDelegate.MODE_NIGHT_YES ? View.VISIBLE : View.INVISIBLE);
+
+ applyRowAccessibility(binding.themeRowSystem, mode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM,
+ getString(io.netbird.client.R.string.advanced_theme_system));
+ applyRowAccessibility(binding.themeRowLight, mode == AppCompatDelegate.MODE_NIGHT_NO,
+ getString(io.netbird.client.R.string.advanced_theme_light));
+ applyRowAccessibility(binding.themeRowDark, mode == AppCompatDelegate.MODE_NIGHT_YES,
+ getString(io.netbird.client.R.string.advanced_theme_dark));
+ }
+
+ private void applyRowAccessibility(View row, boolean selected, String label) {
+ row.setContentDescription(label);
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
+ row.setStateDescription(selected ? getString(io.netbird.client.R.string.theme_picker_selected) : null);
+ }
+ row.setSelected(selected);
}
private void pick(int mode) {
SharedPreferences prefs = requireContext().getSharedPreferences("settings", 0);
prefs.edit().putInt("theme_mode", mode).apply();
AppCompatDelegate.setDefaultNightMode(mode);
+ if (binding != null) {
+ binding.getRoot().announceForAccessibility(
+ getString(io.netbird.client.R.string.theme_picker_announce, labelFor(requireContext(), mode)));
+ }
if (getParentFragment() instanceof OnThemeChangedListener) {
((OnThemeChangedListener) getParentFragment()).onThemeChanged(mode);
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index be447dea..d19770d2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -114,6 +114,9 @@
Network & Internet settings → Advanced → Check the gear icon for all the apps listed here on this page. Disable Always On for the apps that are not NetBird.]]>
+ Selected
+ %1$s theme selected
+
System
Theme Mode
Dark
From 9055b6f746edfb3710c2e7c86a3eda47fe8861e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:30:07 +0200
Subject: [PATCH 007/140] Override bottom_nav_inset to 0dp on w960dp+
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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.
---
app/src/main/res/values-w960dp/dimens.xml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 app/src/main/res/values-w960dp/dimens.xml
diff --git a/app/src/main/res/values-w960dp/dimens.xml b/app/src/main/res/values-w960dp/dimens.xml
new file mode 100644
index 00000000..014be3fa
--- /dev/null
+++ b/app/src/main/res/values-w960dp/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 0dp
+
From e07f430086a8645ace58bbd649e053e2b56b82cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:30:27 +0200
Subject: [PATCH 008/140] Constrain profile picker name to a single line
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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.
---
app/src/main/res/layout/list_item_profile_picker.xml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/app/src/main/res/layout/list_item_profile_picker.xml b/app/src/main/res/layout/list_item_profile_picker.xml
index 1b01db15..e9380ec9 100644
--- a/app/src/main/res/layout/list_item_profile_picker.xml
+++ b/app/src/main/res/layout/list_item_profile_picker.xml
@@ -24,6 +24,8 @@
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="1"
android:textColor="@color/nb_txt"
android:textSize="16sp"
tools:text="default" />
From b28e21ef1af8cf54e6f761276f12f22cd1d21de4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:30:48 +0200
Subject: [PATCH 009/140] Reuse SettingsSectionHeader style in section template
layout
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.
---
app/src/main/res/layout/list_item_setting_section.xml | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/app/src/main/res/layout/list_item_setting_section.xml b/app/src/main/res/layout/list_item_setting_section.xml
index d561040c..42b1bdfc 100644
--- a/app/src/main/res/layout/list_item_setting_section.xml
+++ b/app/src/main/res/layout/list_item_setting_section.xml
@@ -1,13 +1,5 @@
From ab564991ea037ae58d1091a8bd09edac63b6c3e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Sun, 10 May 2026 16:31:44 +0200
Subject: [PATCH 010/140] Document why getActiveProfile uses string-match for
empty-state
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.
---
.../io/netbird/client/tool/ProfileManagerWrapper.java | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java b/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
index daa51fd0..f3151529 100644
--- a/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
+++ b/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
@@ -53,9 +53,12 @@ public String getActiveProfile() {
try {
return profileManager.getActiveProfile();
} catch (Exception e) {
- // First-launch / fresh install: the profile state file is empty, so the
- // engine returns "unexpected end of JSON input". Treat this as the
- // implicit "default" profile and don't pollute the log with stack traces.
+ // First-launch / fresh install: the profile state file exists but is empty,
+ // so the engine returns "unexpected end of JSON input" wrapped in a generic
+ // gomobile proxyerror. The wrapped error chain isn't exposed across the
+ // gomobile binding, so we have to inspect the message text — a stable
+ // string from Go's encoding/json package — to distinguish this benign
+ // case from real failures we want to log loudly.
String msg = e.getMessage();
if (msg != null && msg.contains("unexpected end of JSON input")) {
Log.d(TAG, "Active profile not initialised yet; falling back to default");
From 268d7ddf1096dab4e96ca44882fc32372f848ad3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Fri, 19 Jun 2026 05:35:02 +0200
Subject: [PATCH 011/140] Merge profile-id migration (#189) into iOS-style
redesign
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Squash-merge the four commits from PR #189 (profile-id branch) onto the
redesign branch, adapting the profile-id migration to the new bottom-nav
UI instead of the old drawer/NavigationView layout:
- getActiveProfile() now returns a Profile (with ID) instead of a String;
update SettingsFragment and HomeFragment callers to use getName().
- Drop the PR's drawer-specific MainActivity changes (updateProfileMenuItem,
drawer onKeyDown) — the redesign replaced the drawer with bottom nav.
- Graft the new disable-IPv6 switch listener into AdvancedFragment and add
the IPv6 settings row to fragment_advanced.xml in the redesign row style.
- Bump netbird submodule to 62afff6 (adds Profile.ID to the gomobile binding).
---
Readme.md | 4 +-
.../client/ui/advanced/AdvancedFragment.java | 14 ++++++
.../netbird/client/ui/home/HomeFragment.java | 5 +-
.../java/io/netbird/client/ui/home/Peer.java | 10 +++-
.../netbird/client/ui/home/PeersAdapter.java | 12 ++++-
.../ui/home/PeersFragmentViewModel.java | 2 +-
.../io/netbird/client/ui/home/Resource.java | 2 +-
.../client/ui/profile/ProfilesFragment.java | 38 ++-------------
.../client/ui/settings/SettingsFragment.java | 5 +-
app/src/main/res/layout/fragment_advanced.xml | 48 +++++++++++++++++++
app/src/main/res/menu/peer_clipboard_menu.xml | 3 ++
app/src/main/res/values/strings.xml | 3 ++
netbird | 2 +-
.../io/netbird/client/tool/EngineRunner.java | 31 ++++++------
.../java/io/netbird/client/tool/IFace.java | 31 ++++++++++--
.../client/tool/NetworkChangeNotifier.java | 3 ++
.../java/io/netbird/client/tool/Profile.java | 15 ++++--
.../client/tool/ProfileManagerWrapper.java | 33 ++++++-------
.../io/netbird/client/tool/TUNParameters.java | 4 +-
.../io/netbird/client/tool/VPNService.java | 1 +
20 files changed, 181 insertions(+), 85 deletions(-)
diff --git a/Readme.md b/Readme.md
index 95b4e57d..79f7a462 100644
--- a/Readme.md
+++ b/Readme.md
@@ -7,7 +7,7 @@
-
+
@@ -20,7 +20,7 @@
See Documentation
- Join our Slack channel
+ Join our Slack channel
diff --git a/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java b/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
index 6488385f..978f67ef 100644
--- a/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
@@ -178,6 +178,7 @@ private void initializeEngineConfigSwitches() {
binding.switchDisableFirewall.setChecked(goPreferences.getDisableFirewall());
binding.switchAllowSsh.setChecked(goPreferences.getServerSSHAllowed());
binding.switchBlockInbound.setChecked(goPreferences.getBlockInbound());
+ binding.switchDisableIpv6.setChecked(goPreferences.getDisableIPv6());
// Set up change listeners
binding.switchDisableClientRoutes.setOnCheckedChangeListener((buttonView, isChecked) -> {
@@ -234,6 +235,15 @@ private void initializeEngineConfigSwitches() {
}
});
+ binding.switchDisableIpv6.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ try {
+ goPreferences.setDisableIPv6(isChecked);
+ goPreferences.commit();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Failed to set disable IPv6", e);
+ }
+ });
+
// Make parent rows clickable to toggle switches (for TV remote)
binding.layoutAllowSsh.setOnClickListener(v -> binding.switchAllowSsh.toggle());
binding.layoutBlockInbound.setOnClickListener(v -> binding.switchBlockInbound.toggle());
@@ -242,6 +252,10 @@ private void initializeEngineConfigSwitches() {
binding.layoutDisableDns.setOnClickListener(v -> binding.switchDisableDns.toggle());
binding.layoutDisableFirewall.setOnClickListener(v -> binding.switchDisableFirewall.toggle());
+ binding.layoutDisableIpv6.setOnClickListener(v -> {
+ binding.switchDisableIpv6.toggle();
+ });
+
} catch (Exception e) {
Log.e(LOGTAG, "Failed to initialize engine config switches", e);
}
diff --git a/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java b/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
index 794e011e..b4fa38a0 100644
--- a/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
@@ -19,6 +19,7 @@
import io.netbird.client.StateListener;
import io.netbird.client.StateListenerRegistry;
import io.netbird.client.databinding.FragmentHomeBinding;
+import io.netbird.client.tool.Profile;
import io.netbird.client.tool.ProfileManagerWrapper;
public class HomeFragment extends Fragment implements StateListener, ProfilePickerSheet.OnProfileSwitchedListener {
@@ -126,8 +127,8 @@ private void updateProfileChip() {
if (binding == null) return;
try {
ProfileManagerWrapper profileManager = new ProfileManagerWrapper(requireContext());
- String activeProfile = profileManager.getActiveProfile();
- binding.profileChipText.setText(activeProfile != null ? activeProfile : "");
+ Profile activeProfile = profileManager.getActiveProfile();
+ binding.profileChipText.setText(activeProfile != null ? activeProfile.getName() : "");
} catch (Exception e) {
Log.e("HomeFragment", "Failed to read active profile", e);
binding.profileChipText.setText("");
diff --git a/app/src/main/java/io/netbird/client/ui/home/Peer.java b/app/src/main/java/io/netbird/client/ui/home/Peer.java
index 7e876c96..27ca7231 100644
--- a/app/src/main/java/io/netbird/client/ui/home/Peer.java
+++ b/app/src/main/java/io/netbird/client/ui/home/Peer.java
@@ -3,11 +3,13 @@
public class Peer {
private final Status status;
private final String ip;
+ private final String ipv6;
private final String fqdn;
- public Peer(Status status, String ip, String fqdn) {
+ public Peer(Status status, String ip, String ipv6, String fqdn) {
this.status = status;
this.ip = ip;
+ this.ipv6 = ipv6;
this.fqdn = fqdn;
}
@@ -19,7 +21,11 @@ public String getIp() {
return ip;
}
+ public String getIpv6() {
+ return ipv6;
+ }
+
public String getFqdn() {
return fqdn;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/netbird/client/ui/home/PeersAdapter.java b/app/src/main/java/io/netbird/client/ui/home/PeersAdapter.java
index 438047c2..deb44998 100644
--- a/app/src/main/java/io/netbird/client/ui/home/PeersAdapter.java
+++ b/app/src/main/java/io/netbird/client/ui/home/PeersAdapter.java
@@ -120,6 +120,9 @@ private static void showPopup(View view, Peer peer) {
PopupMenu popup = new PopupMenu(view.getContext(), view);
popup.getMenuInflater().inflate(R.menu.peer_clipboard_menu, popup.getMenu());
+ boolean hasIpv6 = peer.getIpv6() != null && !peer.getIpv6().isEmpty();
+ popup.getMenu().findItem(R.id.copy_ipv6).setVisible(hasIpv6);
+
popup.setOnMenuItemClickListener(menuItem -> {
int id = menuItem.getItemId();
if (id == R.id.copy_fqdn) {
@@ -128,6 +131,9 @@ private static void showPopup(View view, Peer peer) {
} else if (id == R.id.copy_ip) {
copyToClipboard(view.getContext(), "IP Address", peer.getIp());
return true;
+ } else if (id == R.id.copy_ipv6) {
+ copyToClipboard(view.getContext(), "IPv6 Address", peer.getIpv6());
+ return true;
}
return false;
});
@@ -165,7 +171,11 @@ public PeerViewHolder(ListItemPeerBinding binding) {
public void bind(Peer peer) {
binding.status.setText(peer.getStatus().toString());
- binding.ip.setText(peer.getIp());
+ String ipDisplay = peer.getIp();
+ if (peer.getIpv6() != null && !peer.getIpv6().isEmpty()) {
+ ipDisplay = ipDisplay + "\n" + peer.getIpv6();
+ }
+ binding.ip.setText(ipDisplay);
binding.fqdn.setText(peer.getFqdn());
if (peer.getStatus() == Status.CONNECTED) {
diff --git a/app/src/main/java/io/netbird/client/ui/home/PeersFragmentViewModel.java b/app/src/main/java/io/netbird/client/ui/home/PeersFragmentViewModel.java
index 89af502d..11fc1765 100644
--- a/app/src/main/java/io/netbird/client/ui/home/PeersFragmentViewModel.java
+++ b/app/src/main/java/io/netbird/client/ui/home/PeersFragmentViewModel.java
@@ -64,7 +64,7 @@ private List getPeers(PeerInfoArray peersInfo) {
}
status = Status.fromLong(peerInfo.getConnStatus());
- peers.add(new Peer(status, peerInfo.getIP(), peerInfo.getFQDN()));
+ peers.add(new Peer(status, peerInfo.getIP(), peerInfo.getIPv6(), peerInfo.getFQDN()));
}
return peers;
}
diff --git a/app/src/main/java/io/netbird/client/ui/home/Resource.java b/app/src/main/java/io/netbird/client/ui/home/Resource.java
index 813904fe..3a4e3217 100644
--- a/app/src/main/java/io/netbird/client/ui/home/Resource.java
+++ b/app/src/main/java/io/netbird/client/ui/home/Resource.java
@@ -36,7 +36,7 @@ public Status getStatus() {
}
public boolean isExitNode() {
- return address.equals("0.0.0.0/0");
+ return address != null && (address.contains("0.0.0.0/0") || address.contains("::/0"));
}
public boolean isSelected() {
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 f06b75dd..96c27109 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
@@ -129,35 +129,11 @@ private void showAddDialog() {
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();
}
- /**
- * Sanitizes profile name using the same rules as the go client.
- * Only keeps letters, digits, underscores, and hyphens.
- * This matches the sanitization in netbird/client/internal/profilemanager/profilemanager.go
- */
- private String sanitizeProfileName(String name) {
- StringBuilder result = new StringBuilder();
- for (int i = 0; i < name.length(); i++) {
- char c = name.charAt(i);
- if (Character.isLetterOrDigit(c) || c == '_' || c == '-') {
- result.append(c);
- }
- }
- return result.toString();
- }
private void showSwitchDialog(Profile profile) {
createDialog(
@@ -205,11 +181,7 @@ private void addProfile(String profileName) {
} catch (Exception e) {
Log.e(TAG, "Failed to add profile", e);
String errorMsg = e.getMessage();
- if (errorMsg != null && errorMsg.contains("already exists")) {
- Toast.makeText(requireContext(),
- getString(R.string.profiles_error_already_exists, profileName),
- Toast.LENGTH_SHORT).show();
- } else {
+ if (errorMsg != null) {
Toast.makeText(requireContext(),
"Failed to add profile: " + e.getMessage(),
Toast.LENGTH_SHORT).show();
@@ -220,7 +192,7 @@ private void addProfile(String profileName) {
private void switchProfile(Profile profile) {
try {
// Switch profile (VPN service will be stopped automatically in ProfileManagerWrapper)
- profileManager.switchProfile(profile.getName());
+ profileManager.switchProfile(profile.getID());
Toast.makeText(requireContext(),
getString(R.string.profiles_success_switched, profile.getName()),
@@ -241,7 +213,7 @@ private void switchProfile(Profile profile) {
private void logoutProfile(Profile profile) {
try {
// Logout from profile (VPN service will be stopped automatically if it's the active profile)
- profileManager.logoutProfile(profile.getName());
+ profileManager.logoutProfile(profile.getID());
Toast.makeText(requireContext(),
getString(R.string.profiles_success_logged_out, profile.getName()),
@@ -258,7 +230,7 @@ private void logoutProfile(Profile profile) {
private void removeProfile(Profile profile) {
try {
- if (profile.getName().equals("default")) {
+ if (profile.getID().equals("default")) {
Toast.makeText(requireContext(),
R.string.profiles_error_cannot_remove_default,
Toast.LENGTH_SHORT).show();
@@ -272,7 +244,7 @@ private void removeProfile(Profile profile) {
return;
}
- profileManager.removeProfile(profile.getName());
+ profileManager.removeProfile(profile.getID());
Toast.makeText(requireContext(),
getString(R.string.profiles_success_removed, profile.getName()),
Toast.LENGTH_SHORT).show();
diff --git a/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java b/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
index 0b7f673a..814ea886 100644
--- a/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/settings/SettingsFragment.java
@@ -18,6 +18,7 @@
import io.netbird.client.R;
import io.netbird.client.databinding.FragmentSettingsBinding;
+import io.netbird.client.tool.Profile;
import io.netbird.client.tool.ProfileManagerWrapper;
public class SettingsFragment extends Fragment {
@@ -86,8 +87,8 @@ private void updateActiveProfileName() {
if (binding == null) return;
try {
ProfileManagerWrapper profileManager = new ProfileManagerWrapper(requireContext());
- String activeProfile = profileManager.getActiveProfile();
- binding.activeProfileName.setText(activeProfile != null ? activeProfile : "");
+ Profile activeProfile = profileManager.getActiveProfile();
+ binding.activeProfileName.setText(activeProfile != null ? activeProfile.getName() : "");
} catch (Exception e) {
Log.e(LOGTAG, "Failed to read active profile", e);
binding.activeProfileName.setText("");
diff --git a/app/src/main/res/layout/fragment_advanced.xml b/app/src/main/res/layout/fragment_advanced.xml
index 9675626a..d0546209 100644
--- a/app/src/main/res/layout/fragment_advanced.xml
+++ b/app/src/main/res/layout/fragment_advanced.xml
@@ -429,6 +429,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 d19770d2..6da0c30e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -48,6 +48,7 @@
Connecting
Connected
Copy IP
+ Copy IPv6
Copy FQDN
Filter
@@ -102,6 +103,8 @@
Disables NetBird DNS configuration on this device
Disable firewall
Disables the NetBird firewall
+ Disable IPv6
+ Disables IPv6 overlay addressing on the tunnel interface
Enable SSH
Allows SSH connections to this device
Block inbound connections
diff --git a/netbird b/netbird
index b19b7464..62afff6d 160000
--- a/netbird
+++ b/netbird
@@ -1 +1 @@
-Subproject commit b19b7464eac5c58bb6a6780a033398a27f3d772f
+Subproject commit 62afff6d52f29f49184f4c0763210684193b44f8
diff --git a/tool/src/main/java/io/netbird/client/tool/EngineRunner.java b/tool/src/main/java/io/netbird/client/tool/EngineRunner.java
index 474de644..d6420d6f 100644
--- a/tool/src/main/java/io/netbird/client/tool/EngineRunner.java
+++ b/tool/src/main/java/io/netbird/client/tool/EngineRunner.java
@@ -83,7 +83,7 @@ private synchronized void runClient(@Nullable URLOpener urlOpener, boolean isAnd
try {
configurationFilePath = profileManager.getActiveConfigPath();
stateFilePath = profileManager.getActiveStateFilePath();
- String activeProfile = profileManager.getActiveProfile();
+ Profile activeProfile = profileManager.getActiveProfile();
Log.d(LOGTAG, "Initializing engine with profile: " + activeProfile);
Log.d(LOGTAG, "Config path: " + configurationFilePath);
Log.d(LOGTAG, "State path: " + stateFilePath);
@@ -94,7 +94,8 @@ private synchronized void runClient(@Nullable URLOpener urlOpener, boolean isAnd
// Create fresh PlatformFiles with current config/state paths
// This allows profile switching without recreating the entire Client
- var platformFiles = new AndroidPlatformFiles(configurationFilePath, stateFilePath, context.getCacheDir().getAbsolutePath());
+ String cacheDir = context.getCacheDir().getAbsolutePath();
+ var platformFiles = new AndroidPlatformFiles(configurationFilePath, stateFilePath, cacheDir);
Log.d(LOGTAG, "Running engine with config: " + configurationFilePath + ", state: " + stateFilePath);
try {
@@ -298,19 +299,6 @@ public void renewTUN(int fd) {
}
}
- public String debugBundle(boolean anonymize) throws Exception {
- String configPath = profileManager.getActiveConfigPath();
- String statePath = profileManager.getActiveStateFilePath();
- String cacheDir = context.getCacheDir().getAbsolutePath();
- var platformFiles = new AndroidPlatformFiles(configPath, statePath, cacheDir);
- try {
- return goClient.debugBundle(platformFiles, anonymize);
- } catch (Exception e) {
- Log.e(LOGTAG, "goClient error", e);
- throw e;
- }
- }
-
public void selectRoute(String route) throws Exception {
Log.d(LOGTAG, String.format("selecting route: %s", route));
try {
@@ -332,4 +320,17 @@ public void deselectRoute(String route) throws Exception {
throw e;
}
}
+
+ public String debugBundle(boolean anonymize) throws Exception {
+ String configPath = profileManager.getActiveConfigPath();
+ String statePath = profileManager.getActiveStateFilePath();
+ String cacheDir = context.getCacheDir().getAbsolutePath();
+ var platformFiles = new AndroidPlatformFiles(configPath, statePath, cacheDir);
+ try {
+ return goClient.debugBundle(platformFiles, anonymize);
+ } catch (Exception e) {
+ Log.e(LOGTAG, "goClient error", e);
+ throw e;
+ }
+ }
}
diff --git a/tool/src/main/java/io/netbird/client/tool/IFace.java b/tool/src/main/java/io/netbird/client/tool/IFace.java
index 918d2acb..137fe8ce 100644
--- a/tool/src/main/java/io/netbird/client/tool/IFace.java
+++ b/tool/src/main/java/io/netbird/client/tool/IFace.java
@@ -28,22 +28,26 @@ public IFace(VPNService vpnService) {
}
@Override
- public long configureInterface(String address, long mtu, String dns, String searchDomainsString, String routesString) throws Exception {
+ public long configureInterface(String address, String addressV6, long mtu, String dns, String searchDomainsString, String routesString) throws Exception {
String[] searchDomains = toSearchDomains(searchDomainsString);
LinkedList routes = toRoutes(routesString);
InetNetwork addr = InetNetwork.parse(address);
+ InetNetwork addrV6 = null;
+ if (addressV6 != null && !addressV6.isEmpty()) {
+ addrV6 = InetNetwork.parse(addressV6);
+ }
long fd = -1;
try {
- fd = createTun(addr.getAddress().getHostAddress(), addr.getMask(), (int) mtu, dns, searchDomains, routes);
+ fd = createTun(addr.getAddress().getHostAddress(), addr.getMask(), addrV6, (int) mtu, dns, searchDomains, routes);
} catch (Exception e) {
Log.e(LOGTAG, "failed to create tunnel", e);
}
// only set the currently used TUN parameters if createTun didn't throw exceptions
if (fd != -1) {
- this.vpnService.setCurrentTUNParameters(new TUNParameters(address, mtu, dns, searchDomainsString, routesString));
+ this.vpnService.setCurrentTUNParameters(new TUNParameters(address, addressV6, mtu, dns, searchDomainsString, routesString));
}
return fd;
@@ -57,9 +61,13 @@ public boolean protectSocket(int fd) {
return true;
}
- private int createTun(String ip, int prefixLength, int mtu, String dns, String[] searchDomains, LinkedList routes) throws Exception {
+ private int createTun(String ip, int prefixLength, InetNetwork addrV6, int mtu, String dns, String[] searchDomains, LinkedList routes) throws Exception {
VpnService.Builder builder = vpnService.getBuilder();
builder.addAddress(ip, prefixLength);
+ if (addrV6 != null) {
+ builder.addAddress(addrV6.getAddress().getHostAddress(), addrV6.getMask());
+ Log.d(LOGTAG, "add IPv6 address: " + addrV6.getAddress().getHostAddress() + "/" + addrV6.getMask());
+ }
builder.allowFamily(OsConstants.AF_INET);
builder.allowFamily(OsConstants.AF_INET6);
builder.setMtu(mtu);
@@ -69,6 +77,10 @@ private int createTun(String ip, int prefixLength, int mtu, String dns, String[]
Log.d(LOGTAG,"add search domain: "+ sd);
}
+ if (addrV6 == null && hasIPv4DefaultRoute(routes)) {
+ routes.add(new Route("::/0"));
+ }
+
for (Route r : routes) {
builder.addRoute(r.addr, r.prefixLength);
Log.d(LOGTAG, "add route: "+r.addr+"/"+r.prefixLength);
@@ -149,6 +161,17 @@ private String[] toSearchDomains(String searchDomains) {
return searchDomains.split(";");
}
+ // Blackhole IPv6 when the tunnel has an IPv4 default route but no IPv6
+ // address on the interface, to prevent IPv6 leaks around the tunnel.
+ private boolean hasIPv4DefaultRoute(LinkedList routes) {
+ for (Route r : routes) {
+ if ("0.0.0.0".equals(r.addr) && r.prefixLength == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private LinkedList toRoutes(String routesString) {
LinkedList routesList = new LinkedList<>();
if(routesString == null) {
diff --git a/tool/src/main/java/io/netbird/client/tool/NetworkChangeNotifier.java b/tool/src/main/java/io/netbird/client/tool/NetworkChangeNotifier.java
index f19c4221..e250092c 100644
--- a/tool/src/main/java/io/netbird/client/tool/NetworkChangeNotifier.java
+++ b/tool/src/main/java/io/netbird/client/tool/NetworkChangeNotifier.java
@@ -39,7 +39,10 @@ public void onNetworkChanged(String routes) {
@Override
public void setInterfaceIP(String ip) {
+ }
+ @Override
+ public void setInterfaceIPv6(String ip) {
}
public void addRouteChangeListener(RouteChangeListener routeChangeListener) {
diff --git a/tool/src/main/java/io/netbird/client/tool/Profile.java b/tool/src/main/java/io/netbird/client/tool/Profile.java
index db84ff02..a4c1dc7d 100644
--- a/tool/src/main/java/io/netbird/client/tool/Profile.java
+++ b/tool/src/main/java/io/netbird/client/tool/Profile.java
@@ -3,17 +3,24 @@
import java.util.Objects;
public class Profile {
+ private final String id;
private final String name;
private final boolean isActive;
- public Profile(String name, boolean isActive) {
+ public Profile(String id, String name, boolean isActive) {
if (name == null) {
throw new IllegalArgumentException("Profile name cannot be null");
}
+ if (id == null) {
+ throw new IllegalArgumentException("ID cannot be null");
+ }
+ this.id = id;
this.name = name;
this.isActive = isActive;
}
+ public String getID() {return id;}
+
public String getName() {
return name;
}
@@ -24,7 +31,7 @@ public boolean isActive() {
@Override
public String toString() {
- return name + (isActive ? " (Active)" : "");
+ return id + name + (isActive ? " (Active)" : "");
}
@Override
@@ -32,11 +39,11 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Profile profile = (Profile) o;
- return Objects.equals(name, profile.name);
+ return Objects.equals(id, profile.id);
}
@Override
public int hashCode() {
- return Objects.hash(name);
+ return Objects.hash(id);
}
}
diff --git a/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java b/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
index f3151529..5ff6ea66 100644
--- a/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
+++ b/tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
@@ -36,7 +36,7 @@ public List listProfiles() {
for (int i = 0; i < array.length(); i++) {
io.netbird.gomobile.android.Profile p = array.get(i);
if (p != null) {
- profiles.add(new Profile(p.getName(), p.getIsActive()));
+ profiles.add(new Profile(p.getID(), p.getName(), p.getIsActive()));
}
}
}
@@ -49,9 +49,10 @@ public List listProfiles() {
/**
* Gets the currently active profile name
*/
- public String getActiveProfile() {
+ public Profile getActiveProfile() {
try {
- return profileManager.getActiveProfile();
+ io.netbird.gomobile.android.Profile p = profileManager.getActiveProfile();
+ return new Profile(p.getID(), p.getName(), true);
} catch (Exception e) {
// First-launch / fresh install: the profile state file exists but is empty,
// so the engine returns "unexpected end of JSON input" wrapped in a generic
@@ -65,7 +66,7 @@ public String getActiveProfile() {
} else {
Log.e(TAG, "Failed to get active profile", e);
}
- return "default";
+ return new Profile("default", "default", true);
}
}
@@ -73,15 +74,15 @@ public String getActiveProfile() {
* Switches to a different profile
* Stops the VPN service before switching
*/
- public void switchProfile(String profileName) throws Exception {
- if (profileName == null || profileName.trim().isEmpty()) {
- throw new IllegalArgumentException("Profile name cannot be empty");
+ public void switchProfile(String id) throws Exception {
+ if (id == null || id.trim().isEmpty()) {
+ throw new IllegalArgumentException("ID cannot be empty");
}
// Stop VPN service before switching profile
stopEngine();
- profileManager.switchProfile(profileName);
+ profileManager.switchProfile(id);
}
/**
@@ -98,29 +99,29 @@ public void addProfile(String profileName) throws Exception {
* Logs out from a profile (clears authentication, requires re-login)
* Stops the VPN service if logging out from the active profile
*/
- public void logoutProfile(String profileName) throws Exception {
- if (profileName == null || profileName.trim().isEmpty()) {
+ public void logoutProfile(String id) throws Exception {
+ if (id == null) {
throw new IllegalArgumentException("Profile name cannot be empty");
}
// Check if logging out from active profile
- String activeProfile = getActiveProfile();
- if (activeProfile.equals(profileName)) {
+ Profile activeProfile = getActiveProfile();
+ if (activeProfile.getID().equals(id)) {
// Stop VPN service if logging out from active profile
stopEngine();
}
- profileManager.logoutProfile(profileName);
+ profileManager.logoutProfile(id);
}
/**
* Removes a profile
*/
- public void removeProfile(String profileName) throws Exception {
- if (profileName == null || profileName.trim().isEmpty()) {
+ public void removeProfile(String id) throws Exception {
+ if (id == null || id.trim().isEmpty()) {
throw new IllegalArgumentException("Profile name cannot be empty");
}
- profileManager.removeProfile(profileName);
+ profileManager.removeProfile(id);
}
/**
diff --git a/tool/src/main/java/io/netbird/client/tool/TUNParameters.java b/tool/src/main/java/io/netbird/client/tool/TUNParameters.java
index e5d72578..6ba8202e 100644
--- a/tool/src/main/java/io/netbird/client/tool/TUNParameters.java
+++ b/tool/src/main/java/io/netbird/client/tool/TUNParameters.java
@@ -2,13 +2,15 @@
public class TUNParameters {
String address;
+ String addressV6;
long mtu;
String dns;
String searchDomainsString;
String routesString;
- public TUNParameters(String address, long mtu, String dns, String searchDomainsString, String routesString) {
+ public TUNParameters(String address, String addressV6, long mtu, String dns, String searchDomainsString, String routesString) {
this.address = address;
+ this.addressV6 = addressV6;
this.mtu = mtu;
this.dns = dns;
this.searchDomainsString = searchDomainsString;
diff --git a/tool/src/main/java/io/netbird/client/tool/VPNService.java b/tool/src/main/java/io/netbird/client/tool/VPNService.java
index 60e809ae..83ab6124 100644
--- a/tool/src/main/java/io/netbird/client/tool/VPNService.java
+++ b/tool/src/main/java/io/netbird/client/tool/VPNService.java
@@ -317,6 +317,7 @@ private void recreateTUN(String routes) {
try {
int fd = (int)iface.configureInterface(
currentTUNParameters.address,
+ currentTUNParameters.addressV6,
currentTUNParameters.mtu,
currentTUNParameters.dns,
currentTUNParameters.searchDomainsString,
From 1f48811ced3d6a949409bf58b55a24c7024ad914 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zolt=C3=A1n=20Papp?=
Date: Fri, 19 Jun 2026 08:32:56 +0200
Subject: [PATCH 012/140] Redesign home screen in iOS style with toggle connect
button
Replace the Lottie connect button and background mask with a custom
pill-shaped SwitchMaterial toggle (white thumb, orange track when
connected), and restructure the home layout to match the iOS client:
centered profile chip, NetBird logo, status text, hostname with a
tappable IP/IPv6 detail section.
- Remove Lottie dependency, ButtonAnimation and unused JSON assets
- Add Inter and JetBrains Mono fonts; logo from the iOS client
- Hostname shown emphasized, IPv4 in the muted summary (with chevron)
- Info rows (IPv4 + IPv6) expand on tapping the summary; IPv6 row only
shown when an IPv6 address is available; copy-to-clipboard buttons
- Append ellipsis to Connecting/Disconnecting status
- Make bottom nav unselected items white in night mode
- Drop the 'profile created'/'switched to profile' success toasts
---
app/build.gradle.kts | 1 -
app/src/main/assets/button_full.json | 1 -
app/src/main/assets/button_full_dark.json | 1 -
app/src/main/assets/loading.json | 1 -
.../client/ui/home/ButtonAnimation.java | 182 -----------
.../netbird/client/ui/home/HomeFragment.java | 150 ++++++---
.../client/ui/home/ProfilePickerSheet.java | 6 -
.../client/ui/profile/ProfilesFragment.java | 7 -
app/src/main/res/color/connect_thumb_tint.xml | 6 +
app/src/main/res/color/connect_track_tint.xml | 6 +
app/src/main/res/color/tab_icon_color.xml | 2 +-
app/src/main/res/color/tab_text_color.xml | 2 +-
.../res/drawable-night-xxhdpi/bg_bottom.png | Bin 24725 -> 0 bytes
.../main/res/drawable-night/nb_logo_full.png | Bin 0 -> 9593 bytes
.../main/res/drawable-xxhdpi/bg_bottom.png | Bin 25580 -> 0 bytes
.../res/drawable/connect_switch_thumb.xml | 18 ++
.../res/drawable/connect_switch_track.xml | 9 +
app/src/main/res/drawable/ic_content_copy.xml | 10 +
app/src/main/res/drawable/info_row_bg.xml | 10 +
app/src/main/res/drawable/nb_logo_full.png | Bin 0 -> 6831 bytes
app/src/main/res/font/inter_variable.ttf | Bin 0 -> 879708 bytes
.../main/res/font/jetbrains_mono_variable.ttf | Bin 0 -> 303144 bytes
app/src/main/res/layout/fragment_home.xml | 293 +++++++++++-------
app/src/main/res/values-night/colors.xml | 15 +
app/src/main/res/values/colors.xml | 15 +
app/src/main/res/values/strings.xml | 10 +-
gradle/libs.versions.toml | 2 -
27 files changed, 387 insertions(+), 360 deletions(-)
delete mode 100644 app/src/main/assets/button_full.json
delete mode 100644 app/src/main/assets/button_full_dark.json
delete mode 100644 app/src/main/assets/loading.json
delete mode 100644 app/src/main/java/io/netbird/client/ui/home/ButtonAnimation.java
create mode 100644 app/src/main/res/color/connect_thumb_tint.xml
create mode 100644 app/src/main/res/color/connect_track_tint.xml
delete mode 100644 app/src/main/res/drawable-night-xxhdpi/bg_bottom.png
create mode 100644 app/src/main/res/drawable-night/nb_logo_full.png
delete mode 100644 app/src/main/res/drawable-xxhdpi/bg_bottom.png
create mode 100644 app/src/main/res/drawable/connect_switch_thumb.xml
create mode 100644 app/src/main/res/drawable/connect_switch_track.xml
create mode 100644 app/src/main/res/drawable/ic_content_copy.xml
create mode 100644 app/src/main/res/drawable/info_row_bg.xml
create mode 100644 app/src/main/res/drawable/nb_logo_full.png
create mode 100644 app/src/main/res/font/inter_variable.ttf
create mode 100644 app/src/main/res/font/jetbrains_mono_variable.ttf
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index febc2632..a05d8a0e 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -84,7 +84,6 @@ dependencies {
androidTestImplementation(libs.uiautomator)
androidTestImplementation(libs.test.rules)
implementation(libs.browser) // Added for CustomTabsIntent
- implementation(libs.lottie)
implementation(libs.zxing)
if (hasGoogleServicesJson) {
diff --git a/app/src/main/assets/button_full.json b/app/src/main/assets/button_full.json
deleted file mode 100644
index 896eaae4..00000000
--- a/app/src/main/assets/button_full.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.9.0","fr":29.9700012207031,"ip":0,"op":340.000013848484,"w":257,"h":256,"nm":"NetBird button","ddd":0,"assets":[{"id":"comp_0","nm":"button start connecting","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[129.533,124.035,0],"ix":2,"l":2},"a":{"a":0,"k":[45.597,36.157,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.964705944061,0.51372551918,0.1882353127,1]},{"t":45.0000018328876}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[52.608,39.099],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0.701960802078,0.701960802078,0.701960802078,1],"e":[0.952941236309,0.36862745098,0.196078446332,1]},{"t":45.0000018328876}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.248,45.377],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.964705942191,0.513725490196,0.188235309077,1]},{"t":45.0000018328876}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[32.909,36.157],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78.0000031770051,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.949019610882,0.949019610882,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78.0000031770051,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[105.052,105.052,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.827450990677,0.827450990677,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78.0000031770051,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 5 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[104.105,104.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.600000023842,0.600000023842,0.600000023842,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[104.105,104.105],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78.0000031770051,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Layer 6 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[116.664,116.664,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.600000023842,0.600000023842,0.600000023842,1],"ix":4},"o":{"a":0,"k":23,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.664,116.664],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78.0000031770051,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Layer 7 Outlines 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":44,"s":[0],"e":[100]},{"i":{"x":[0.534],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[100],"e":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[0],"e":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":87,"s":[0],"e":[100]},{"t":88.0000035843135}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[128,128,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":44,"s":[100,100,100],"e":[78,78,100]},{"i":{"x":[0.534,0.534,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":45,"s":[78,78,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":84,"s":[100,100,100],"e":[100,100,100]},{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":87,"s":[100,100,100],"e":[78,78,100]},{"t":88.0000035843135}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-70.416,0],[0,-70.416],[70.416,0],[0,70.416]],"o":[[70.416,0],[0,70.416],[-70.416,0],[0,-70.416]],"v":[[0,-127.5],[127.5,0],[0,127.5],[-127.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.952941236309,0.36862745098,0.196078446332,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128,128],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78.0000031770051,"st":0,"bm":0}]},{"id":"comp_1","nm":"connecting loop","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[129.533,124.035,0],"ix":2,"l":2},"a":{"a":0,"k":[45.597,36.157,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.964705944061,0.51372551918,0.1882353127,1]},{"t":0}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[52.608,39.099],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.701960802078,0.701960802078,0.701960802078,1],"e":[0.952941236309,0.36862745098,0.196078446332,1]},{"t":0}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.248,45.377],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.964705942191,0.513725490196,0.188235309077,1]},{"t":0}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[32.909,36.157],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":42.0000017106951,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.949019610882,0.949019610882,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":42.0000017106951,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[105.052,105.052,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.827450990677,0.827450990677,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":42.0000017106951,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 5 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[104.105,104.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.600000023842,0.600000023842,0.600000023842,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[104.105,104.105],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":42.0000017106951,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Layer 6 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[116.664,116.664,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.600000023842,0.600000023842,0.600000023842,1],"ix":4},"o":{"a":0,"k":23,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.664,116.664],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":42.0000017106951,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Layer 7 Outlines 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":-1,"s":[0],"e":[100]},{"i":{"x":[0.534],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100],"e":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":39,"s":[0],"e":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":42,"s":[0],"e":[100]},{"t":43.0000017514259}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[128,128,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":-1,"s":[100,100,100],"e":[78,78,100]},{"i":{"x":[0.534,0.534,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[78,78,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":39,"s":[100,100,100],"e":[100,100,100]},{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":42,"s":[100,100,100],"e":[78,78,100]},{"t":43.0000017514259}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-70.416,0],[0,-70.416],[70.416,0],[0,70.416]],"o":[[70.416,0],[0,70.416],[-70.416,0],[0,-70.416]],"v":[[0,-127.5],[127.5,0],[0,127.5],[-127.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.952941236309,0.36862745098,0.196078446332,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128,128],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":42.0000017106951,"st":-45.0000018328876,"bm":0}]},{"id":"comp_2","nm":"connecting to active","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[129.533,124.035,0],"ix":2,"l":2},"a":{"a":0,"k":[45.597,36.157,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.964705944061,0.51372551918,0.1882353127,1]},{"t":0}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[52.608,39.099],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.701960802078,0.701960802078,0.701960802078,1],"e":[0.952941236309,0.36862745098,0.196078446332,1]},{"t":0}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.248,45.377],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.964705942191,0.513725490196,0.188235309077,1]},{"t":0}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[32.909,36.157],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.949019610882,0.949019610882,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[105.052,105.052,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.827450990677,0.827450990677,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 5 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[104.105,104.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.600000023842,0.600000023842,0.600000023842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.952941179276,0.368627458811,0.196078434587,1]},{"t":16.0000006516934}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[104.105,104.105],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Layer 6 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[116.664,116.664,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-2,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.600000023842,0.600000023842,0.600000023842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.952941179276,0.368627458811,0.196078434587,1]},{"t":12.00000048877}],"ix":4},"o":{"a":0,"k":23,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.664,116.664],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0}]},{"id":"comp_3","nm":"button activate","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[129.533,124.035,0],"ix":2,"l":2},"a":{"a":0,"k":[45.597,36.157,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705942191,0.513725490196,0.188235309077,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[52.608,39.099],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.952941236309,0.36862745098,0.196078446332,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.248,45.377],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705942191,0.513725490196,0.188235309077,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[32.909,36.157],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":160.000006516934,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.949019610882,0.949019610882,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":170.000006924242,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[105.052,105.052,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.827450990677,0.827450990677,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":170.000006924242,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 5 Outlines 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[104.105,104.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.964705944061,0.51372551918,0.1882353127,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[104.105,104.105],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.41],"y":[0]},"t":0,"s":[0],"e":[100]},{"t":139.000005661586}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.405],"y":[0]},"t":10,"s":[0],"e":[100]},{"t":158.000006435472}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0],"e":[720]},{"t":159.000006476203}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":160.000006516934,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Layer 5 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[104.105,104.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.952941236309,0.36862745098,0.196078446332,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[104.105,104.105],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":160.000006516934,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Layer 6 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[116.664,116.664,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.95294123888,0.368627458811,0.196078449488,1],"ix":4},"o":{"a":0,"k":23,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.664,116.664],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":160.000006516934,"st":0,"bm":0}]},{"id":"comp_4","nm":"connecting to active 2","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[129.533,124.035,0],"ix":2,"l":2},"a":{"a":0,"k":[45.597,36.157,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.964705944061,0.51372551918,0.1882353127,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0.964705944061,0.51372551918,0.1882353127,1],"e":[0.600000023842,0.600000023842,0.600000023842,1]},{"t":27.0000010997325}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[52.608,39.099],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.701960802078,0.701960802078,0.701960802078,1],"e":[0.952941236309,0.36862745098,0.196078446332,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0.952941236309,0.36862745098,0.196078446332,1],"e":[0.701960802078,0.701960802078,0.701960802078,1]},{"t":27.0000010997325}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.248,45.377],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.964705942191,0.513725490196,0.188235309077,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0.964705942191,0.513725490196,0.188235309077,1],"e":[0.600000023842,0.600000023842,0.600000023842,1]},{"t":27.0000010997325}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[32.909,36.157],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.949019610882,0.949019610882,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[105.052,105.052,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[256,256],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.827450990677,0.827450990677,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 5 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[104.105,104.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-35,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.952941179276,0.368627458811,0.196078434587,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0.952941179276,0.368627458811,0.196078434587,1],"e":[0.600000023842,0.600000023842,0.600000023842,1]},{"t":10.0000004073083}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[104.105,104.105],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Layer 6 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.75,128,0],"ix":2,"l":2},"a":{"a":0,"k":[116.664,116.664,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-2,"s":[0.600000023842,0.600000023842,0.600000023842,1],"e":[0.952941179276,0.368627458811,0.196078434587,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0.952941179276,0.368627458811,0.196078434587,1],"e":[0.600000023842,0.600000023842,0.600000023842,1]},{"t":10.0000004073083}],"ix":4},"o":{"a":0,"k":23,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.664,116.664],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30.0000012219251,"st":-45.0000018328876,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"button start connecting","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.5,128,0],"ix":2,"l":2},"a":{"a":0,"k":[128.5,128,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":257,"h":256,"ip":0,"op":78.0000031770051,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"connecting loop","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.5,128,0],"ix":2,"l":2},"a":{"a":0,"k":[128.5,128,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":257,"h":256,"ip":78.0000031770051,"op":120.0000048877,"st":78.0000031770051,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"connecting to active","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.5,128,0],"ix":2,"l":2},"a":{"a":0,"k":[128.5,128,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":257,"h":256,"ip":120.0000048877,"op":150.000006109625,"st":120.0000048877,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"button activate","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.5,128,0],"ix":2,"l":2},"a":{"a":0,"k":[128.5,128,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":257,"h":256,"ip":150.000006109625,"op":310.000012626559,"st":150.000006109625,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"connecting to active 2","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.5,128,0],"ix":2,"l":2},"a":{"a":0,"k":[128.5,128,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":257,"h":256,"ip":310.000012626559,"op":340.000013848484,"st":310.000012626559,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/assets/button_full_dark.json b/app/src/main/assets/button_full_dark.json
deleted file mode 100644
index e899a7d4..00000000
--- a/app/src/main/assets/button_full_dark.json
+++ /dev/null
@@ -1 +0,0 @@
-{"nm":"NetBird button","ddd":0,"h":256,"w":257,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":0,"nm":"button start connecting","sr":1,"st":0,"op":78.0000031770051,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[128.5,128,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.5,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":257,"h":256,"refId":"comp_0","ind":1},{"ty":0,"nm":"connecting loop","sr":1,"st":78.0000031770051,"op":120.0000048877,"ip":78.0000031770051,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[128.5,128,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.5,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":257,"h":256,"refId":"comp_1","ind":2},{"ty":0,"nm":"connecting to active","sr":1,"st":120.0000048877,"op":150.000006109625,"ip":120.0000048877,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[128.5,128,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.5,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":257,"h":256,"refId":"comp_2","ind":3},{"ty":0,"nm":"button activate","sr":1,"st":150.000006109625,"op":310.000012626559,"ip":150.000006109625,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[128.5,128,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.5,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":257,"h":256,"refId":"comp_3","ind":4},{"ty":0,"nm":"connecting to active 2","sr":1,"st":310.000012626559,"op":340.000013848484,"ip":310.000012626559,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[128.5,128,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.5,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":257,"h":256,"refId":"comp_4","ind":5}],"v":"5.9.0","fr":29.9700012207031,"op":340.000013848484,"ip":0,"assets":[{"nm":"button start connecting","id":"comp_0","fr":29.9700012207031,"layers":[{"ty":4,"nm":"Layer 2 Outlines","sr":1,"st":0,"op":78.0000031770051,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[45.597,36.157,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[129.533,124.035,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":6,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]]},"ix":2}},{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 2","ix":2,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]]},"ix":2}},{"ty":"mm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Merge","nm":"Merge Paths 1","mm":1},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":10},{"s":[0.9647,0.5137,0.1882],"t":45.0000018328876}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[52.608,39.099],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 2","ix":2,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.702,0.702,0.702],"t":10},{"s":[0.9529,0.3686,0.1961],"t":45.0000018328876}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[47.248,45.377],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 3","ix":3,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":10},{"s":[0.9647,0.5137,0.1882],"t":45.0000018328876}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[32.909,36.157],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":78.0000031770051,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0941,0.102,0.1137],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"Shape Layer 2","sr":1,"st":0,"op":78.0000031770051,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[105.052,105.052,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8275,0.8275,0.8275],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"Layer 5 Outlines","sr":1,"st":0,"op":78.0000031770051,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[104.105,104.105,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"c":{"a":0,"k":[0.6,0.6,0.6],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[104.105,104.105],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":4,"nm":"Layer 6 Outlines","sr":1,"st":0,"op":78.0000031770051,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[116.664,116.664,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.6,0.6,0.6],"ix":4},"r":1,"o":{"a":0,"k":23,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[116.664,116.664],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5},{"ty":4,"nm":"Layer 7 Outlines 2","sr":1,"st":0,"op":78.0000031770051,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[128,128,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[100,100,100],"t":44},{"o":{"x":0.333,"y":0},"i":{"x":0.534,"y":1},"s":[78,78,100],"t":45},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100,100],"t":84},{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[100,100,100],"t":87},{"s":[78,78,100],"t":88.0000035843135}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":44},{"o":{"x":0.333,"y":0},"i":{"x":0.534,"y":1},"s":[100],"t":45},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":84},{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":87},{"s":[100],"t":88.0000035843135}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-70.416,0],[0,-70.416],[70.416,0],[0,70.416]],"o":[[70.416,0],[0,70.416],[-70.416,0],[0,-70.416]],"v":[[0,-127.5],[127.5,0],[0,127.5],[-127.5,0]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"c":{"a":0,"k":[0.9529,0.3686,0.1961],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[128,128],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":6}]},{"nm":"connecting loop","id":"comp_1","fr":29.9700012207031,"layers":[{"ty":4,"nm":"Layer 2 Outlines","sr":1,"st":-45.0000018328876,"op":42.0000017106951,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[45.597,36.157,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[129.533,124.035,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":6,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]]},"ix":2}},{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 2","ix":2,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]]},"ix":2}},{"ty":"mm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Merge","nm":"Merge Paths 1","mm":1},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-35},{"s":[0.9647,0.5137,0.1882],"t":0}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[52.608,39.099],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 2","ix":2,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.702,0.702,0.702],"t":-35},{"s":[0.9529,0.3686,0.1961],"t":0}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[47.248,45.377],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 3","ix":3,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-35},{"s":[0.9647,0.5137,0.1882],"t":0}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[32.909,36.157],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":-45.0000018328876,"op":42.0000017106951,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0941,0.102,0.1137],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"Shape Layer 2","sr":1,"st":-45.0000018328876,"op":42.0000017106951,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[105.052,105.052,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8275,0.8275,0.8275],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"Layer 5 Outlines","sr":1,"st":-45.0000018328876,"op":42.0000017106951,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[104.105,104.105,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"c":{"a":0,"k":[0.6,0.6,0.6],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[104.105,104.105],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":4,"nm":"Layer 6 Outlines","sr":1,"st":-45.0000018328876,"op":42.0000017106951,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[116.664,116.664,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.6,0.6,0.6],"ix":4},"r":1,"o":{"a":0,"k":23,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[116.664,116.664],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5},{"ty":4,"nm":"Layer 7 Outlines 2","sr":1,"st":-45.0000018328876,"op":42.0000017106951,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[128,128,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[100,100,100],"t":-1},{"o":{"x":0.333,"y":0},"i":{"x":0.534,"y":1},"s":[78,78,100],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100,100],"t":39},{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[100,100,100],"t":42},{"s":[78,78,100],"t":43.0000017514259}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":-1},{"o":{"x":0.333,"y":0},"i":{"x":0.534,"y":1},"s":[100],"t":0},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":39},{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":42},{"s":[100],"t":43.0000017514259}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-70.416,0],[0,-70.416],[70.416,0],[0,70.416]],"o":[[70.416,0],[0,70.416],[-70.416,0],[0,-70.416]],"v":[[0,-127.5],[127.5,0],[0,127.5],[-127.5,0]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"c":{"a":0,"k":[0.9529,0.3686,0.1961],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[128,128],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":6}]},{"nm":"connecting to active","id":"comp_2","fr":29.9700012207031,"layers":[{"ty":4,"nm":"Layer 2 Outlines","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[45.597,36.157,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[129.533,124.035,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":6,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]]},"ix":2}},{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 2","ix":2,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]]},"ix":2}},{"ty":"mm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Merge","nm":"Merge Paths 1","mm":1},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-35},{"s":[0.9647,0.5137,0.1882],"t":0}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[52.608,39.099],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 2","ix":2,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.702,0.702,0.702],"t":-35},{"s":[0.9529,0.3686,0.1961],"t":0}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[47.248,45.377],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 3","ix":3,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-35},{"s":[0.9647,0.5137,0.1882],"t":0}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[32.909,36.157],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0941,0.102,0.1137],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"Shape Layer 2","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[105.052,105.052,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8275,0.8275,0.8275],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"Layer 5 Outlines","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[104.105,104.105,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-35},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":4},{"s":[0.9529,0.3686,0.1961],"t":16.0000006516934}],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[104.105,104.105],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":4,"nm":"Layer 6 Outlines","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[116.664,116.664,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-2},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":4},{"s":[0.9529,0.3686,0.1961],"t":12.00000048877}],"ix":4},"r":1,"o":{"a":0,"k":23,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[116.664,116.664],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5}]},{"nm":"button activate","id":"comp_3","fr":29.9700012207031,"layers":[{"ty":4,"nm":"Layer 2 Outlines","sr":1,"st":0,"op":160.000006516934,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[45.597,36.157,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[129.533,124.035,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":6,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]]},"ix":2}},{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 2","ix":2,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]]},"ix":2}},{"ty":"mm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Merge","nm":"Merge Paths 1","mm":1},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9647,0.5137,0.1882],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[52.608,39.099],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 2","ix":2,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9529,0.3686,0.1961],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[47.248,45.377],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 3","ix":3,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9647,0.5137,0.1882],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[32.909,36.157],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":170.000006924242,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0941,0.102,0.1137],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"Shape Layer 2","sr":1,"st":0,"op":170.000006924242,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[105.052,105.052,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8275,0.8275,0.8275],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"Layer 5 Outlines 2","sr":1,"st":0,"op":160.000006516934,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[104.105,104.105,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"c":{"a":0,"k":[0.9647,0.5137,0.1882],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[104.105,104.105],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.405,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":10},{"s":[100],"t":158.000006435472}],"ix":2},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"s":[720],"t":159.000006476203}],"ix":3},"s":{"a":1,"k":[{"o":{"x":0.41,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":0},{"s":[100],"t":139.000005661586}],"ix":1},"m":1}],"ind":4},{"ty":4,"nm":"Layer 5 Outlines","sr":1,"st":0,"op":160.000006516934,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[104.105,104.105,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"c":{"a":0,"k":[0.9529,0.3686,0.1961],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[104.105,104.105],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5},{"ty":4,"nm":"Layer 6 Outlines","sr":1,"st":0,"op":160.000006516934,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[116.664,116.664,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9529,0.3686,0.1961],"ix":4},"r":1,"o":{"a":0,"k":23,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[116.664,116.664],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":6}]},{"nm":"connecting to active 2","id":"comp_4","fr":29.9700012207031,"layers":[{"ty":4,"nm":"Layer 2 Outlines","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[45.597,36.157,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[129.533,124.035,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":6,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.672,7.566],[0.27,32.965],[12.953,11.002],[0.272,32.965],[-38.337,32.965]]},"ix":2}},{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 2","ix":2,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[-10.95,1.012],[0,0],[0,0],[10.108,4.897],[0,0],[0,0],[-0.064,0.134]],"o":[[2.06,-3.18],[0,0],[0,0],[-2.004,-17.157],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.332,-22.468],[12.114,-32.965],[38.337,-32.965],[12.953,11.002],[-7.521,-20.408],[-7.375,-20.66],[-7.364,-20.641],[-7.258,-20.865]]},"ix":2}},{"ty":"mm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Merge","nm":"Merge Paths 1","mm":1},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-35},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.9647,0.5137,0.1882],"t":10},{"s":[0.6,0.6,0.6],"t":27.0000010997325}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[52.608,39.099],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 2","ix":2,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[10.108,4.897],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.003,-17.158]],"v":[[-2.162,-26.687],[-18.312,1.287],[5.63,26.687],[18.312,4.723]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.702,0.702,0.702],"t":-35},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.9529,0.3686,0.1961],"t":10},{"s":[0.702,0.702,0.702],"t":27.0000010997325}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[47.248,45.377],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 3","ix":3,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[-5.791,-49.891]],"o":[[0,0],[0,0],[0,0]],"v":[[19.97,35.907],[-32.659,-19.927],[32.659,13.984]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-35},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.9647,0.5137,0.1882],"t":10},{"s":[0.6,0.6,0.6],"t":27.0000010997325}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[32.909,36.157],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0941,0.102,0.1137],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"Shape Layer 2","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[105.052,105.052,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[256,256],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8275,0.8275,0.8275],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[69.593,69.593],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"Layer 5 Outlines","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[104.105,104.105,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-53.63,0],[0,-53.63],[53.63,0],[0,53.63]],"o":[[53.63,0],[0,53.63],[-53.63,0],[0,-53.63]],"v":[[0,-97.105],[97.105,0],[0,97.105],[-97.105,0]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-35},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.9529,0.3686,0.1961],"t":4},{"s":[0.6,0.6,0.6],"t":10.0000004073083}],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[104.105,104.105],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":4,"nm":"Layer 6 Outlines","sr":1,"st":-45.0000018328876,"op":30.0000012219251,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[116.664,116.664,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[128.75,128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-64.432,0],[0,-64.432],[64.432,0],[0,64.432]],"o":[[64.432,0],[0,64.432],[-64.432,0],[0,-64.432]],"v":[[0,-116.664],[116.664,0],[0,116.664],[-116.664,0]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.6,0.6,0.6],"t":-2},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.9529,0.3686,0.1961],"t":4},{"s":[0.6,0.6,0.6],"t":10.0000004073083}],"ix":4},"r":1,"o":{"a":0,"k":23,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[116.664,116.664],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5}]}]}
\ No newline at end of file
diff --git a/app/src/main/assets/loading.json b/app/src/main/assets/loading.json
deleted file mode 100644
index 909ea4f1..00000000
--- a/app/src/main/assets/loading.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.9.0","fr":29.9700012207031,"ip":0,"op":120.0000048877,"w":24,"h":24,"nm":"loading","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24,24],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[75.141,75.141],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.533],"y":[1]},"o":{"x":[0.387],"y":[0]},"t":25,"s":[0],"e":[100]},{"t":118.000004806239}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0],"e":[100]},{"t":104.000004236007}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0],"e":[720]},{"t":119.000004846969}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":120.0000048877,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/java/io/netbird/client/ui/home/ButtonAnimation.java b/app/src/main/java/io/netbird/client/ui/home/ButtonAnimation.java
deleted file mode 100644
index 9d06fc7f..00000000
--- a/app/src/main/java/io/netbird/client/ui/home/ButtonAnimation.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package io.netbird.client.ui.home;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.util.Log;
-import android.widget.TextView;
-
-import com.airbnb.lottie.LottieAnimationView;
-import com.airbnb.lottie.LottieDrawable;
-
-class ButtonAnimation {
- private LottieAnimationView btn;
- private TextView textConnStatus;
-
- private enum AnimationState {
- DISCONNECTED("Disconnected"),
- CONNECTING("Connecting"),
- CONNECTED("Connected"),
- DISCONNECTING("Disconnecting");
-
- private final String text;
- AnimationState(String text) { this.text = text; }
- }
-
- private AnimationState currentState = AnimationState.DISCONNECTED;
-
- // Frame ranges
- private static final int CONNECTING_START = 78, CONNECTING_END = 120;
- private static final int CONNECTING_FADE_OUT_START = 121, CONNECTING_FADE_OUT_END = 142;
- private static final int DISCONNECTING_FADE_IN_START = 152, DISCONNECTING_FADE_IN_END = 214;
- private static final int DISCONNECTING_LOOP_START = 215, DISCONNECTING_LOOP_END = 258;
- private static final int DISCONNECTING_FADE_OUT_START = 259, DISCONNECTING_FADE_OUT_END = 339;
-
-
- public ButtonAnimation() {
- }
-
- public void refresh(LottieAnimationView buttonConnect, TextView textConnStatus) {
- Log.i("ButtonAnimation", "refresh: "+currentState);
- btn = buttonConnect;
- this.textConnStatus = textConnStatus;
- updateText(currentState.text);
-
- switch (currentState) {
- case DISCONNECTED:
- btn.setRepeatCount(0);
- btn.setMinAndMaxFrame(DISCONNECTING_FADE_OUT_END, DISCONNECTING_FADE_OUT_END);
- btn.playAnimation();
- break;
-
- case CONNECTING:
- btn.setRepeatCount(LottieDrawable.INFINITE);
- btn.setMinAndMaxFrame(CONNECTING_START, CONNECTING_END);
- btn.playAnimation();
- break;
-
- case CONNECTED:
- btn.setRepeatCount(0);
- btn.setMinAndMaxFrame(CONNECTING_FADE_OUT_END, CONNECTING_FADE_OUT_END);
- btn.playAnimation();
- break;
-
- case DISCONNECTING:
- btn.setRepeatCount(LottieDrawable.INFINITE);
- btn.setMinAndMaxFrame(DISCONNECTING_LOOP_START, DISCONNECTING_LOOP_END);
- btn.playAnimation();
- break;
- }
- }
-
- public void destroy() {
- Log.d("ButtonAnimation", currentState+" -> destroy ");
- btn.cancelAnimation();
- btn.removeAllAnimatorListeners();
- btn.setImageDrawable(null);
- }
-
- public void connecting() {
- Log.d("ButtonAnimation", currentState+" -> connecting ");
- if (currentState == AnimationState.CONNECTING)
- return;
-
- // Go send invalid connecting state for a moment
- if (currentState == AnimationState.DISCONNECTING)
- return;
-
- currentState = AnimationState.CONNECTING;
- updateText(AnimationState.CONNECTING.text);
-
- btn.removeAllAnimatorListeners();
- btn.setMinAndMaxFrame(CONNECTING_START, CONNECTING_END);
- btn.setRepeatCount(LottieDrawable.INFINITE);
- btn.playAnimation();
- }
-
- public void connected() {
- Log.d("ButtonAnimation", currentState+" -> connected ");
- if (currentState == AnimationState.CONNECTED) return;
-
- updateText(AnimationState.CONNECTED.text);
-
- btn.removeAllAnimatorListeners();
-
- if (!btn.isAnimating()) {
- // when we switch the fragment and the animation is not running
- currentState = AnimationState.CONNECTED;
- btn.setMinAndMaxFrame(CONNECTING_FADE_OUT_END, CONNECTING_FADE_OUT_END);
- btn.setRepeatCount(0);
- btn.playAnimation();
- } else {
- // Wait for current animation to end, then start the connected animation
- btn.setRepeatCount(0);
- btn.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- btn.removeAnimatorListener(this);
- currentState = AnimationState.CONNECTED;
- btn.setMinAndMaxFrame(CONNECTING_FADE_OUT_START, CONNECTING_FADE_OUT_END);
- btn.setRepeatCount(0);
- btn.playAnimation();
- }
- });
- }
- }
-
- public void disconnecting() {
- Log.d("ButtonAnimation", currentState+" -> disconnecting ");
- if (currentState == AnimationState.DISCONNECTING) return;
-
- currentState = AnimationState.DISCONNECTING;
- updateText(AnimationState.DISCONNECTING.text);
-
- btn.removeAllAnimatorListeners();
- btn.setRepeatCount(0);
- btn.setMinAndMaxFrame(DISCONNECTING_FADE_IN_START, DISCONNECTING_FADE_IN_END);
- btn.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- btn.removeAnimatorListener(this);
- btn.setMinAndMaxFrame(DISCONNECTING_LOOP_START, DISCONNECTING_LOOP_END);
- btn.setRepeatCount(LottieDrawable.INFINITE);
- btn.playAnimation();
- }
- });
-
- btn.playAnimation();
- }
-
- public void disconnected() {
- Log.d("ButtonAnimation", currentState+" -> disconnected ");
- if (currentState == AnimationState.DISCONNECTED)
- return;
-
- updateText(AnimationState.DISCONNECTED.text);
-
- btn.removeAllAnimatorListeners();
- if(currentState == AnimationState.CONNECTING) {
- currentState = AnimationState.DISCONNECTED;
- btn.setRepeatCount(0);
- btn.setMinAndMaxFrame(DISCONNECTING_FADE_OUT_END, DISCONNECTING_FADE_OUT_END);
- btn.playAnimation();
- return;
- }
-
- currentState = AnimationState.DISCONNECTED;
- btn.setRepeatCount(0);
- btn.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- btn.removeAllAnimatorListeners();
- btn.setRepeatCount(0);
- btn.setMinAndMaxFrame(DISCONNECTING_FADE_OUT_START, DISCONNECTING_FADE_OUT_END);
- btn.playAnimation();
- }
- });
- }
-
- private void updateText(String text) {
- Log.i("ButtonAnimation", "set text: "+text);
- textConnStatus.post(() -> textConnStatus.setText(text));
- }
-}
diff --git a/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java b/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
index b4fa38a0..0dc13bf3 100644
--- a/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/home/HomeFragment.java
@@ -1,20 +1,24 @@
package io.netbird.client.ui.home;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.content.Context;
-import android.content.res.Configuration;
import android.os.Bundle;
+import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
-import com.airbnb.lottie.LottieAnimationView;
+import com.google.android.material.switchmaterial.SwitchMaterial;
import io.netbird.client.PlatformUtils;
+import io.netbird.client.R;
import io.netbird.client.ServiceAccessor;
import io.netbird.client.StateListener;
import io.netbird.client.StateListenerRegistry;
@@ -30,9 +34,10 @@ public class HomeFragment extends Fragment implements StateListener, ProfilePick
private TextView textHostname;
private TextView textNetworkAddress;
+ private TextView textIpAddress;
+ private TextView textConnStatus;
- private LottieAnimationView buttonConnect;
- private ButtonAnimation buttonAnimation;
+ private SwitchMaterial buttonConnect;
private boolean isConnected;
@Override
@@ -57,25 +62,14 @@ public View onCreateView(@NonNull LayoutInflater inflater,
textHostname = binding.textHostname;
textNetworkAddress = binding.textNetworkAddress;
- TextView textConnStatus = binding.textConnectionStatus;
+ textIpAddress = binding.textIpAddress;
+ textConnStatus = binding.textConnectionStatus;
buttonConnect = binding.btnConnect;
- // Try to load the correct Lottie file for dark/light mode, fallback to light if dark is missing
- boolean isDarkMode = (requireContext().getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
- String lottieFile = isDarkMode ? "button_full_dark.json" : "button_full.json";
- try {
- buttonConnect.setAnimation(lottieFile);
- } catch (Exception e) {
- // fallback to light mode animation if dark mode file is missing or invalid
- buttonConnect.setAnimation("button_full.json");
- }
-
- if(buttonAnimation == null) {
- buttonAnimation = new ButtonAnimation();
- }
- buttonAnimation.refresh(buttonConnect, textConnStatus);
+ // Toggle taps drive the connection. We use a click listener rather than a
+ // checked-change listener so that programmatic state updates coming from the
+ // service (connected/disconnected callbacks) don't trigger a connection switch.
buttonConnect.setOnClickListener(v -> {
if (serviceAccessor == null) {
return;
@@ -84,15 +78,21 @@ public View onCreateView(@NonNull LayoutInflater inflater,
if (isConnected) {
// We're currently connected, so disconnect
buttonConnect.setEnabled(false);
- buttonAnimation.disconnecting();
+ setStatusText(R.string.main_status_disconnecting);
serviceAccessor.switchConnection(false);
} else {
// We're currently disconnected, so connect
- buttonAnimation.connecting();
+ setStatusText(R.string.main_status_connecting);
serviceAccessor.switchConnection(true);
}
});
+ binding.btnCopyIp.setOnClickListener(v -> copyToClipboard(textIpAddress.getText()));
+ binding.btnCopySecondary.setOnClickListener(v -> copyToClipboard(binding.textSecondaryValue.getText()));
+
+ // Tapping the address summary expands/collapses the detailed info rows.
+ binding.networkAddressSummary.setOnClickListener(v -> toggleInfoRows());
+
binding.profileChip.setOnClickListener(v -> {
ProfilePickerSheet sheet = new ProfilePickerSheet();
sheet.show(getChildFragmentManager(), "ProfilePickerSheet");
@@ -135,12 +135,56 @@ private void updateProfileChip() {
}
}
+ private void toggleInfoRows() {
+ if (binding == null) return;
+ boolean expand = binding.infoRows.getVisibility() != View.VISIBLE;
+ binding.infoRows.setVisibility(expand ? View.VISIBLE : View.GONE);
+ binding.infoRowsChevron.animate().rotation(expand ? 180f : 0f).setDuration(150).start();
+ }
+
+ private void copyToClipboard(CharSequence value) {
+ Context ctx = getContext();
+ if (ctx == null || value == null) return;
+ String text = value.toString().trim();
+ // Don't copy the empty-state placeholder.
+ if (TextUtils.isEmpty(text) || getString(R.string.main_value_empty).equals(text)) {
+ return;
+ }
+ ClipboardManager clipboard = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE);
+ if (clipboard == null) return;
+ clipboard.setPrimaryClip(ClipData.newPlainText("NetBird", text));
+ Toast.makeText(ctx, R.string.main_copied, Toast.LENGTH_SHORT).show();
+ }
+
+ private void setStatusText(int resId) {
+ if (textConnStatus == null) return;
+ textConnStatus.post(() -> {
+ if (textConnStatus != null) {
+ textConnStatus.setText(resId);
+ }
+ });
+ }
+
+ private void setToggle(boolean checked, boolean enabled, int statusResId) {
+ if (buttonConnect == null) return;
+ buttonConnect.post(() -> {
+ if (buttonConnect == null) return;
+ buttonConnect.setChecked(checked);
+ buttonConnect.setEnabled(enabled);
+ setStatusText(statusResId);
+ });
+ }
+
@Override
public void onDestroyView() {
super.onDestroyView();
- buttonAnimation.destroy();
stateListenerRegistry.unregisterServiceStateListener(this);
binding = null;
+ buttonConnect = null;
+ textConnStatus = null;
+ textHostname = null;
+ textNetworkAddress = null;
+ textIpAddress = null;
}
@Override
@@ -157,49 +201,71 @@ public void onEngineStarted() {
@Override
public void onEngineStopped() {
isConnected = false;
- buttonConnect.post(() -> {
- buttonAnimation.disconnected();
- buttonConnect.setEnabled(true);
- });
+ setToggle(false, true, R.string.main_status_disconnected);
}
@Override
- public void onAddressChanged(String netAddr, String hostname) {
- if(textNetworkAddress == null || textHostname == null) {
+ public void onAddressChanged(String fqdn, String ip) {
+ if (binding == null) {
return;
}
- textNetworkAddress.post(() -> textNetworkAddress.setText(netAddr));
- textHostname.post(() -> textHostname.setText(hostname));
+ // The engine packs the addresses as "IPv4\nIPv6" when an IPv6 address is
+ // available (see Status.UpdateLocalPeerState); otherwise it's just the IPv4.
+ String ipv4 = "";
+ String ipv6 = "";
+ if (!TextUtils.isEmpty(ip)) {
+ String[] parts = ip.split("\n", 2);
+ ipv4 = parts[0].trim();
+ if (parts.length > 1) {
+ ipv6 = parts[1].trim();
+ }
+ }
+
+ final String fIpv4 = ipv4;
+ final String fIpv6 = ipv6;
+ final boolean hasIpv4 = !TextUtils.isEmpty(fIpv4);
+ binding.getRoot().post(() -> {
+ if (binding == null) return;
+ // Emphasized line shows the hostname (fqdn); muted summary shows the IPv4 address.
+ binding.textHostname.setText(fqdn);
+ binding.textNetworkAddress.setText(fIpv4);
+ // Primary info row shows the IPv4 address.
+ binding.textIpAddress.setText(fIpv4);
+ // Secondary info row shows the IPv6 address only when one is available.
+ boolean hasIpv6 = !TextUtils.isEmpty(fIpv6);
+ binding.textSecondaryValue.setText(hasIpv6 ? fIpv6 : "");
+ binding.secondaryValueRow.setVisibility(hasIpv6 ? View.VISIBLE : View.GONE);
+ // Only show the muted address summary (with chevron) when we have an address.
+ binding.networkAddressSummary.setVisibility(hasIpv4 ? View.VISIBLE : View.GONE);
+ // Without an address there's nothing to expand: collapse the info rows and reset the chevron.
+ if (!hasIpv4) {
+ binding.infoRows.setVisibility(View.GONE);
+ binding.infoRowsChevron.setRotation(0f);
+ }
+ });
}
@Override
public void onConnected() {
isConnected = true;
-
- buttonConnect.post(() -> {
- buttonAnimation.connected();
- buttonConnect.setEnabled(true);
- });
+ setToggle(true, true, R.string.main_status_connected);
}
@Override
public void onConnecting() {
- buttonConnect.post(() -> buttonAnimation.connecting());
+ setToggle(true, false, R.string.main_status_connecting);
}
@Override
public void onDisconnected() {
isConnected = false;
- buttonConnect.post(() -> {
- buttonAnimation.disconnected();
- buttonConnect.setEnabled(true);
- });
+ setToggle(false, true, R.string.main_status_disconnected);
}
@Override
public void onDisconnecting() {
- buttonConnect.post(() -> buttonAnimation.disconnecting());
+ setToggle(false, false, R.string.main_status_disconnecting);
}
@Override
diff --git a/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java b/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
index 019253af..09218c89 100644
--- a/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
+++ b/app/src/main/java/io/netbird/client/ui/home/ProfilePickerSheet.java
@@ -90,9 +90,6 @@ private void handlePickProfile(Profile profile) {
}
try {
profileManager.switchProfile(profile.getName());
- Toast.makeText(requireContext(),
- getString(R.string.profiles_success_switched, profile.getName()),
- Toast.LENGTH_SHORT).show();
if (getParentFragment() instanceof OnProfileSwitchedListener) {
((OnProfileSwitchedListener) getParentFragment()).onProfileSwitched(profile.getName());
@@ -139,9 +136,6 @@ private void showAddDialog() {
}
try {
profileManager.addProfile(sanitized);
- Toast.makeText(requireContext(),
- getString(R.string.profiles_success_added, sanitized),
- Toast.LENGTH_SHORT).show();
loadProfiles();
} catch (Exception e) {
Log.e(TAG, "Failed to add profile", e);
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 96c27109..b801f0f5 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
@@ -174,9 +174,6 @@ private void showRemoveDialog(Profile profile) {
private void addProfile(String profileName) {
try {
profileManager.addProfile(profileName);
- Toast.makeText(requireContext(),
- getString(R.string.profiles_success_added, profileName),
- Toast.LENGTH_SHORT).show();
loadProfiles();
} catch (Exception e) {
Log.e(TAG, "Failed to add profile", e);
@@ -194,10 +191,6 @@ private void switchProfile(Profile profile) {
// Switch profile (VPN service will be stopped automatically in ProfileManagerWrapper)
profileManager.switchProfile(profile.getID());
- Toast.makeText(requireContext(),
- getString(R.string.profiles_success_switched, profile.getName()),
- Toast.LENGTH_SHORT).show();
-
loadProfiles();
// Navigate back to home
diff --git a/app/src/main/res/color/connect_thumb_tint.xml b/app/src/main/res/color/connect_thumb_tint.xml
new file mode 100644
index 00000000..316c517f
--- /dev/null
+++ b/app/src/main/res/color/connect_thumb_tint.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/color/connect_track_tint.xml b/app/src/main/res/color/connect_track_tint.xml
new file mode 100644
index 00000000..aad4b9aa
--- /dev/null
+++ b/app/src/main/res/color/connect_track_tint.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/color/tab_icon_color.xml b/app/src/main/res/color/tab_icon_color.xml
index 2c787611..5985f4cb 100644
--- a/app/src/main/res/color/tab_icon_color.xml
+++ b/app/src/main/res/color/tab_icon_color.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/app/src/main/res/color/tab_text_color.xml b/app/src/main/res/color/tab_text_color.xml
index 2c787611..5985f4cb 100644
--- a/app/src/main/res/color/tab_text_color.xml
+++ b/app/src/main/res/color/tab_text_color.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/app/src/main/res/drawable-night-xxhdpi/bg_bottom.png b/app/src/main/res/drawable-night-xxhdpi/bg_bottom.png
deleted file mode 100644
index b40d0ca49024eb0bf793040080a0815f2c846192..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 24725
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
Y1@UsJ((-qmF>~zZ%(p&o#ohXU0KVE$tpET3
diff --git a/app/src/main/res/drawable-night/nb_logo_full.png b/app/src/main/res/drawable-night/nb_logo_full.png
new file mode 100644
index 0000000000000000000000000000000000000000..f98e90ef85982dfb5a36dceefdc14af325ac7df7
GIT binary patch
literal 9593
zcmeHLc{r5s*B@ES*dk@i7%BUVnK8^{XN2q$V<}@6O_sroH6xKFq$CnaO+-?*q9jYo
zmXLLjl1N$0o-FUscfH=pQM_JkPn${W<4+?sLxE_jAG8@(AB9@m&A_
zfX~##$QA%#d=@<>6voBdCBT*1x9EV~#XiToB0DpF$#g5ka&NUm}PYOeO&U!2{mb
z&ipSyJZsA$XE@yQTl}W*DbMTnpS2-(A`kCmkK{K&S7!%>2Jm=x=5~9bQVcCDGPqL@
z4!9kZ(kdn!g|+AHrkH4PE~htU;I87XAfK@u1f7kTegPyEyQm-fZ>ZJ2yhCTP;
zI88#n<%6hr&0a;3+Xnf2oC2Uv7Yt8zUe0-0^pjnY!`yNA6H*un
zS66CsI=~H4pTeu2Ek8NKy)sF>n<3?=*P|?(WzN(8E?zJU1F7t|s{k2ZKt2MWGs(DfMbuxhI=t
zJkP@hD`4u0iMl^Jos(|T75<`LcWMRW-#j`1kZsgbw3b1If74wVdVo#8;hSQx^Va;U
za$Vzd!>S$m{Y%Rw-Wrw>wQ%3u$7`u*=)7s@gIr8f#5wQbk;>fWGqq#<(1o0%F{37I
z85;&{!Mb-SEo@O0dhG>+&Q$3<0lkwsoc|K^Q?
zLUC5|g_2oG=4fG###6jiaRiDxQ8n1xmz8}0fR=8sFAncXq=DRt9%LVF@a(f1Fo;ah
z20N%*KrMU?iKoaWq5ed>P|IWZP)|IH0M^ynr4@{30eBN>I8d;+mk$*ktPS4AMYHa=
z#1JrOTZQJS4R*A!1{qTPi6De3LKUil2_^@^z&g7?TK)tQ+SbVUHwe~~Huw~c=8J|v
zf`WongW#$Ze-DTn3Wb6|VGtNhg{7fF4e_Djf>nH|vRe?pFpP*)yg%8OMyB|HwlHz-
zlmMDG7|a?6{qCQ)uZ6`Q@IKVvSYYu13C8(C)KsAmZ*Rz7XHaRFKo-bv4*ka&)MKn#
zh1e3QlmLG`5fe!Cp~?Og;)tn*^&bdZA$gF!eYb;Rk@q)a1pFU*z5)JT+d2e1gy==|
zW`R;!{;B;9A?H|^hJ-&SU6Sy-TrDENRaqozjM;4OdA
z1PY!^KyTj?VMrtarm3ldz@xSC
zMI6TP8?oZugWN)G!4Y$Rb8WM$qX~LlzaJV`WrLOU((s80cm6dT@plVQ6
zIAVK*fJYm%AaShBA$#LIh!9^NkL`i2bwRVDVKIx_N>mo|wwx6V+R&efqfz{iQ7B&8
z;4RlcTabSYTd?YhfTQ7za5N&z8WaXctEr)($YW|qG!%h`t0_TQkAKmp5XhvE|4DnR
zdO%vg*4%_lW!Vqe7X2zIJEGsOr(cg=O3MBt)2^IdX9(0PhwLUDyRMgZ|{$vdP8)J~)B8F^rjo(Aog8Vm9
zw6+!g(q>rme#uzvi`5Mwf3(BjNZV>W|A(L77UTcW0t@g1H|24XH{du4w`mnY^L9FA_ks2u*)=`Vg{pb-Rz~<|uEXht^
z6D$<~P(Hf#Wy{r0yT=l8(@ZTe+~d4l0vs~sL3Ahput&nwNdH*yz;xCJ|3Txlh8nI^
z%?$~(o%2&>H&+22P;VtTw^Ld7+`U7W!=4?E2c21V>f|lV?|*)6jU(rz+eNK&!}q!^
zL+%C|9S+pme_iv;IZ|30hM~_m$F;Iv;CSzV2;0Kft`De-Izs@N^MVFE|KFF(kv3kD
z?IF@!8%)DS_8I*;?qT***XYt$hF3oOh;)L_3%X~kBlTM#xDIkiFd&+bEv#tdr;yv|
z&ecaine*0y52*XOri+}IW)a@@`dsOC9~YtV{g|CHIg-cyTe|&ZI3iXWEFZPanDWT9
z3O@LLbRW%0MRMoxGjYBHk=lV420XZ!Qx{KWbNsYs2CgBkC{soP{pveq&WpK!yb*iu
z?1N}wz`1#$mVKA{Ranx8NL98|5L@a8>;<2`)A*j{Uw?3LHBHkJ)5^YMa;@2kPdHpsh+*W^ZyG+QrPj
zkmX3y&wvfn06&qS+RA8PM_V+RSm$o0&j_|R)i<6PQ{-`#GFW)
z^(lTTDg4rTQyepLTS+hLa~ZqU$1hI298JsCh2T*T2X^ek9*u
zb}t~OZdOn)hqF}R)={;>+aOCLwPuY&Cln95YpUG*l&vI+Ny7@3n!R8;m<6QTE~nZ~
zn%%Py9qHThw%77e7NGIrP*s)T#&Xo&+Lc`HAJ%p2kt}aza(W~4F(u;}@(0g;7hN+1
z{dh{VNu(6FMhY5CK;i(tY7ON%)Q>$LvGbyxqk^wW?^+4h-BkR_RATjzG|uln`z~(i
z7+3h)R5ksW@lBFXTd+(fik=tjJfMF=6qDZ5&ulK=s3ZgiV_h~IeN1D_1``AgOj0=f
z!0`o&HdT5bqnGCDPGm7`zffiPWX?ZnA7Gpf)=nH*#&x7#vC6HGbAj1jcHR;2y!Hc!
zaRH7fx@ts|t|eHtUYI_zDlDrlq1gm=lu5V!B;<*^sjs0
zv*IPU7fh^HE*2-UGrGFN1
z3qGcd?b|Oy?^^@blBLS?JJ}5cYPHu3!`nPA0<_Ao9(TRpUjJS*E4KDhc3mO_m2XB^
z06k?J=3bwgzOhbm42(Dkmf)%`_05cL3Os%|U1Zbh$5KP$MmR@8ZlISmR4eKE$a|@_)0Zh6?`L!3vg27zYI2XjwSB*VkGa-4V
zQe9bAQ#iT0dO3HH)-an*fkeC%Ov1WxL;GA(wfPpJBV{=2@cpo$mc?-ZE|<7$4rbSbfv{=n~xg$)MdR4ZUpj(P`N9eY07SRVPQd8x{}0F*tIZUHhU9*X_6}
zdH9*mNL{^9Evx>KM|{JaWv}|Nx7%FMa;}}+zNL!&jPSN%2I!erHt*g=^`b9_pDyCN
zA;&~iu44Cz`PX^&mbAK?0blD_XzQV)$F6-#)Nf{=shSFw7@c#YN1o<~+~gol$5c@E
zxPNi@Lai2k3412{714VA==R|2
z>-OQ7#$LG5F>bw0Q?3y60yE(KrKjaLIfDtS+@9q#qn|BBs?Uh)sg!^%S=k#q!M|kD
zW?#K0uV4U{Aa{4KIjo+imb%_<`sO38aXwi!n_tv-hxFIT*jQ0XDmW&DGpICl8r8Wc
z{(J7Y_oN5k0(G4J+1luYQtq73%6?hbI`n-hI{RVO(v|7QoP%Ctl7+E=@E6A{2Ck}v
zPQaMm{M*Mt2
zyt^1t6#IiZnSHVAWy@>jhhNeU68B;mzHv7eZA0Y-XLj_3S4HTFOs5;>9DNdtD(cZ+
zwcWI78=MlguQ>IjyT;idi$Ln<>=es^8=jGreL$2Nd-N)bbBD~GE0-g^aF3@9DyWcH
zo>vYW&n{6{HyG~wJP%8c7MB$@rn^Q>UIe^ruhbAod&+9O3Fg^p_9Qi3%=zyl8R%=+
z)?vZgN?XNN2{onM7_)m1+g9cXtOUFyq
zk{TSlddsY_sLOPp86(`oGLZ!I8%A8*@&gzYxXOoqFq)ub~
z`!0*m6zm$`IUnQk&?L9l>Qhmt>zV2J%;Yw+wDQ<;On%hWs&iPosH@5RyL%sB$`)0}
z6n=16@?UF~iTH`}>b-sTPNq;|U}*zKk+RY#%8j{4jRWYAiS(@L^hti!{AEaXE^ef^
z6wBD(YEWN9$?)=fd_F1z_%e&L!tTD(G^*dAqKQ1OfOF|%FaEl&u4Z!KF(4XKbI5g=
zKK2P5IU`p0L2lsd*wZb_r2F%0-njUOx(=
zY85?h4OiR;^;@MEB8Alwl?U(=pY8H3cx?|(dwLeOz-7y@v<_->8+WaH?%CX3jApj_
z=4`F;&?{@+cl8<{sPT)BKE9#mUg<>w~z#=a_3=6&RIE@JE%Ia;R-
z=^8K$%%4_P&ul=D8>rHvv{?&6(P)>o`G?t6zMZyS6-DHl>1$I#+|cZUMaF`M7%Tm(
zhUN48@S0J6(ZlFOiAR_3o*aoFfUCS+bx$eT(p~f=Vw-NFrwiTEm=IaJlkVk=8GSPs
z17lLB$0rzzxo{7ya(kq120%WpOuG2bdui*I?
zC;DvPMt#HSw|C@E6~`xhPJi&FJIq<*{`CC{<9UmQbj3EKo^X$MT&dN?KP^Ncg3mIf
zHX4ql<+HX~K@6FUx+c=?CE!i$Zle^&%BNj}136jJg^q#y9D?ax=Sm$uAF5cfv0Ecis7y2bI`tGsJIjpx|h`=>M=Z{rz?
zi+8lJ?iPbVjxUh3gWjJE=G+!kOZ>$`g}EdqloqOHcWbJ|hoT)i@}m)VM~-3cE(AP`
zcr`UN*l~`oXtCome@1)p$P~2Q>y-d7uxJ6*MaK(Bok|E-;qZHq+I#YzXT-AWh*$fS
z8YMs+1(DavfaxP7dFDxR`aSIDWsoY>mvumT)X9(|)5+j3ITh=_ClbwY#PZZ*JkZrHOLU{0n@CyswI|`*%d_Dce
zp!YJ|x&YrB?(<{WqV)4^!|CJ@h^PHf|20o$w98O)x0D|J>cUH22gwx))^v=p8aA$U
zvbL`3Ap2w=UxocBbG=Hr$>$-b6h!LVQzuTHRGyKLeJf_4A;hI>p#u@ZjICwl7q=so
zv_vv-aMU@^>!GcnS5Cef1$H&}2`vk+)ysyYt0)|b?H3l2-#GRv_TxWL&Qq_f@^mQj
z(o!^o#*EF6r(aWzqhxbDFP!R7urcp`KNNnaMVUti_~dwMvR!0wkAb+XO_g1>{H_Dl
z>#>{s{jscV;E$_{aWy)8<)RlKRZ)}#F+!H9R}_Qa9P~{}x9H#*u-tYOP=3vJmclvV
zWXkwrN*mXez>@0NUentoe3bfH%m!%LsU?dpX3j)(Q7ibGCH;^|_|1?5cDS(fT7;86
zk^u@?7sP$I`;hygV%JV|(jNj1=uzbX4Bbpg1&4T0##L;(lDlI3C*2)Sie=-?ZnsAx
z9?Qaf+w^xn#^!{JVN;L+@+p-)6w>>n3U+tv~#1gYARY*M%Rkyb9tSE$dx+`pfs#4VG_VOql87}H}fI2d!J
zELCWQ@IKaFKWr1hjGjh~UXTxsek7h}<{AH98SU9I;C2*c*q9u3xnkF@^5bvE-P7N+
zJ{b-&W_Vc$w%6D0y>-KDl9!$~0<-$`@hVaD;w8tdxZ}+fFNYAn=M%-M_*E$4k45YV-5#+z{bp~|6n>0~X^hlkpY2ive80byWpRHD@rgQbCj;9KutYws0Y
zJ@1v19mLk+Oax-!smD1=I$#M^j1_?&?Y77Ezg89>y@BnztG%vs+beGhl!cxkgdM*p
zU2Y*8#Jj`T_889HCnJcWe12`o
zxU}HWe7mIMP>FukGvdwytv@;2(1qyOm^!Pk;d$-4>Y^hrIBl+BSL~gR44wP2Qw*&2
zhJlsb7nUar9+X291xS!ZD+h!GN)dI2sUdmCJ&P^bD_a8fB}k&_X;QBB)-OA%;oWS%mOu3NWmn4|g13w@mc)^)!Pb%Ms21bvJH7&$!H=zbvv8bSoK|M-y2+U_tu+tX
zgv+i=@mlDk3IVqUDX%;BmsB^7hx$smwuBCvEEi0>eP7NIk_?-+gJ(;Svn56sVv{x`
z$sf)^Kpd&;j?>xKyft9CVtsgKV68
zR%_1aB67FML_EBhVYr?d5UTqgvzY1OT*gg*IG1$|IbU_<7U+t-Uk5X}ZrNIa81SuU
zwl>Mr{aUhZ0q;Dze4sx{$DtW}MOJEbVSY`BGr90;)I{B~TC3;Xc(C#6e*Ci>k7;{(
zRu0S}=TssUU+f<$ohlj836dUba{{uxJ4v`EvkQ#H9Ace1vh0jS)vv#(D!P`dfhD9p
z|4`i~pLDde@$!4?3~xigq#Sdpq-|yI#Jq@6X-l#vrNtD_+xC>(%~fH~adkNjIap>s
zY2q~Y8KPzX0&23{wII^%BIz_jS1fEi0JAJgjI(x0OEHjUM+6vk5ln+l#8keqa&6IB
zfG;KcT<_^^7X`V37SvnQ8Z(!KQ=FQz&8Hddu~UHHTbtKC^z8~~$M(U^Jd}4!JgWCh
z*!c7aDoPmi;9VJb7iiZFG|=%d(;QgYOwILH0YUP(HurtK$0OwYK;)UZ7tA$k>AC2&
z3);p`0DQUQwAW<&_lgVNv8~@&@8GuIQZmOj0mn2Kj1|NyPq5yc0!%TMMh^|#BL54Q
Ck{e9`
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxhdpi/bg_bottom.png b/app/src/main/res/drawable-xxhdpi/bg_bottom.png
deleted file mode 100644
index 2c8710cc5a1567dc8f8c8b41a1d1446604f6c4f8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 25580
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
UJk2!xUt&V5mpd-Yv*jH8Keb@1761SM
diff --git a/app/src/main/res/drawable/connect_switch_thumb.xml b/app/src/main/res/drawable/connect_switch_thumb.xml
new file mode 100644
index 00000000..9003ac59
--- /dev/null
+++ b/app/src/main/res/drawable/connect_switch_thumb.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/connect_switch_track.xml b/app/src/main/res/drawable/connect_switch_track.xml
new file mode 100644
index 00000000..c2582c51
--- /dev/null
+++ b/app/src/main/res/drawable/connect_switch_track.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_content_copy.xml b/app/src/main/res/drawable/ic_content_copy.xml
new file mode 100644
index 00000000..5c76228d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_content_copy.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/info_row_bg.xml b/app/src/main/res/drawable/info_row_bg.xml
new file mode 100644
index 00000000..abe89de5
--- /dev/null
+++ b/app/src/main/res/drawable/info_row_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/nb_logo_full.png b/app/src/main/res/drawable/nb_logo_full.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e139f393597072af3f988cf41b94d8808f31c5a
GIT binary patch
literal 6831
zcmcgx_d6Tj_qQpbp=y^M4lHd5Z+%=65L_|W*{#(SQ^68aCL~Kwk
zsItDV`R}|%&v|wKZZQeo2Lnave+-ra1JAT5R3o#q(_=P2sf<
z+Pla;C5L$%%!b1Xp*@uot`AJm4yh?Z$)u|s_0dvAb|F1P4i{NRRVu_Rbd*Zh
ze|3W6>%Pi!M*vl*{@;z!I3z&q`}WD7z`9LgY56_9lAm%4%hJqOquil;@OQrD7+0N0
zpvo$eY}CCTZ|)-1Hj>OEC{s$r^z@hC`A~l2eusa#vjT$(Rr38i!bs7nImEgNUU>1y
z^*(oQKnP3;_((qzR$jviET*f2l)h?wD^;f`=u8sFik@Q%-S_6ykmKK1Nj
zR6dt4JK@C*3itW?RRd4X|H#W7z!Am<4NLd%klq`3IK=3~&aB$xZ`bX!b2R8G2#Ch#
z`xu2vs!%QE&(ajpW9?;xMhoQYL2Rb*jY1#>PpUuviwg6-zb4
zk@+t3$lSF<8^%osQTo)1s%4)pWAz?2>~^hr+pOys<5Tx0-$N~`?bAOU9UVQpyR~_HB>L}?;dbpv8P=D)n&jhu7uw+*A$y~a>>
z-CaqtXzwMTymNv!@~QX+ZM+rNgc%?`BjXz&%wjy3u9ya9ngnjKwY7cl@;3fX7xu(E
zr?c0{n2olMHrXjrz`K%)vP_lb-Qqd^cI!e3&)-AWbN2a1lryi1X)(Yrzh=KU$HuFN
z(~g3reZ0M$&YgbsrwJa7kB^TGIWm6LjDCO+;&8wG=S3LMgaM+>IIh~?ou4fHkwEsv
z+6~M(OSeWR_0IuIyLq~j_FI-ta`1Ufa`L_bqP~f(ul<7w&Z-@!yZV{{sX-Ma8?jic
zHQkD#4QVGwEQ7l^9eV9I)7mY*P?B5dc1n-Ht1Z`n+sjS<1{{6~d#~)Gm?_3gFQ#?$
zr%}KnfDIJv?8UEqdS8py60VC&?$t7L}V9h;B)Wf?f
zNY9^;b3Gg_YrASSs7>Vfl8SO&uI}VCDW@`Z%r
zTyq6_yC?{<0!oruP;rIycD7v2QaM8}dv8sIf~Yt%v4&;k<&8syVB)=7JWIY!->ZIp
z6{ae@UI`d>1*f!KyXGTpn>QXNsU!WxrKHpnMH|pGy8fyX)9+&o!!(U_{ObRZT9RbtYSBhy@;RBu_mNX1!0ItgphT;Tvs#>(7$#
z;XUgPvkDG7vGZ5<)49~#PE_*W^78KKG?>b27s?UW|^Av)`*~W6y
z>Da~O$d`YJOsJ^AutE`;EFe@)BA23hXM<9x4TL^n5+ovk4$~9~nrxraF%&WjNQw=-%>Ge%=r=)5En`gV`%w@Vw&_xccns;cR
zqoYsMZis#po!T^l7DdSj?U)&Yqa0hY%HZ1IA4;b8f5l1uS2CblT0+Q(B8Rxv09Ztb
zt^7{~-_%7JH9E`-P&`oOeS!YN{p@GLvgT>|c+-7xt^=p5sZ%zt%v1nXQ=i9(NkuBi
zQ|*|BSp@QJPR>m_#}faDE&kHHt}*ebcJKV$Z#ZKUb+xtE+uM8OTjtX*Q;>RbR}g
z4CKGvaEkA6=^5fNV?yYF#Li;3Y1yTC->2w6**sKjoZrg_QIqhJwRahgKPFZ1?eCsE
z5^{5VZQkZT`5d9>fygQ|V9F@c9D(E(NQ#!p*PSFPyj;vJkH8AaB#h@irp)?AP0Erb
zDou`OX&yN+nU7BECb{BMJD4jjF8;mOeqMVVPr?>4Gh;WEiW8=wrDm@D_KIi_eflH
z3`x872fk`;^Y{Zt&uo6sLJ#-eY1^TKyuAGN$@Ck35z&VIf8fS~(S~2|H}B>&p1D$<
za!g5;aHsrKphYl4J@PJ-LJz$IxrqfrD6{aNR(JW5tMlhhRMc7E#jUJIDm2daytvd(J
zvZ-5JNYHo14R9SK8grTg%gm%Z0xP?&+S@1e{@aawc
zY{-A@TK`f+RCFJ^>>C*>opAEU_sgUii8f;)gKas^B)?i
zl-tt%7o1&4ymc+zpb^EkY1H((n~lM=_!h^YU#O*e7$*R}V{^Ng|H`e!dFh)^mCRr#
zBQBsUvLJ)Lz&>b}YCpUsm^58xYz9*z7WocXQ7+`D@*-=PuAnz{C)Z
z1n{r7$TMhoiBvm(7G9b9GDw!}KIY`Bo>jM+v^j0ot-I2j;or6S_WfIHX_A}#Pn>en
z$f9cjyAYK<7K%=-;^K!a*3avHHd8LRWlqinh&}}v)zMTVs+|K|9I_CC;>=JLm`y~f
z?DNR$*QZvRD$2)0G4cx!Ywg6Oq|)q}UvU(&tUD%wqiPJQl4^_S=W`fGcoT}^PCzc1
zlam1&E6!iQVm56(mdTEfd!v}PjBVVIq3$E`~qPuiWfG+AuN1%O(~G@>~*tFH&ad=
z(;4ekdz3tXtM0|%nPPkI(;Wexx|XvywRNZXD8*hpWqWTR$G>aXT%zLDS?b@I!CwKT
zygjq?G#N!E+v_w9?1an)yZJ*6!VIK3wcLRW?}rs66|>Ms&4BBVP9Y!UW
zBtsMf7ZWbrec!k&8^05WjOdBpE5#uBTCgE&aU9j{CW_oS)TGz8UE5
zUY~B0`-WO<^`tQc$0ng5^;rtHT-%r^-U#$@)0waHfF@&w#IwFXdC-8F-fwf9;durV
z=w*U3>QFEFGjPk%)P4)wMrek^*Kiu-t#Z2-YZybecp#hk4g<}Sk)c*%V&bOP9JRF}
z48y{1Zyj-vTMC4_2xZ(q;)}h2_$gaz&w_LpAc8R<^^P8qfJff25ufpiBW3qDJDcdc
zmYts8LXUN9pLm#=OX#o|rJtQ9FaD?*cnidAwO<;eIP72~V!R!e7w;fRW$IN%^;Yh$
z_U0S~Zv|O@opciJfZ)8{+`qf>5%WVdrE7YC^IWuUd@7-m+si(NvYWOzZsnKlBP!dTeWz?MY=|fp8TJ|?5T{T
zT~q$=ua!B8obvs08z0^%dpKAlnKzBHRFc~gcDZ@niYcVTu*Ka8_{2gzx?pE
zCO^ZZ=dqo{h{{t~gxIHtCHuRsS=g@3bSIZa+OJwifp`T;CEr~fYp%QE?^{OV5)^{LwbY+ye$IJt~LA$t#DH`rw9&bKWu%nytTXTL@Ku&D|oCJE3K^!cp2T{JGo>
ze9k7&Tvi891mNBp?QICmPJC6S_UMfgftVI4Wnxw
zvM43)GQrZ61s!WpZRXWmaL~kfkfuPae6&Q;6n^Kz3{6XRC8=V{g(IugLQ!O*37hkOI;AD!pL#`v#uSD!Jl)zzpC
zt4GlarNjJ!5(uBScG#0WDFCC51b1FwR96^s@eAwuy7omhFlV@Z4*~gG^6Qhm6^lXC
zA@;W7XU?ZDr0MABJmDA08!r7-0G%ZVNdn#e
z42O&+#`8keF!6>@$gl5go2|h?MfC>>2Y}y?pK~#(!SI$`CZgz0^MIns)!wd;uX}c4
zySB`%mc);b`~ylo@Fr__CYFD9hay9f
zWSjTqh_s&Ul<>HFzwg|pX9JLB?#IP);6sL4-_7D{aIB^hmJECO^?h;0A{qqB7s_=D9yf~FFMWkhRGs08FrpFI#m1RO!Pyms
z;H$EdqCPP0`$s{8tOUMyOb13(_e<=ZS-s|{ppxc!
znbtF?VfV(Q|Cba17$ExUcy^>f@w$_Ppi(@FJjv$nFLgL$vDz!G|2h0$8|6Y)+#4sh
z^CE{gN~p~aJ=^^j#d%9uWt}#YdlJq2
zfW+}d%%q6>?R)d8j&dUNNAKnlt2>%a>y%CQ+cE3#L!Rdg7^B}Lw&2&KDEqiCqJ9~T
zyqRl7JoiFWi1Fe}Y$E=u#2=}=k0boWfP?k@K+rS8u$gEniz{#Ci<$x?k)Fa5Tf
z3UIY*f&8$fY2FaY7~z3^;K2K7^yy0^Xjpq@2xU$UbD_Y)uyr>mw1^+5=y4wgHKtMd
z(!Sb!TF2q%GshPiDs@BZVe;fqNe}!IC^EKa5qIW*QMhSdfYyZ+ujP@9YU^P#LP>lH
zFBnCenbj!92CvQwsBZh7te`{9KLyH1C0(-XJQXOm>2m2
zS)G4r16ei0^Ss_qK~!LJ>za%?%Ijmn6K0}JDF#(i^m=P|J4C--
zysYGg4wH?Njg{<1yIoDigE<2ZVp~v7quVF02A1KWB7q;Pas?*4NTsa-2lv)hQ~T-0
zcpK=QWOL&0xTL>Fi2qE)FEyuUED*VK_5A+kzOC_hULo4ZbpD^-T87UjR(|~q59C>!
zTm8yQ$@>CZMrM{0e}wluESsWn9!Lu=KNGf*j00$=6f!o{!5u{!F7>-?Q@U21-F4M`yF;nd%qysf15y(GA1KjmJB0Lu`*D`JP
zjI?4AL`FwPGjyGzwNm@c*?YTcjZ?mY5+nvYv*XmnIP4BIXfYK$ZRVm4?CuPFL$%a>
zu`h)pCbjI*02*#eWuR>N*HsI;>NpLJuks=xt-3_-{hWE4{8QFEAq<
zbAO*=mfwahi4|<%j;03-E5Pl0Zdusmde3atbqE8~9Hs*9=jUhDva^|Y*AZ+|lOFH0
zagT!oC&VLHX((K8YO_LlvX$rMQ{1Npgd1S`!e206i~Kc4#g{c!DrIj;NJwD&S*PJG
zP9y@kR&sjY_dFCm!!@;E%I47w}b1vy1RD}=4ws?9h
z=tej5SV{7{ze$2!g3#z+7F&f>mCk*A~KQ$lSmKY
zDOswYkNnsyucT?^>EN|!$4*=?1qG-f4euh2a3hP;+AX3|4HOOSt#8I)ihDjixYY{v
zM!OO=1wPSmdgYvmczido3)^^`sYaq6!?P}!cR7;KqUwaCXUdt9kKfOaQ5kq2VTBv|
z{-mTZ<{p?<8LUcm0q&F>_?O3XMB;Y=*tB+zIK}iOYIXX?XmJ4iQCX*a%a7a&<1}I{
zOC0R^khRf9yp}i;YI235-fE|77+;Of}SNDJp`;DNk%oj5wQFzo7I-a97TNr
zs;ZS8f7<9sRy_u^G!gDIDS@G!lky1~FT-b;Rj95JY-WKrmvMuMpQ?vnsJ&RMxj&BpqDQSSvs;k|H;ho}Q1B&rh
zH|l2l^!BK#rqh{#&|;^Ow+#BIena=_&%uG%8$4png2IXSBk2YF^GD`EM?R35V^WHL
zNMM8J9>bc=WLfS{CDs*2^2L#bE}y-XuLj{O#PLFV2LUDQiIhjybmsRKZv~^i9sILy
z>(
z$cVIp8}uJ(lY2eZbtL9VrEVa^GZ)ym0|*+0ZRDwBWB&IXgJkzwPu>O7P8anm8f0aF
zP%&M;u~npLlFp+W?DzpmiY9YzGtYO)9ZS#Wb?MDs$FQV`8o^K(nKq`Y@L6sNlz5F8
zz`1vKJQcIV!O4jSTd6qCo2(kPsTX&E$9W~*ltj^|;5^Q{?3;p?`!w{Q`f~*LG{mFc
zJlzY2RoGQ%vY!s@pSiITHAngZ)&CBpcUf
zNp(FnF`?gEN_C^*)L~7QeugBMR0epQM1KH$;?_4FBM2X+#opon=#2L6-H8N}9!HW!
zBOt$yDgvvaa%CYAg@-bB1D|QE=OWREfrq;RK-TE=(=Crp_{RtiUjSk
z6IVlDqh&f)h1nfdx961byZzXk#QEP4Cz(J0^qP3wTIU-7
CKLeWp
literal 0
HcmV?d00001
diff --git a/app/src/main/res/font/inter_variable.ttf b/app/src/main/res/font/inter_variable.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..4ab79e0102bbe0ffa1ed879b13e52ac8c6487833
GIT binary patch
literal 879708
zcmd>`3A|5L+xOSB*S7ZI5JEWr|2a73ka;Gv49PrYCYcj5B}qsUGF8Y>NEt#hq%@h5
zN|G|2V@^70QVHk%UH@wzx4L`oyXSe|_jx{__wDof_FMn8_g;IgbzN)iy{@$nA%ze*
z@INEUG^|&@!CN0bFhJ-5mxM^1(6GhbtqydXv{LA&h6&YSYQt7->I4gy%oN@^T-3E~
zqqcXp)Y)=(7q&rrAxfNUhTliJ=RGOx(Aqd*<=w4HmyKL}@qQuXX8i8fs`Z_%`;Be7
z8pqG$_tEYnx(^+1hkq#SgYV;a`JMy2581kDY(*hTUlpQv$v!wP^QH~P@n3O#(|rR*
z_4(na`*sWQUN)ifPrVPvRjWoDg&np|*k4}l+q-+O@^gn(!u_h_{EB^%k!xb)KKver
z--Y@P95ymb(@UvBs60a4etN**p55bG-BUz}IYsgN{J`!bhs4bmmvR1loS!(T`@r6-
z`)~P5s1pl>$kKGk;0K3&@o1$dg}R9PkM{)ioe_0j`sMr-KUI>53_3T32I_ygBU;5%Woqp4Qaii!Q{C}dzEQSa_ye{Jm
z`fa?ZoFP0RymICv9C(gZeI%x-7tliCY2+$lQbds6QY=ZwuOup`FibFnm?e{;S6
z=Jo!MqWsNx)y2j?k<+#o)oe^PAB6rSV9q3%sVYtbXq46qW+1`Ck)9b=cLPo(pxjDL47oudk)
zy-i8e_kxerdXWqIGxFo;7}5v8C2$>lkGxyK+%Uf}^dx={0MDxOVi9zst|fXPf3F@d
zdgv+W+wWsC
z&NbE2s~h;jjo&jxFGGA0D$-sz*yAs-n^4wr92>~T%_Q{aKaqa@M&7%ktXU#*+7Yl%
z)qjok;Rk<<^mBjbJpUJz7lEJNOrAgezWLby=``Kz&t%-=4E(n+Cp
zQ%e6U+6zm^eINZq+5)zI5zL1Ve8YK^Z_V|y8RvMJVCTQXZDO<;Cp!KQv*_mg`|U)>
zn=xla-~T}t;obpQWR3&Uo0)~W5lceN`2AP<7wxcxMPF~tU$@WQBl>1~UG$Bq3C~#t
z{hyIr7|UPe#fzL?W|SK{p8kf}Mu;&0*QKvz<#XjFF%~S+DPobll)etU
z4i14MA)BDz(>c)1;57IG{2W4grNM5T(=sgY5&S+2HvR*;Px?CCXRO*TYSD4ElR^58
z5W40p)y4F>8Pxv|zeRrf9oFe5TtoNyl78!UBEK$^{)URRCw5LFwK=8_(nn>Zbbq?R)y^qOa|Tu~`sh(tJR6
zy?I{X^o@B-YuGPF`X*>8LhXnV=EsgVLViE3(^H|N0UdjoNk3%<;~qp6G2p*QA4AWw
zTzGf9hH<N|2p_W&e#~HvHqXsnSXl?-Q&-M_xTU*`|r!7>#zR@{GB#DA}X4ju+v0?e~0NJ
z?)(E!q0hoH@Vx&+c^Uct8TEX;cZ9^Qn}Ra?i*bJ!_|Zx{_cnSD;@t!9mtJi#Ew)B`
zOiaSMYP28Vow69-V}HSWCGabQ+IVjn3urBdHBTn2dHf@cU6TIHzdeV_i{f5gQRcgN
z_kp4wIlU5COQ0_1O+0s|qr5euihoE{G2e@aJz9&j0a!++l4gRZWp7h_p!EU
zg>s&QUt&Iu>2t`-fpT7k;#^Dhq;+OltTD0vaRTYXVn`->|1B(PdXrJSV!XMG`!B_PwqYIjGMxi0$Zt^ehD=bz>&_)TAL44wm3@O&Er{lAFWBN~_;Xv5=pCOmuthxe$W
zc8s{wE)#d^pG21%_G%0JuLtA6TKKdgQf0p=p^0sP*gm|qgVXNg|+E$CoT+O)yDMYmX9
zUt1M@*8taS!uc2@<}Fc?){e1v={_Q2PKiM}0(}SLa)D@y@mn6(SEV(ezZK)`9?<~r
z&E@^2q9mOgTaRTGgKSYzDi(t}jB!mI0=OnF5%xKO`cB2QpNRRHu)g>9i}~hY`ZqV?
zd71Idy;F2Esp7d9GX}pJy)@3kX(io@nRv;gEWyExl
z3buo}U=&yn=7CLMewfZU?_vC=bKW8p$B1S?GZ>%~MLHM)TC&Ol;qSl9_sYoTjCeaN
zmy|ddvJv{;P0+EhUeY4{U${=}M4d$jUJ;Bp%*CpiSPb7=Op5o5#U{6CnW>a$iF8Y(
z`Hj7JEaDG%*}=f*6s0O>q`KL1~xt8$@TL?3YgW9ERKBo@c$B1XzI
z)Fqc_f!{6UZqY|i6@5I+y*}D{^Kbc`n6AGN(^YfKd(F{D7tluwP$tqh=*P!mzme8C
zL@&?+&y-%Eh1W!^0pEiCAt#~4d*HxL(D4;uIry(!lcJYnGb2q5jqw3&r^Hai58v}z
zi(ZILtjqx8vZdKCT6(j=SD}ByXcq11ieJm)kj5hIY+eDV=(3ph(TbZnTGd<
zhcP!~7fZbyxNf)DsxGFV^&IAa(I}%Y{J)}TpvQ^fx~^yqZLQmi)~c*XL=3ex${LO`
z2gteUzv+^(^l;4k!zo|)kDWi9u2GHgJAyUcWn4$cI*JPBRZ&(~5EXS7Q9)M{1NCZg
zFQEpDo~k=yo=;%>%@p_PIbeSoTz4RdQgdQxO
zgwFkcp$+nh>qB%l(Ol;dO;tY8L