From 752b2fb1cadccce4aaab51dc2d6022bc727692d5 Mon Sep 17 00:00:00 2001 From: "Andrew K. Choi" Date: Wed, 3 Dec 2025 20:46:36 +0900 Subject: [PATCH] global fix --- .idea/copilotDiffState.xml | 35 ----------- app/src/main/AndroidManifest.xml | 1 + .../com/example/camcontrol/CameraManager.kt | 5 +- .../com/example/camcontrol/MainActivity.kt | 62 +++++++++++-------- .../java/com/example/camcontrol/Models.kt | 6 +- .../com/example/camcontrol/StreamViewModel.kt | 31 +++++++++- .../example/camcontrol/WebSocketManager.kt | 12 +++- .../main/res/xml/network_security_config.xml | 11 ++++ 8 files changed, 95 insertions(+), 68 deletions(-) delete mode 100644 .idea/copilotDiffState.xml create mode 100644 app/src/main/res/xml/network_security_config.xml 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 + + +