146 lines
5.9 KiB
Kotlin
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
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|