When paired with AITURK IDE: - an "unknown method" (-32601) answer and the proxy's 403/route-404 are shown as plain sentences, never as raw JsonRpcError text; a method the IDE does not have is not sent again on the same socket - Account connectors, Vault, Keys and Files are hidden (the IDE has no connectors.* / vault.* and its phone proxy refuses /api/env and /api/files) - an idle-closed chat socket is reopened when the app returns to the foreground; idle tunnel connections are dropped on a network change - an unsaved chat no longer polls /api/sessions/<id> - the pairing screen shows the app version A plain Hermes connection is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B8ppceaR5s6cvMnm7uGRnf
70 lines
2.7 KiB
Kotlin
70 lines
2.7 KiB
Kotlin
package com.m57.hermescontrol
|
|
|
|
import android.app.Application
|
|
import android.os.Build
|
|
import coil3.ImageLoader
|
|
import coil3.PlatformContext
|
|
import coil3.SingletonImageLoader
|
|
import coil3.gif.AnimatedImageDecoder
|
|
import coil3.gif.GifDecoder
|
|
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
|
import coil3.request.crossfade
|
|
import com.m57.hermescontrol.data.local.AuthManager
|
|
import com.m57.hermescontrol.data.local.SessionListCacheStore
|
|
import com.m57.hermescontrol.data.remote.NetworkMonitor
|
|
import com.m57.hermescontrol.data.remote.OkHttpProvider
|
|
import com.m57.hermescontrol.notification.TurnCorrelationTracker
|
|
import com.m57.hermescontrol.ui.analytics.AnalyticsPreloader
|
|
import com.m57.hermescontrol.ui.chat.cleanStalePastedImages
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.SupervisorJob
|
|
import kotlinx.coroutines.flow.first
|
|
import kotlinx.coroutines.launch
|
|
|
|
class HermesControlApp :
|
|
Application(),
|
|
SingletonImageLoader.Factory {
|
|
private val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
|
|
|
override fun onCreate() {
|
|
super.onCreate()
|
|
val startupTimeMs = System.currentTimeMillis()
|
|
appScope.launch(Dispatchers.IO) {
|
|
cleanStalePastedImages(cacheDir, startupTimeMs)
|
|
}
|
|
AuthManager.init(this)
|
|
NetworkMonitor.init(this)
|
|
com.m57.hermescontrol.data.aiturk.AiturkCompat
|
|
.init(this)
|
|
SessionListCacheStore.init(this)
|
|
// Reply-notification turn boundaries survive process death (armed before
|
|
// each mobile prompt, consumed by the matching completion).
|
|
TurnCorrelationTracker.attach(this)
|
|
appScope.launch {
|
|
AuthManager.initializationState.first { it == AuthManager.InitializationState.Ready }
|
|
// Issue #537 follow-up (A): preload analytics in the background after launch
|
|
// so the tab renders instantly when opened (the usage endpoint is slow on a
|
|
// cold backend). Fire-and-forget; never blocks UI startup.
|
|
AnalyticsPreloader.preload(this@HermesControlApp)
|
|
}
|
|
}
|
|
|
|
override fun newImageLoader(context: PlatformContext): ImageLoader =
|
|
ImageLoader
|
|
.Builder(context)
|
|
.components {
|
|
add(
|
|
OkHttpNetworkFetcherFactory(
|
|
callFactory = { OkHttpProvider.base },
|
|
),
|
|
)
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
add(AnimatedImageDecoder.Factory())
|
|
} else {
|
|
add(GifDecoder.Factory())
|
|
}
|
|
}.crossfade(true)
|
|
.build()
|
|
}
|