git.iko.soy/opencode-android
on master help sign in
Fix lint warnings, preview flash, and refresh race in session list
commitcea6f433b4ff285298b15977079f677982397105 authoriko <mail@iko.soy> dateTue 30 Jun 2026, 05:20 (3 months ago) parent2ec6140
5 files changed+11−18
app/src/main/AndroidManifest.xml+3−1 app/src/main/java/soy/iko/opencode/notification/NotificationChannels.kt−2 app/src/main/java/soy/iko/opencode/notification/RunForegroundService.kt+1−6 app/src/main/java/soy/iko/opencode/ui/session/SessionListViewModel.kt+7−2 app/src/main/res/values/strings.xml−7
app/src/main/AndroidManifest.xml+3−1
@@ -1,5 +1,6 @@
11<?xml version="1.0" encoding="utf-8"?>
2−<manifest xmlns:android="http://schemas.android.com/apk/res/android">
2+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+ xmlns:tools="http://schemas.android.com/tools">
34
45 <uses-permission android:name="android.permission.INTERNET" />
56 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -24,6 +25,7 @@
2425 android:launchMode="singleTop"
2526 android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboardHidden|uiMode|navigation"
2627 android:enableOnBackInvokedCallback="true"
28+ tools:targetApi="33"
2729 android:theme="@style/Theme.OpencodeAndroid.Splash">
2830 <intent-filter>
2931 <action android:name="android.intent.action.MAIN" />
app/src/main/java/soy/iko/opencode/notification/NotificationChannels.kt−2
@@ -3,7 +3,6 @@ package soy.iko.opencode.notification
33import android.app.NotificationChannel
44import android.app.NotificationManager
55import android.content.Context
6−import android.os.Build
76import soy.iko.opencode.R
87
98/**
@@ -19,7 +18,6 @@ object NotificationChannels {
1918 const val COMPLETED = "session_completed"
2019
2120 fun create(context: Context) {
22− if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
2321 val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager ?: return
2422 nm.createNotificationChannel(
2523 NotificationChannel(STATUS, context.getString(R.string.notif_channel_status), NotificationManager.IMPORTANCE_LOW).apply {
app/src/main/java/soy/iko/opencode/notification/RunForegroundService.kt+1−6
@@ -72,12 +72,7 @@ class RunForegroundService : Service() {
7272 private const val NOTIF_ID = 1
7373
7474 fun start(context: Context) {
75− val intent = Intent(context, RunForegroundService::class.java)
76− if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
77− context.startForegroundService(intent)
78− } else {
79− context.startService(intent)
80− }
75+ context.startForegroundService(Intent(context, RunForegroundService::class.java))
8176 }
8277
8378 fun stop(context: Context) {
app/src/main/java/soy/iko/opencode/ui/session/SessionListViewModel.kt+7−2
@@ -90,6 +90,7 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
9090 fun clearTransientError() { _transientError.value = null }
9191
9292 private var previewJob: Job? = null
93+ private var refreshJob: Job? = null
9394
9495 /** Per-session in-flight preview loads, so rapid SSE events for the same session
9596 * coalesce into a single request instead of firing one per event. Accessed from
@@ -166,7 +167,8 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
166167 _serverLabel.value = conn.profile.displayLabel
167168 _state.update { it.copy(loading = true, error = null) }
168169 _refreshing.value = true
169− viewModelScope.launch {
170+ refreshJob?.cancel()
171+ refreshJob = viewModelScope.launch {
170172 runCatching { conn.repository.listSessions() }
171173 .onSuccess { list ->
172174 val sorted = list.sortedByDescending { it.time?.updated ?: it.time?.created ?: 0 }
@@ -212,7 +214,10 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
212214 previewJob?.cancel()
213215 val conn = container.activeConnection.value ?: return
214216 val api = conn.api
215− _state.update { it.copy(previews = emptyMap()) }
217+ // Keep previews for sessions still in the list; drop stale ones without
218+ // clearing the whole map (which would cause a visual flash).
219+ val keepIds = sessions.mapTo(mutableSetOf()) { it.id }
220+ _state.update { s -> s.copy(previews = s.previews.filterKeys { it in keepIds }) }
216221 previewJob = viewModelScope.launch {
217222 val semaphore = Semaphore(NetworkConfig.maxConcurrentPreviews)
218223 sessions.take(NetworkConfig.maxPreviewSessions).map { session ->
app/src/main/res/values/strings.xml−7
@@ -5,7 +5,6 @@
55
66 <!-- Common -->
77 <string name="back">Back</string>
8− <string name="loading">Loading</string>
98 <string name="cancel">Cancel</string>
109 <string name="save">Save</string>
1110 <string name="delete">Delete</string>
@@ -89,7 +88,6 @@
8988 <!-- Errors (view models) -->
9089 <string name="error_generic">Something went wrong.</string>
9190 <string name="error_client_status">Request failed (%1$d).</string>
92− <string name="error_failed_to_send">Failed to send</string>
9391 <string name="error_agent_reported">The agent reported an error.</string>
9492 <string name="error_not_reachable">Could not reach %1$s</string>
9593 <string name="error_timeout">The request timed out. Check the connection and try again.</string>
@@ -102,7 +100,6 @@
102100 <string name="show_less">Show less</string>
103101 <string name="tool_completed">Completed</string>
104102 <string name="tool_error">Error</string>
105− <string name="tool_running">In progress</string>
106103 <string name="state_expanded">Expanded</string>
107104 <string name="state_collapsed">Collapsed</string>
108105
@@ -121,9 +118,6 @@
121118 <string name="default_agent">Default</string>
122119 <string name="default_agent_desc">Server default agent</string>
123120 <string name="no_commands">No commands reported by the server.</string>
124− <string name="loading_models">Loading models…</string>
125− <string name="loading_agents">Loading agents…</string>
126− <string name="loading_commands">Loading commands…</string>
127121 <string name="saving">Saving…</string>
128122 <string name="image_failed">Failed to load image</string>
129123
@@ -163,7 +157,6 @@
163157 <string name="no_crash_reports">No crashes recorded. \ud83d\udc4d</string>
164158 <string name="clear_all">Clear all</string>
165159 <string name="crash_report">Crash report</string>
166− <string name="diagnostics_share_subject">opencode-android crash report</string>
167160
168161 <!-- Notifications -->
169162 <string name="notif_channel_status">Agent activity</string>