git.iko.soy/opencode-android
on 29df003 help sign in
61 lines 2.3 kB history raw
1package soy.iko.opencode
3import android.app.Application
4import android.content.Context
5import androidx.core.content.edit
6import androidx.lifecycle.AndroidViewModel
7import androidx.lifecycle.viewModelScope
8import kotlinx.coroutines.flow.distinctUntilChangedBy
9import kotlinx.coroutines.launch
10import soy.iko.opencode.core.Event
11import soy.iko.opencode.core.OpencodeCore
13/**
14 * Lifecycle-scoped host for the [OpencodeCore] so a single core (and its SSE
15 * connection) survives configuration changes. It also persists the last server
16 * URL / username so reconnecting is one tap.
17 */
18class CoreViewModel(app: Application) : AndroidViewModel(app) {
19 private val prefs = app.getSharedPreferences("opencode", Context.MODE_PRIVATE)
21 val core = OpencodeCore(viewModelScope)
23 init {
24 prefs.getString(KEY_URL, null)?.let { core.dispatch(Event.ServerUrlChanged(it)) }
25 prefs.getString(KEY_USER, null)?.let { core.dispatch(Event.UsernameChanged(it)) }
27 // On a fresh process after a configuration change, resume the SSE stream if
28 // the core is already connected (no-op otherwise — it guards on `connected`).
29 core.resumeStreamingIfConnected()
31 // Returning users shouldn't have to tap Connect: if a URL was restored and we
32 // aren't already connected, kick off the connection attempt on launch. The core
33 // handles an empty/invalid URL, so this only fires when there's something to try.
34 core.view.value.let { restored ->
35 if (restored.serverUrl.isNotEmpty() && !restored.connected) {
36 core.dispatch(Event.Connect)
37 }
38 }
40 // Persist connection details once a connection succeeds.
41 viewModelScope.launch {
42 core.view.distinctUntilChangedBy { it.connected to it.serverUrl }.collect { state ->
43 if (state.connected) {
44 prefs.edit {
45 putString(KEY_URL, state.serverUrl)
46 putString(KEY_USER, state.username)
47 }
48 }
49 }
50 }
51 }
53 override fun onCleared() {
54 core.shutdown()
55 }
57 private companion object {
58 const val KEY_URL = "serverUrl"
59 const val KEY_USER = "username"
60 }