diff --git a/.idea/copilotDiffState.xml b/.idea/copilotDiffState.xml
deleted file mode 100644
index b87fde3..0000000
--- a/.idea/copilotDiffState.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1974fe9..db166c3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,6 +19,7 @@
android:required="false" />
Unit
) {
val context = LocalContext.current
+ val lifecycleOwner = LocalLifecycleOwner.current
val cameraManager = remember { CameraManager(context) }
// Проверяем разрешения на камеру
val hasCameraPermission = PermissionManager.hasCameraPermission(context)
val hasInternetPermission = PermissionManager.hasInternetPermission(context)
- LaunchedEffect(isCameraRunning) {
- if (isCameraRunning && hasCameraPermission) {
- // Start camera preview when connected
- // In a real app, would bind to lifecycle and PreviewView
- }
- }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween
) {
- // Camera preview placeholder
+ // Camera preview area using PreviewView
Box(
modifier = Modifier
.fillMaxWidth()
@@ -340,13 +329,36 @@ fun StreamingScreen(
)
}
} else if (isCameraRunning) {
- // Camera preview would be rendered here
- // Using AndroidView with PreviewView in a real implementation
- Text(
- text = "🎥 Camera Preview",
- color = Color.White,
- style = MaterialTheme.typography.headlineSmall
+ // Render PreviewView via AndroidView and start camera
+ var previewViewRef: PreviewView? by remember { mutableStateOf(null) }
+
+ AndroidView(
+ factory = { ctx ->
+ PreviewView(ctx).apply {
+ scaleType = PreviewView.ScaleType.FILL_CENTER
+ // Keep reference for starting camera
+ previewViewRef = this
+ }
+ },
+ modifier = Modifier
+ .fillMaxSize()
)
+
+ // Start/stop camera based on lifecycle and preview availability
+ DisposableEffect(previewViewRef, isCameraRunning) {
+ val pv = previewViewRef
+ if (pv != null && isCameraRunning) {
+ cameraManager.startCamera(
+ lifecycleOwner,
+ pv.surfaceProvider,
+ onError = { err -> Log.e("CameraManager", "Camera error: $err") }
+ )
+ }
+
+ onDispose {
+ cameraManager.stopCamera()
+ }
+ }
} else {
Text(
text = "Camera Inactive",
diff --git a/app/src/main/java/com/example/camcontrol/Models.kt b/app/src/main/java/com/example/camcontrol/Models.kt
index 9c8e1d6..7e2467b 100644
--- a/app/src/main/java/com/example/camcontrol/Models.kt
+++ b/app/src/main/java/com/example/camcontrol/Models.kt
@@ -9,7 +9,10 @@ data class ServerConnectionConfig(
val password: String
) {
fun getWebSocketUrl(): String {
- return "ws://$serverHost:$serverPort/ws/client/$roomId/$password"
+ // URL-encode roomId and password to handle special characters and avoid accidental mismatches
+ val encRoom = try { java.net.URLEncoder.encode(roomId, "UTF-8") } catch (e: Exception) { roomId }
+ val encPass = try { java.net.URLEncoder.encode(password, "UTF-8") } catch (e: Exception) { password }
+ return "ws://$serverHost:$serverPort/ws/client/$encRoom/$encPass"
}
}
@@ -41,4 +44,3 @@ object VideoCommands {
fun adjustQuality(quality: Int) = VideoCommand(type = "adjust_quality", quality = quality)
fun reset() = VideoCommand(type = "reset")
}
-
diff --git a/app/src/main/java/com/example/camcontrol/StreamViewModel.kt b/app/src/main/java/com/example/camcontrol/StreamViewModel.kt
index e75d76e..07e0e68 100644
--- a/app/src/main/java/com/example/camcontrol/StreamViewModel.kt
+++ b/app/src/main/java/com/example/camcontrol/StreamViewModel.kt
@@ -98,8 +98,34 @@ class StreamViewModel : ViewModel() {
private fun onMessage(message: String) {
Log.d("StreamViewModel", "Message received: $message")
viewModelScope.launch {
- if (!message.contains("ping")) {
- updateStatus("Получено: $message")
+ try {
+ // Try to parse as ConnectionResponse
+ val gson = com.google.gson.Gson()
+ val connectionResponse = try {
+ gson.fromJson(message, ConnectionResponse::class.java)
+ } catch (e: Exception) {
+ null
+ }
+
+ if (connectionResponse != null && (connectionResponse.client_id != null || connectionResponse.success)) {
+ Log.d("StreamViewModel", "ConnectionResponse: success=${connectionResponse.success}, client_id=${connectionResponse.client_id}, room_id=${connectionResponse.room_id}, error=${connectionResponse.error}")
+ if (connectionResponse.success) {
+ updateStatus("Сессия создана. Client ID: ${connectionResponse.client_id ?: "-"}")
+ } else {
+ updateStatus("Ошибка на сервере: ${connectionResponse.error ?: "unknown"}")
+ _connectionState.value = ConnectionState.Error(connectionResponse.error ?: "Server error")
+ }
+ } else {
+ // General message handling
+ if (!message.contains("ping")) {
+ updateStatus("Получено: $message")
+ }
+ }
+ } catch (e: Exception) {
+ Log.e("StreamViewModel", "Failed to handle message: ${e.message}")
+ if (!message.contains("ping")) {
+ updateStatus("Получено: $message")
+ }
}
}
}
@@ -173,4 +199,3 @@ sealed class ConnectionState {
object Disconnected : ConnectionState()
data class Error(val message: String) : ConnectionState()
}
-
diff --git a/app/src/main/java/com/example/camcontrol/WebSocketManager.kt b/app/src/main/java/com/example/camcontrol/WebSocketManager.kt
index b86c114..7cb280f 100644
--- a/app/src/main/java/com/example/camcontrol/WebSocketManager.kt
+++ b/app/src/main/java/com/example/camcontrol/WebSocketManager.kt
@@ -79,7 +79,16 @@ class WebSocketManager(
fun isConnected(): Boolean = webSocket != null
override fun onOpen(webSocket: WebSocket, response: Response) {
- Log.d("WebSocket", "Connected!")
+ Log.d("WebSocket", "Connected! Response code=${response.code}, message=${response.message}")
+ try {
+ val headers = response.headers
+ for (i in 0 until headers.size) {
+ Log.d("WebSocket", "Header: ${headers.name(i)}=${headers.value(i)}")
+ }
+ Log.d("WebSocket", "Request url: ${response.request.url}")
+ } catch (e: Exception) {
+ Log.w("WebSocket", "Failed to log headers: ${e.message}")
+ }
onConnected()
}
@@ -105,4 +114,3 @@ class WebSocketManager(
onDisconnected()
}
}
-
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..487da94
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+ 192.168.0.112
+
+
+