tv-controller-android/app/src/main/java/com/example/tvcontroller/MainActivity.kt

146 lines
5.9 KiB
Kotlin

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
)
}
}
}
}