package com.sptmobile.link import android.content.Context import android.os.Build import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import java.util.UUID import kotlinx.coroutines.flow.first private val Context.deviceNameStore by preferencesDataStore(name = "device_name") /** * The device string this phone is known by on every paired host. `pair` * registers the host-side spool under it and `spoolDrain` reads back by it — * the two MUST use the same value, which is why it lives here and not inline * in either caller. * * `MODEL-`: [Build.MODEL] alone collides — two phones of the same * model pairing with one host would share a spool (each drain-committing the * other's messages away). The per-install random suffix is minted once and * persisted, so the name is stable across restarts and re-pairs for the life * of the install. */ // [impl->REQ-INBOUND-NOTIFS] object DeviceName { private val suffixKey = stringPreferencesKey("suffix") @Volatile private var cached: String? = null suspend fun value(context: Context): String { cached?.let { return it } val store = context.applicationContext.deviceNameStore var suffix = store.data.first()[suffixKey] if (suffix == null) { // Mint inside edit so a racing first-read can't double-mint. store.edit { prefs -> if (prefs[suffixKey] == null) { prefs[suffixKey] = UUID.randomUUID().toString().take(8) } } suffix = store.data.first()[suffixKey] } return compose(Build.MODEL, suffix.orEmpty()).also { cached = it } } /** Pure name shape, JVM-testable: blank/absent model falls back. */ fun compose(model: String?, suffix: String): String { val base = model?.takeIf { it.isNotBlank() } ?: "spt-mobile" return if (suffix.isBlank()) base else "$base-$suffix" } }