package sh.lajo.buddy import android.app.Activity import android.content.Context import android.content.Intent import android.net.VpnService import android.os.Build import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.padding import androidx.compose.material3.Icon import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import sh.lajo.buddy.ui.theme.BuddyTheme class MainActivity : ComponentActivity() { private val vpnPrepareLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == Activity.RESULT_OK) { startBuddyVpnServiceIfAllowed() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() if (ConfigManager.shouldFetchConfig(this)) { ConfigManager.fetchConfig(this) } maybePrepareAndStartVpn() setContent { BuddyTheme { val context = LocalContext.current val prefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) val navController = rememberNavController() val startDestination = if (prefs.getBoolean("onboardingFinished", false)) "home" else "onboarding/step1" val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route if (prefs.getBoolean("onboardingFinished", false)) { val wsIntent = Intent(context, WebSocketService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(wsIntent) } else { context.startService(wsIntent) } } // Determine which destinations should show the bottom bar val showBottomBar = currentRoute in listOf("main", "home", "settings") Scaffold( bottomBar = { // Only show the bottom bar on the main screens if (showBottomBar) { NavigationBar { Destination.entries.forEach { destination -> NavigationBarItem( selected = currentRoute == destination.route, onClick = { navController.navigate(destination.route) { // Pop up to main to avoid building up a large stack popUpTo("main") { saveState = true } // Avoid multiple copies of the same destination when // reselecting the same item launchSingleTop = true // Restore state when reselecting a previously selected item restoreState = true } }, icon = { Icon(destination.icon, contentDescription = destination.contentDescription) }, label = { Text(destination.label) } ) } } } } ) { contentPadding -> AppNavHost( navController = navController, startDestination = startDestination, modifier = Modifier.padding(contentPadding) ) } } } } private fun maybePrepareAndStartVpn() { // If the user already granted VPN permission, prepare() returns null. val prepareIntent = VpnService.prepare(this) if (prepareIntent != null) { vpnPrepareLauncher.launch(prepareIntent) } else { startBuddyVpnServiceIfAllowed() } } private fun startBuddyVpnServiceIfAllowed() { // Even on Android O+, VpnService isn't started via startForegroundService like typical // foreground services; establishing the VPN tunnel is controlled by VpnService APIs. // Using startService here is the recommended pattern. val intent = Intent(this, BuddyVPNService::class.java) startService(intent) } }