From aacd4e6bd723fb6f9aa389d979f3bc7104eb8db2 Mon Sep 17 00:00:00 2001 From: Z User Date: Thu, 12 Nov 2026 16:51:00 +0000 Subject: [PATCH] =?UTF-8?q?fix(ui):=20lint-clean=20LogsScreen=20=E2=80=94?= =?UTF-8?q?=20composition-safe=20resources=20and=20remembered=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lintDebug aborts the build with three errors introduced with the diagnostics screen: - context.getString() inside the composable (share subject and chooser label) trips LocalContextGetResourceValueCall — resolve both strings with stringResource() in composition instead; - derivedStateOf without remember (UnrememberedMutableState) rebuilt its state object on every recomposition — wrap it in remember. Verified locally: :app:lintDebug passes with 0 errors; unit tests green. --- .../oustery/opencodephone/ui/logs/LogsScreen.kt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/github/oustery/opencodephone/ui/logs/LogsScreen.kt b/app/src/main/java/io/github/oustery/opencodephone/ui/logs/LogsScreen.kt index a79bd37..fcf5efc 100644 --- a/app/src/main/java/io/github/oustery/opencodephone/ui/logs/LogsScreen.kt +++ b/app/src/main/java/io/github/oustery/opencodephone/ui/logs/LogsScreen.kt @@ -70,10 +70,10 @@ fun LogsScreen(graph: io.github.oustery.opencodephone.AppGraph) { entry.error?.contains(query, ignoreCase = true) == true) } } - val atBottom by derivedStateOf { + val atBottom by remember { derivedStateOf { val last = listState.layoutInfo.visibleItemsInfo.lastOrNull() last == null || last.index >= listState.layoutInfo.totalItemsCount - 2 - } + } } LaunchedEffect(filtered.size, autoScroll) { if (autoScroll && filtered.isNotEmpty() && atBottom) { listState.scrollToItem(filtered.size - 1) @@ -82,6 +82,11 @@ fun LogsScreen(graph: io.github.oustery.opencodephone.AppGraph) { val export = remember(filtered) { AppLog.exportText() } val context = androidx.compose.ui.platform.LocalContext.current + // Resolve in composition: stringResource() is configuration-aware, while + // context.getString() in a composable trips lint's + // LocalContextGetResourceValueCall and can go stale on config changes. + val shareSubject = stringResource(R.string.logs_share_subject) + val shareLabel = stringResource(R.string.logs_share) ScreenHeader( title = stringResource(R.string.logs_title), @@ -98,13 +103,10 @@ fun LogsScreen(graph: io.github.oustery.opencodephone.AppGraph) { val intent = android.content.Intent(android.content.Intent.ACTION_SEND).apply { type = "text/plain" putExtra(android.content.Intent.EXTRA_TEXT, export.take(90_000)) - putExtra( - android.content.Intent.EXTRA_SUBJECT, - context.getString(R.string.logs_share_subject), - ) + putExtra(android.content.Intent.EXTRA_SUBJECT, shareSubject) } context.startActivity( - android.content.Intent.createChooser(intent, context.getString(R.string.logs_share)), + android.content.Intent.createChooser(intent, shareLabel), ) }) { Icon(