nodes: better default display names
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
package com.steipete.clawdis.node
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
|
||||
object DeviceNames {
|
||||
fun bestDefaultNodeName(context: Context): String {
|
||||
val deviceName =
|
||||
runCatching {
|
||||
Settings.Global.getString(context.contentResolver, "device_name")
|
||||
}
|
||||
.getOrNull()
|
||||
?.trim()
|
||||
.orEmpty()
|
||||
|
||||
if (deviceName.isNotEmpty()) return deviceName
|
||||
|
||||
val model =
|
||||
listOfNotNull(Build.MANUFACTURER?.takeIf { it.isNotBlank() }, Build.MODEL?.takeIf { it.isNotBlank() })
|
||||
.joinToString(" ")
|
||||
.trim()
|
||||
|
||||
return model.ifEmpty { "Android Node" }
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import java.util.UUID
|
||||
class SecurePrefs(context: Context) {
|
||||
companion object {
|
||||
val defaultWakeWords: List<String> = listOf("clawd", "claude")
|
||||
private const val displayNameKey = "node.displayName"
|
||||
}
|
||||
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
@@ -35,7 +36,8 @@ class SecurePrefs(context: Context) {
|
||||
private val _instanceId = MutableStateFlow(loadOrCreateInstanceId())
|
||||
val instanceId: StateFlow<String> = _instanceId
|
||||
|
||||
private val _displayName = MutableStateFlow(prefs.getString("node.displayName", "Android Node")!!)
|
||||
private val _displayName =
|
||||
MutableStateFlow(loadOrMigrateDisplayName(context = context))
|
||||
val displayName: StateFlow<String> = _displayName
|
||||
|
||||
private val _cameraEnabled = MutableStateFlow(prefs.getBoolean("camera.enabled", true))
|
||||
@@ -68,7 +70,7 @@ class SecurePrefs(context: Context) {
|
||||
|
||||
fun setDisplayName(value: String) {
|
||||
val trimmed = value.trim()
|
||||
prefs.edit().putString("node.displayName", trimmed).apply()
|
||||
prefs.edit().putString(displayNameKey, trimmed).apply()
|
||||
_displayName.value = trimmed
|
||||
}
|
||||
|
||||
@@ -116,6 +118,17 @@ class SecurePrefs(context: Context) {
|
||||
return fresh
|
||||
}
|
||||
|
||||
private fun loadOrMigrateDisplayName(context: Context): String {
|
||||
val existing = prefs.getString(displayNameKey, null)?.trim().orEmpty()
|
||||
if (existing.isNotEmpty() && existing != "Android Node") return existing
|
||||
|
||||
val candidate = DeviceNames.bestDefaultNodeName(context).trim()
|
||||
val resolved = candidate.ifEmpty { "Android Node" }
|
||||
|
||||
prefs.edit().putString(displayNameKey, resolved).apply()
|
||||
return resolved
|
||||
}
|
||||
|
||||
fun setWakeWords(words: List<String>) {
|
||||
val sanitized = WakeWords.sanitize(words, defaultWakeWords)
|
||||
val encoded =
|
||||
|
||||
@@ -126,7 +126,7 @@ final class BridgeConnectionController {
|
||||
private func makeHello(token: String) -> BridgeHello {
|
||||
let defaults = UserDefaults.standard
|
||||
let nodeId = defaults.string(forKey: "node.instanceId") ?? "ios-node"
|
||||
let displayName = defaults.string(forKey: "node.displayName") ?? "iOS Node"
|
||||
let displayName = self.resolvedDisplayName(defaults: defaults)
|
||||
|
||||
return BridgeHello(
|
||||
nodeId: nodeId,
|
||||
@@ -139,6 +139,21 @@ final class BridgeConnectionController {
|
||||
caps: self.currentCaps())
|
||||
}
|
||||
|
||||
private func resolvedDisplayName(defaults: UserDefaults) -> String {
|
||||
let key = "node.displayName"
|
||||
let existing = defaults.string(forKey: key)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
if !existing.isEmpty, existing != "iOS Node" { return existing }
|
||||
|
||||
let deviceName = UIDevice.current.name.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let candidate = deviceName.isEmpty ? "iOS Node" : deviceName
|
||||
|
||||
if existing.isEmpty || existing == "iOS Node" {
|
||||
defaults.set(candidate, forKey: key)
|
||||
}
|
||||
|
||||
return candidate
|
||||
}
|
||||
|
||||
private func currentCaps() -> [String] {
|
||||
var caps = ["canvas"]
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ let package = Package(
|
||||
.product(name: "PeekabooBridge", package: "PeekabooCore"),
|
||||
.product(name: "PeekabooAutomationKit", package: "PeekabooAutomationKit"),
|
||||
],
|
||||
exclude: [
|
||||
// Legacy web-based WebChat assets (SwiftUI-only WebChat doesn't use these).
|
||||
"Resources/WebChat",
|
||||
],
|
||||
resources: [
|
||||
.copy("Resources/Clawdis.icns"),
|
||||
.copy("Resources/CanvasA2UI"),
|
||||
|
||||
40
docs/device-models.md
Normal file
40
docs/device-models.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Device model database (friendly names)
|
||||
|
||||
The macOS companion app shows friendly Apple device model names in the **Instances** UI by mapping Apple model identifiers (e.g. `iPad16,6`, `Mac16,6`) to human-readable names.
|
||||
|
||||
The mapping is vendored as JSON under:
|
||||
|
||||
- `apps/macos/Sources/Clawdis/Resources/DeviceModels/`
|
||||
|
||||
## Data source
|
||||
|
||||
We currently vendor the mapping from the MIT-licensed repository:
|
||||
|
||||
- `kyle-seongwoo-jun/apple-device-identifiers`
|
||||
|
||||
To keep builds deterministic, the JSON files are pinned to specific upstream commits (recorded in `apps/macos/Sources/Clawdis/Resources/DeviceModels/NOTICE.md`).
|
||||
|
||||
## Updating the database
|
||||
|
||||
1. Pick the upstream commits you want to pin to (one for iOS, one for macOS).
|
||||
2. Update the commit hashes in `apps/macos/Sources/Clawdis/Resources/DeviceModels/NOTICE.md`.
|
||||
3. Re-download the JSON files, pinned to those commits:
|
||||
|
||||
```bash
|
||||
IOS_COMMIT="<commit sha for ios-device-identifiers.json>"
|
||||
MAC_COMMIT="<commit sha for mac-device-identifiers.json>"
|
||||
|
||||
curl -fsSL "https://raw.githubusercontent.com/kyle-seongwoo-jun/apple-device-identifiers/${IOS_COMMIT}/ios-device-identifiers.json" \
|
||||
-o apps/macos/Sources/Clawdis/Resources/DeviceModels/ios-device-identifiers.json
|
||||
|
||||
curl -fsSL "https://raw.githubusercontent.com/kyle-seongwoo-jun/apple-device-identifiers/${MAC_COMMIT}/mac-device-identifiers.json" \
|
||||
-o apps/macos/Sources/Clawdis/Resources/DeviceModels/mac-device-identifiers.json
|
||||
```
|
||||
|
||||
4. Ensure `apps/macos/Sources/Clawdis/Resources/DeviceModels/LICENSE.apple-device-identifiers.txt` still matches upstream (replace it if the upstream license changes).
|
||||
5. Verify the macOS app builds cleanly (no warnings):
|
||||
|
||||
```bash
|
||||
swift build --package-path apps/macos
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user