diff --git a/backend/src/main/kotlin/meatbag/backend/Application.kt b/backend/src/main/kotlin/meatbag/backend/Application.kt index af31592..868157d 100644 --- a/backend/src/main/kotlin/meatbag/backend/Application.kt +++ b/backend/src/main/kotlin/meatbag/backend/Application.kt @@ -125,8 +125,8 @@ fun Application.module() { } } - // Send pairing success indicator screen only if we actually paired in this session - if (showedPairingScreen) { + // Send pairing success indicator screen only if we actually paired in this session AND no specific profile was requested + if (showedPairingScreen && profileId == null) { val successMessage = Message( id = "pairing_success_$deviceId", title = "Pairing Successful", diff --git a/client/src/androidMain/kotlin/meatbag/client/MainActivity.kt b/client/src/androidMain/kotlin/meatbag/client/MainActivity.kt index 65d7632..fbbfefd 100644 --- a/client/src/androidMain/kotlin/meatbag/client/MainActivity.kt +++ b/client/src/androidMain/kotlin/meatbag/client/MainActivity.kt @@ -95,6 +95,11 @@ class MainActivity : ComponentActivity() { // SharedPreferences for connection details val prefs = getSharedPreferences("meatbag_prefs", Context.MODE_PRIVATE) + val deviceId = prefs.getString("device_id", null) ?: run { + val newId = java.util.UUID.randomUUID().toString() + prefs.edit().putString("device_id", newId).apply() + newId + } setContent { var host by remember { mutableStateOf(prefs.getString("host", "10.0.0.7") ?: "10.0.0.7") } @@ -110,18 +115,21 @@ class MainActivity : ComponentActivity() { var errorMessage by remember { mutableStateOf(null) } var activeProfileId by remember { mutableStateOf(intent.getStringExtra("LAUNCH_PROFILE_ID")) } + var isInitialLaunch by remember { mutableStateOf(true) } LaunchedEffect(Unit) { onProfileLaunch = { id -> activeProfileId = id + isInitialLaunch = true } } - // Auto-connect when a specific profile is launched via shortcut or intent + // Auto-connect when a specific profile is launched via shortcut or intent on startup/new intent LaunchedEffect(activeProfileId) { - if (activeProfileId != null && connectionState == ConnectionState.DISCONNECTED && clientState == null) { + if (isInitialLaunch && activeProfileId != null && connectionState == ConnectionState.DISCONNECTED && clientState == null) { + isInitialLaunch = false errorMessage = null scope.launch(Dispatchers.Default) { - val newClient = MeatbagClient(host.trim(), portStr.trim().toIntOrNull() ?: 8080, feedback) + val newClient = MeatbagClient(host.trim(), portStr.trim().toIntOrNull() ?: 8080, feedback, deviceId = deviceId) clientState = newClient newClient.connect(deviceType, activeProfileId) } @@ -380,6 +388,7 @@ class MainActivity : ComponentActivity() { Button( onClick = { + isInitialLaunch = false errorMessage = null // Save preferences prefs.edit().apply { @@ -405,7 +414,8 @@ class MainActivity : ComponentActivity() { host = host.trim(), port = portStr.trim().toIntOrNull() ?: 8080, attentionFeedback = feedback, - socksPort = socksPort + socksPort = socksPort, + deviceId = deviceId ) clientState = newClient newClient.connect(deviceType, activeProfileId) @@ -471,9 +481,10 @@ class MainActivity : ComponentActivity() { Button( onClick = { activeProfileId = "meatbag" + isInitialLaunch = false errorMessage = null scope.launch(Dispatchers.Default) { - val newClient = MeatbagClient(host.trim(), portStr.trim().toIntOrNull() ?: 8080, feedback) + val newClient = MeatbagClient(host.trim(), portStr.trim().toIntOrNull() ?: 8080, feedback, deviceId = deviceId) clientState = newClient newClient.connect(deviceType, "meatbag") } @@ -513,9 +524,10 @@ class MainActivity : ComponentActivity() { Button( onClick = { activeProfileId = "lm_studio_remote" + isInitialLaunch = false errorMessage = null scope.launch(Dispatchers.Default) { - val newClient = MeatbagClient(host.trim(), portStr.trim().toIntOrNull() ?: 8080, feedback) + val newClient = MeatbagClient(host.trim(), portStr.trim().toIntOrNull() ?: 8080, feedback, deviceId = deviceId) clientState = newClient newClient.connect(deviceType, "lm_studio_remote") } diff --git a/client/src/commonMain/kotlin/meatbag/client/MeatbagClient.kt b/client/src/commonMain/kotlin/meatbag/client/MeatbagClient.kt index cdffc2d..e07708d 100644 --- a/client/src/commonMain/kotlin/meatbag/client/MeatbagClient.kt +++ b/client/src/commonMain/kotlin/meatbag/client/MeatbagClient.kt @@ -35,7 +35,8 @@ class MeatbagClient( private val host: String = "localhost", private val port: Int = 8080, private val attentionFeedback: AttentionFeedback = NoOpAttentionFeedback, - private val socksPort: Int? = null + private val socksPort: Int? = null, + private val deviceId: String? = null ) { private val jsonConfig = Json { ignoreUnknownKeys = true @@ -76,10 +77,17 @@ class MeatbagClient( connectionJob = CoroutineScope(Dispatchers.Default).launch { while (isActive) { try { - val queryParams = if (profileId != null) { - "?deviceType=$deviceType&profileId=$profileId" - } else { - "?deviceType=$deviceType" + val queryParams = buildString { + append("?deviceType=") + append(deviceType) + if (profileId != null) { + append("&profileId=") + append(profileId) + } + if (deviceId != null) { + append("&deviceId=") + append(deviceId) + } } log("Connecting to ws://$host:$port/ws/connect$queryParams ...") _connectionState.value = ConnectionState.CONNECTING