89 lines
3.7 KiB
Kotlin
89 lines
3.7 KiB
Kotlin
package pw.binom.viewmate.glasses
|
|
|
|
import android.app.Application
|
|
import android.content.Context
|
|
import com.rayneo.arsdk.android.MercurySDK
|
|
import java.io.File
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
|
|
/** Конфигурация очков: адрес WS-сервера телефона. Креды не нужны — очки просто экран. */
|
|
object GlassesConfig {
|
|
// Fallback: эмулятор — 10.0.2.2 (localhost хоста); на устройстве телефон
|
|
// находится авто-обнаружением по mDNS (_viewmate._tcp).
|
|
const val HOST_URL = "ws://10.0.2.2:8080/ws/glasses"
|
|
}
|
|
|
|
/**
|
|
* Application очков: создаёт и запускает HostConnection (WS-клиент к телефону).
|
|
* Синглтон-доступ через companion.
|
|
*/
|
|
class GlassesApp : Application() {
|
|
|
|
lateinit var hostConnection: HostConnection
|
|
private set
|
|
|
|
lateinit var movieController: MovieController
|
|
private set
|
|
|
|
/** Менеджер скачивания контента в память очков (отправку на телефон — через HostConnection). */
|
|
lateinit var downloadManager: GlassesDownloadManager
|
|
private set
|
|
|
|
private val prefs by lazy {
|
|
getSharedPreferences("viewmate_prefs", Context.MODE_PRIVATE)
|
|
}
|
|
|
|
/** Масштаб экрана очков (0.5..1.0). Загружается в onCreate (prefs — после привязки контекста). */
|
|
val scale = MutableStateFlow(1f)
|
|
|
|
/** Идёт распознавание речи (TripleClick стартовал, Click/DoubleClick/тишина завершили). */
|
|
val listening = MutableStateFlow(false)
|
|
|
|
/** Накопленный текст распознавания (для оверлея); обновляется на SttPhrase. */
|
|
val sttText = MutableStateFlow("")
|
|
|
|
/** Текст ответа ассистента (обновляется на ShowText); остаётся до новой сессии. */
|
|
val assistantText = MutableStateFlow("")
|
|
|
|
/** Текущая Activity (для закрытия приложения по команде с телефона). */
|
|
var mainActivity: MainActivity? = null
|
|
|
|
/** Применить и сохранить масштаб. */
|
|
fun applyScale(value: Float) {
|
|
val v = value.coerceIn(0.5f, 1f)
|
|
scale.value = v
|
|
prefs.edit().putFloat("scale", v).apply()
|
|
}
|
|
|
|
override fun onCreate() {
|
|
super.onCreate()
|
|
instance = this
|
|
scale.value = prefs.getFloat("scale", 1f).coerceIn(0.5f, 1f)
|
|
MercurySDK.init(this)
|
|
movieController = MovieController(applicationContext)
|
|
movieController.eventLogger = { msg -> logToFile("mc: $msg") }
|
|
downloadManager = GlassesDownloadManager(applicationContext) { msg -> hostConnection.sendToHost(msg) }
|
|
hostConnection = HostConnection(
|
|
fallbackUrl = GlassesConfig.HOST_URL,
|
|
movieController = movieController,
|
|
downloadManager = downloadManager,
|
|
context = applicationContext,
|
|
)
|
|
hostConnection.start()
|
|
log("app", "HostConnection стартует: mDNS-поиск, fallback: ${GlassesConfig.HOST_URL}")
|
|
}
|
|
|
|
companion object {
|
|
lateinit var instance: GlassesApp
|
|
private set
|
|
|
|
/** Диагностические события в filesDir/events.log (доступно из любой точки, в т.ч. MovieController). */
|
|
fun logToFile(msg: String) {
|
|
runCatching {
|
|
val f = File(instance.filesDir, "events.log")
|
|
f.appendText("${System.currentTimeMillis()} $msg\n")
|
|
}
|
|
}
|
|
}
|
|
}
|