fix: resolve compiler warnings across modules

Clears real Kotlin compiler warnings surfaced across quartz, cli,
relayBench, amethyst, and desktopApp:

- quartz Sha256/EventHasher/ScratchLocal: ThreadLocal.get() is nullable
  in Kotlin; assert non-null (withInitial never yields null).
- quartz GitHttpClient: PriorityQueue.poll() under isNotEmpty() is
  non-null; assert it.
- relayBench CorpusDownloader: drop redundant !! on smart-cast Long;
  Jackson fields() -> properties().
- cli GrapeRankCommand: drop redundant ?. where latest is smart-cast.
- PodcastRemoteContent: OkHttp body is non-null; drop dead elvis.
- Dead/redundant expressions: remove no-op when-branch values and a
  redundant trailing Unit (HomeScreen, LocalCache, EmbeddedTabLayer,
  ParticipantHostActionsSheet, NestActionBar, ControlWhenPlayerIsActive,
  ShareNoteAsImageScreen exhaustive-when else).
- CalendarEventDetailScreen / SetPasswordDialog / ProfileClinkOfferResolver:
  drop always-true conditions (reorder to keep smart-casts).
- WalletColumnScreen: OkHttp body non-null; drop unreachable null-guards.
- PcmTapRegistry: the @OptIn used androidx.annotation.OptIn, which does
  not opt into Kotlin's ExperimentalCoroutinesApi; use kotlin.OptIn.
