package com.example.tvcontroller import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.fillMaxSize 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.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.core.app.ActivityCompat import androidx.lifecycle.lifecycleScope import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.example.tvcontroller.client.WebClient import com.example.tvcontroller.client.WebsocketClient import com.example.tvcontroller.services.BluetoothService import com.example.tvcontroller.services.ControllerService import com.example.tvcontroller.services.DeviceService import com.example.tvcontroller.services.webrtc.WebRtcService import com.example.tvcontroller.ui.theme.TVControllerTheme import com.example.tvcontroller.ui.views.CameraView import com.example.tvcontroller.ui.views.RemoteView import com.example.tvcontroller.ui.views.SettingsView import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch const val TAG = "MainActivity" class MainActivity : ComponentActivity() { private val webClient by lazy { WebClient() } private val websocketClient by lazy { WebsocketClient(webClient.client) } private val webRtcService by lazy { WebRtcService(applicationContext, websocketClient) } private val bluetoothService by lazy { BluetoothService(applicationContext) } private val deviceService by lazy { DeviceService(applicationContext, webClient) } private val controllerService by lazy { ControllerService(bluetoothService) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) checkPermissions() lifecycleScope.launch { deviceService.initialize() if (deviceService.serverAddress.isEmpty() || deviceService.token.isEmpty()) return@launch lifecycleScope.launch(Dispatchers.IO) { websocketClient.connect(deviceService.serverAddress, deviceService.token) } webRtcService.connect() } enableEdgeToEdge() setContent { TVControllerTheme { TvControllerApp( deviceService = deviceService, controllerService = controllerService, bluetoothService = bluetoothService, webRtcService = webRtcService ) } } } private fun checkPermissions() { Log.i(TAG, "Checking permissions") if (!bluetoothService.hasRequiredPermissions()) { Log.i(TAG, "Requesting Bluetooth permissions") ActivityCompat.requestPermissions(this, BluetoothService.BLUETOOTH_PERMISSIONS, 0) } } } @Composable fun TvControllerApp( navController: NavHostController = rememberNavController(), deviceService: DeviceService, controllerService: ControllerService, bluetoothService: BluetoothService, webRtcService: WebRtcService ) { val backStackEntry by navController.currentBackStackEntryAsState() val currentScreen = Screen.valueOf(backStackEntry?.destination?.route ?: Screen.Camera.name) val baselineCamera24 = painterResource(R.drawable.baseline_camera_24) val baselineRemote24 = painterResource(R.drawable.baseline_settings_remote_24) val baselineSettings24 = painterResource(R.drawable.baseline_settings_24) Scaffold(modifier = Modifier.fillMaxSize(), bottomBar = { NavigationBar { NavigationBarItem( onClick = { navController.navigate(Screen.Camera.name) }, icon = { Icon( baselineCamera24, contentDescription = "Camera" ) }, label = { Text("Camera") }, selected = currentScreen == Screen.Camera ) NavigationBarItem( onClick = { navController.navigate(Screen.Remote.name) }, icon = { Icon( baselineRemote24, contentDescription = "Remote" ) }, label = { Text("Remote") }, selected = currentScreen == Screen.Remote ) NavigationBarItem( onClick = { navController.navigate(Screen.Settings.name) }, icon = { Icon( baselineSettings24, contentDescription = "Settings" ) }, label = { Text("Settings") }, selected = currentScreen == Screen.Settings ) } }) { innerPadding -> NavHost( navController = navController, startDestination = Screen.Settings.name, modifier = Modifier.padding(innerPadding) ) { composable(route = Screen.Camera.name) { CameraView( eglBaseContext = webRtcService.eglBaseContext, videoTrack = webRtcService.videoTrack ) } composable(route = Screen.Remote.name) { RemoteView( controllerService = controllerService ) } composable(route = Screen.Settings.name) { SettingsView( deviceService = deviceService, bluetoothService = bluetoothService ) } } } }