feat: add bluetooth service and viewmodel
This commit is contained in:
parent
a7184ece91
commit
421b1719be
@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package com.example.tvcontroller
|
||||
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.app.Activity
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.core.app.ComponentActivity
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
|
||||
object BluetoothService {
|
||||
private lateinit var bluetoothManager: BluetoothManager;
|
||||
private var bluetoothAdapter: BluetoothAdapter? = null;
|
||||
|
||||
fun init(context: Context) {
|
||||
bluetoothManager = getSystemService(context, BluetoothManager::class.java)!!
|
||||
bluetoothAdapter = bluetoothManager.adapter
|
||||
|
||||
if (bluetoothAdapter == null) {
|
||||
throw Exception("Bluetooth not supported on this device")
|
||||
}
|
||||
}
|
||||
|
||||
fun isEnabled(): Boolean {
|
||||
return bluetoothAdapter?.isEnabled?: false
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,20 +1,23 @@
|
||||
package com.example.tvcontroller
|
||||
|
||||
import android.content.ContentValues.TAG
|
||||
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.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material3.Button
|
||||
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.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
@ -23,12 +26,16 @@ import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.example.tvcontroller.ui.theme.TVControllerTheme
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.example.tvcontroller.ui.AppViewModel
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
BluetoothService.init(this)
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
TVControllerTheme {
|
||||
@ -40,17 +47,19 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
@Composable
|
||||
fun TvControllerApp(
|
||||
navController: NavHostController = rememberNavController()
|
||||
navController: NavHostController = rememberNavController(),
|
||||
appViewModel: AppViewModel = viewModel()
|
||||
) {
|
||||
val appUiState by appViewModel.uiState.collectAsState();
|
||||
val backStackEntry by navController.currentBackStackEntryAsState()
|
||||
val currentScreen = Screens.valueOf(backStackEntry?.destination?.route ?: Screens.Camera.name)
|
||||
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(Screens.Camera.name) },
|
||||
onClick = { navController.navigate(Screen.Camera.name) },
|
||||
icon = {
|
||||
Icon(
|
||||
baselineCamera24,
|
||||
@ -58,10 +67,10 @@ fun TvControllerApp(
|
||||
)
|
||||
},
|
||||
label = { Text("Camera") },
|
||||
selected = currentScreen == Screens.Camera
|
||||
selected = currentScreen == Screen.Camera
|
||||
)
|
||||
NavigationBarItem(
|
||||
onClick = { navController.navigate(Screens.Remote.name) },
|
||||
onClick = { navController.navigate(Screen.Remote.name) },
|
||||
icon = {
|
||||
Icon(
|
||||
baselineRemote24,
|
||||
@ -69,10 +78,10 @@ fun TvControllerApp(
|
||||
)
|
||||
},
|
||||
label = { Text("Remote") },
|
||||
selected = currentScreen == Screens.Remote
|
||||
selected = currentScreen == Screen.Remote
|
||||
)
|
||||
NavigationBarItem(
|
||||
onClick = { navController.navigate(Screens.Settings.name) },
|
||||
onClick = { navController.navigate(Screen.Settings.name) },
|
||||
icon = {
|
||||
Icon(
|
||||
baselineSettings24,
|
||||
@ -80,23 +89,23 @@ fun TvControllerApp(
|
||||
)
|
||||
},
|
||||
label = { Text("Settings") },
|
||||
selected = currentScreen == Screens.Settings
|
||||
selected = currentScreen == Screen.Settings
|
||||
)
|
||||
}
|
||||
}) { innerPadding ->
|
||||
Column {
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = Screens.Camera.name,
|
||||
startDestination = Screen.Camera.name,
|
||||
modifier = Modifier.padding(innerPadding)
|
||||
) {
|
||||
composable(route = Screens.Camera.name) {
|
||||
composable(route = Screen.Camera.name) {
|
||||
CameraScreen()
|
||||
}
|
||||
composable(route = Screens.Remote.name) {
|
||||
composable(route = Screen.Remote.name) {
|
||||
RemoteScreen()
|
||||
}
|
||||
composable(route = Screens.Settings.name) {
|
||||
composable(route = Screen.Settings.name) {
|
||||
SettingsScreen()
|
||||
}
|
||||
}
|
||||
@ -106,15 +115,39 @@ fun TvControllerApp(
|
||||
|
||||
@Composable
|
||||
fun CameraScreen(modifier: Modifier = Modifier) {
|
||||
Text(text = "Camera Screen", modifier = modifier)
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(text = "Camera Screen", modifier = modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RemoteScreen(modifier: Modifier = Modifier) {
|
||||
Text(text = "Remote Screen", modifier = modifier)
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(text = "Remote Screen", modifier = modifier)
|
||||
Button(onClick = { Log.i(TAG, "RemoteScreen: Button clicked") }) {
|
||||
Text(text = "Button")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsScreen(modifier: Modifier = Modifier) {
|
||||
Text(text = "Settings Screen", modifier = modifier)
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(text = "Settings Screen", modifier = modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.example.tvcontroller
|
||||
|
||||
enum class Screens {
|
||||
enum class Screen {
|
||||
Camera,
|
||||
Remote,
|
||||
Settings
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.example.tvcontroller.ui
|
||||
|
||||
import com.example.tvcontroller.Screen
|
||||
|
||||
data class AppUiState(
|
||||
val currentScreen: Screen = Screen.Camera,
|
||||
)
|
||||
@ -0,0 +1,19 @@
|
||||
package com.example.tvcontroller.ui
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.example.tvcontroller.Screen
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
class AppViewModel : ViewModel() {
|
||||
private val _uiState = MutableStateFlow(AppUiState())
|
||||
val uiState: StateFlow<AppUiState> = _uiState.asStateFlow()
|
||||
|
||||
fun updateScreen(screen: Screen) {
|
||||
if (uiState.value.currentScreen == screen) return
|
||||
val newUiState = uiState.value.copy(currentScreen = screen)
|
||||
_uiState.update { newUiState }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user