- GitRepositoryScreen: suppress the standard ViewModel-factory cast.
- PushNotificationReceiverService: suppress override-of-deprecated.
- Desktop GlobalScope call sites: @OptIn(DelicateCoroutinesApi::class).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016GMqkg1ndvFihEwZcENiRs
This commit is contained in:
Claude
2026-07-08 18:31:10 +00:00
parent 00246c6ae2
commit d9dee8967b
24 changed files with 36 additions and 45 deletions
@@ -2525,7 +2525,6 @@ object LocalCache : ILocalCache, ICacheProvider {
}
} catch (e: Exception) {
if (e is CancellationException) throw e
null
}
return liveChatChannels.filter { _, channel ->
@@ -108,9 +108,7 @@ fun ControlWhenPlayerIsActive(
}
}
else -> {
Unit
}
else -> {}
}
}
lifecycleOwner.lifecycle.addObserver(observer)
@@ -65,7 +65,7 @@ class SpectrumAudioBufferSink(
private var channels = 1
private var encoding = C.ENCODING_PCM_16BIT
@OptIn(ExperimentalCoroutinesApi::class)
@kotlin.OptIn(ExperimentalCoroutinesApi::class)
override fun flush(
sampleRateHz: Int,
channelCount: Int,
@@ -50,7 +50,7 @@ object PodcastRemoteContent {
.build()
okHttpClient.newCall(request).executeAsync().use { response ->
if (!response.isSuccessful) return@use null
val body = response.body ?: return@use null
val body = response.body
// Reject an oversized declared length outright; cap the read for chunked bodies.
if (body.contentLength() > MAX_BYTES) return@use null
body.string().take(MAX_BYTES.toInt())
@@ -285,8 +285,6 @@ fun ShareNoteAsImageScreen(
*finalState.params,
)
}
else -> {}
}
}
}
@@ -215,7 +215,7 @@ fun CalendarEventDetailScreen(
}
// The Edit affordance is only meaningful when the current account is the
// author — relays will reject a signed-by-stranger replacement.
if (isOwnEvent && event != null) {
if (isOwnEvent) {
IconButton(onClick = {
nav.nav(
Route.EditCalendarEvent(
@@ -559,7 +559,6 @@ fun EmbeddedTabLayer(barFavoriteIds: List<String>) {
"Copy" to {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.setPrimaryClip(ClipData.newPlainText("selection", pageSel.text))
Unit
},
),
onMagnify = onMagnify,
@@ -163,6 +163,7 @@ fun GitRepositoryPullsScreen(
internal class GitRepositoryBrowserViewModelFactory(
private val okHttpClient: (String) -> OkHttpClient,
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T = GitRepositoryBrowserViewModel(okHttpClient) as T
}
@@ -460,10 +460,10 @@ fun DisplayLiveBubbles(
val feedState by liveSection.feedContent.collectAsStateWithLifecycle()
when (val state = feedState) {
is ChannelFeedState.Empty -> null
is ChannelFeedState.FeedError -> null
is ChannelFeedState.Empty -> {}
is ChannelFeedState.FeedError -> {}
is ChannelFeedState.Loaded -> DisplayLiveBubbles(state, accountViewModel, nav)
is ChannelFeedState.Loading -> null
is ChannelFeedState.Loading -> {}
}
}
@@ -199,9 +199,7 @@ internal fun ParticipantHostActionsSheet(
)
}
null -> {
Unit
}
null -> {}
}
}
@@ -255,9 +255,7 @@ private fun StartCluster(
// On-stage controls live in [StageControlsBar]; audience
// has nothing to do here (system volume keys are enough).
is ConnectionUiState.Connected -> {
Unit
}
is ConnectionUiState.Connected -> {}
}
}
}
@@ -76,7 +76,7 @@ fun rememberProfileClinkOffer(
// Fall back to the NIP-05 .well-known clink_offer (cached per address).
val id = nip05?.let { Nip05Id.parse(it) }
offer =
if (id != null && nip05 != null) {
if (nip05 != null && id != null) {
// Distinguish "cache miss" from a cached "no offer" (null) so we don't refetch.
val cacheKey = nip05.lowercase()
val cached = clinkOfferNip05Cache.get(cacheKey)
@@ -86,6 +86,7 @@ class PushNotificationReceiverService : FirebaseMessagingService() {
super.onDestroy()
}
@Suppress("OVERRIDE_DEPRECATION")
override fun onNewToken(token: String) {
scope.launch(Dispatchers.IO) {
Log.d("PushNotificationService", "PushNotificationReceiverService.onNewToken")
@@ -568,7 +568,7 @@ object GrapeRankCommand {
"provider" to provider,
"relay" to relay.url,
"changed" to false,
"based_on" to latest?.id,
"based_on" to latest.id,
),
)
return 0
@@ -744,7 +744,7 @@ object GrapeRankCommand {
latest?.serviceProviders()?.any {
it.service == service && it.pubkey == providerPubkey && it.relayUrl == relay
} ?: false
if (alreadyListed) return latest?.id
if (alreadyListed) return latest.id
val tag = ServiceProviderTag(service, providerPubkey, relay)
val event =
@@ -60,6 +60,7 @@ import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.utils.DualCase
import com.vitorpamplona.quartz.utils.Log
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.BufferOverflow
@@ -711,6 +712,7 @@ class DesktopLocalCache : ICacheProvider {
* @param relay The relay this event came from
* @return true if event was processed, false if no matching request
*/
@OptIn(DelicateCoroutinesApi::class)
fun consume(
event: LnZapPaymentResponseEvent,
relay: NormalizedRelayUrl?,
@@ -104,7 +104,7 @@ fun SetPasswordDialog(
val submit: () -> Unit = {
val currentOk =
!isChange ||
(existingHash != null && PasswordHasher.verify(current.toCharArray(), existingHash))
PasswordHasher.verify(current.toCharArray(), existingHash)
when {
!currentOk -> {
currentError = "Wrong password"
@@ -103,6 +103,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
@@ -818,6 +819,7 @@ fun BoostsPopup(
/**
* Fetches metadata for multiple users in a single subscription.
*/
@OptIn(DelicateCoroutinesApi::class)
private suspend fun fetchMetadataForUsers(
pubKeys: List<String>,
relayManager: DesktopRelayConnectionManager,
@@ -1584,6 +1586,7 @@ private fun openLightningUri(bolt11: String) {
* Fetches user metadata on-demand to get lightning address.
* Returns the lightning address if found, null otherwise.
*/
@OptIn(DelicateCoroutinesApi::class)
private suspend fun fetchUserLightningAddress(
pubKey: String,
relayManager: DesktopRelayConnectionManager,
@@ -27,6 +27,7 @@ import com.vitorpamplona.amethyst.commons.feeds.custom.defaultFeeds
import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -38,6 +39,7 @@ private val feedPrefs: Preferences by lazy {
Preferences.userRoot().node("amethyst/feeds")
}
@OptIn(DelicateCoroutinesApi::class)
private val defaultRepository by lazy {
val repo = FeedDefinitionRepository(GlobalScope)
@@ -66,6 +68,7 @@ val LocalFeedRepository =
defaultRepository
}
@OptIn(DelicateCoroutinesApi::class)
val LocalFeedScope =
compositionLocalOf<CoroutineScope> {
GlobalScope
@@ -564,11 +564,7 @@ private fun SendDialog(
kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
httpClient.newCall(request).execute()
}
val body = response.body?.string()
if (body == null) {
sendState = SendState.Error("Failed to reach payment server", SendState.Idle)
return@LaunchedEffect
}
val body = response.body.string()
val json = mapper.readTree(body)
val callback = json.get("callback")?.asText()?.ifBlank { null }
if (callback == null) {
@@ -611,11 +607,7 @@ private fun SendDialog(
kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
httpClient.newCall(request).execute()
}
val body = response.body?.string()
if (body == null) {
sendState = SendState.Error("Failed to fetch invoice", SendState.Idle)
return@LaunchedEffect
}
val body = response.body.string()
val json = mapper.readTree(body)
val pr = json.get("pr")?.asText()?.ifBlank { null }
if (pr != null) {
@@ -24,8 +24,7 @@ package com.vitorpamplona.quartz.utils.secp256k1
internal actual class ScratchLocal<T> actual constructor(
initializer: () -> T,
) {
private val tl = ThreadLocal.withInitial(initializer)
private val tl: ThreadLocal<T> = ThreadLocal.withInitial(initializer)
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
actual fun get(): T = tl.get()
actual fun get(): T = tl.get()!!
}
@@ -127,7 +127,7 @@ actual object EventHasherSerializer {
content: String,
): Boolean {
val br: BufferRecycler = JacksonMapper.mapper.factory._getBufferRecycler()
val digest = threadLocalDigest.get()
val digest = threadLocalDigest.get()!!
val bb = HashingByteArrayBuilder(br, digest)
try {
val generator = JacksonMapper.mapper.createGenerator(bb, JsonEncoding.UTF8)
@@ -162,7 +162,7 @@ class GitHttpClient(
visited.add(start)
}
while (frontier.isNotEmpty() && result.size < depth) {
val commit = frontier.poll()
val commit = frontier.poll()!!
result.add(commit)
for (parent in commit.parents) {
if (parent !in visited) {
@@ -30,19 +30,19 @@ import java.security.MessageDigest
* (lock acquire + release) for ~2µs of actual hashing. ThreadLocal eliminates all locking
* since each thread gets its own MessageDigest instance. digest() implicitly resets state.
*/
val threadLocalDigest =
val threadLocalDigest: ThreadLocal<MessageDigest> =
ThreadLocal.withInitial {
MessageDigest.getInstance("SHA-256")
}
actual fun sha256(data: ByteArray): ByteArray = threadLocalDigest.get().digest(data)
actual fun sha256(data: ByteArray): ByteArray = threadLocalDigest.get()!!.digest(data)
actual fun sha256Into(
out: ByteArray,
data: ByteArray,
len: Int,
): ByteArray {
val md = threadLocalDigest.get()
val md = threadLocalDigest.get()!!
md.update(data, 0, len)
md.digest(out, 0, 32)
return out
@@ -62,7 +62,7 @@ fun sha256StreamWithCount(
bufferSize: Int = 8192,
): Pair<ByteArray, Long> {
val countingStream = CountingInputStream(inputStream)
val digest = threadLocalDigest.get()
val digest = threadLocalDigest.get()!!
try {
val buffer = ByteArray(bufferSize)
var bytesRead: Int
@@ -99,7 +99,7 @@ object CorpusDownloader {
}
}
if (checkpoint.exists()) {
runCatching { mapper.readTree(checkpoint.readText()) }.getOrNull()?.fields()?.forEach { (url, until) ->
runCatching { mapper.readTree(checkpoint.readText()) }.getOrNull()?.properties()?.forEach { (url, until) ->
cursors[url] = until.asLong()
}
}
@@ -228,9 +228,9 @@ object CorpusDownloader {
added += fresh
val oldest = page.minOf { it.createdAt }
until =
if (fresh == 0 && until != null && oldest >= until!!) {
if (fresh == 0 && until != null && oldest >= until) {
// >PAGE_LIMIT events in this second and we have them all.
until!! - 1
until - 1
} else {
oldest
}