Merge pull request #2639 from davotoula/fix-sonar-empty-functions

Fix sonar empty functions and string literals
This commit is contained in:
Vitor Pamplona
2026-04-29 07:53:22 -04:00
committed by GitHub
11 changed files with 117 additions and 51 deletions
@@ -93,5 +93,7 @@ class MockWritingAssistant : WritingAssistant {
.replace("wont ", "won't ") .replace("wont ", "won't ")
.replace("i ", "I ") .replace("i ", "I ")
override fun close() {} override fun close() {
// no-op: mock holds no native handles or background workers to release.
}
} }
@@ -113,7 +113,9 @@ class CallAudioManager(
override fun onAccuracyChanged( override fun onAccuracyChanged(
sensor: Sensor?, sensor: Sensor?,
accuracy: Int, accuracy: Int,
) {} ) {
// no-op: proximity is a binary near/far signal; accuracy changes don't affect routing.
}
} }
fun startRinging() { fun startRinging() {
@@ -74,7 +74,9 @@ class WebRtcCallSession(
candidate?.let { this@WebRtcCallSession.onIceCandidate(it) } candidate?.let { this@WebRtcCallSession.onIceCandidate(it) }
} }
override fun onIceCandidatesRemoved(candidates: Array<out IceCandidate>?) {} override fun onIceCandidatesRemoved(candidates: Array<out IceCandidate>?) {
// no-op: removed candidates are diagnostic only; ICE state transitions handle reconnects.
}
override fun onSignalingChange(state: PeerConnection.SignalingState?) { override fun onSignalingChange(state: PeerConnection.SignalingState?) {
Log.d(TAG) { "Signaling state changed: $state" } Log.d(TAG) { "Signaling state changed: $state" }
@@ -137,9 +139,13 @@ class WebRtcCallSession(
stream?.videoTracks?.firstOrNull()?.let { onRemoteVideoTrack(it) } stream?.videoTracks?.firstOrNull()?.let { onRemoteVideoTrack(it) }
} }
override fun onRemoveStream(stream: MediaStream?) {} override fun onRemoveStream(stream: MediaStream?) {
// no-op: Plan-B legacy callback. UNIFIED_PLAN delivers track-level events via onAddTrack instead.
}
override fun onDataChannel(channel: DataChannel?) {} override fun onDataChannel(channel: DataChannel?) {
// no-op: this session uses audio/video tracks only; data channels are not negotiated.
}
override fun onRenegotiationNeeded() { override fun onRenegotiationNeeded() {
Log.d(TAG) { "Renegotiation needed" } Log.d(TAG) { "Renegotiation needed" }
@@ -209,9 +215,13 @@ class WebRtcCallSession(
error?.let { onError("Create offer failed: $it") } error?.let { onError("Create offer failed: $it") }
} }
override fun onSetSuccess() {} override fun onSetSuccess() {
// no-op: createOffer fires only onCreate*; setLocalDescription uses loggingSdpObserver.
}
override fun onSetFailure(error: String?) {} override fun onSetFailure(error: String?) {
// no-op: createOffer fires only onCreate*; setLocalDescription uses loggingSdpObserver.
}
}, },
constraints, constraints,
) )
@@ -239,9 +249,13 @@ class WebRtcCallSession(
error?.let { onError("Create answer failed: $it") } error?.let { onError("Create answer failed: $it") }
} }
override fun onSetSuccess() {} override fun onSetSuccess() {
// no-op: createAnswer fires only onCreate*; setLocalDescription uses loggingSdpObserver.
}
override fun onSetFailure(error: String?) {} override fun onSetFailure(error: String?) {
// no-op: createAnswer fires only onCreate*; setLocalDescription uses loggingSdpObserver.
}
}, },
constraints, constraints,
) )
@@ -251,9 +265,13 @@ class WebRtcCallSession(
Log.d(TAG) { "setRemoteDescription type=${sdp.type} sdpLength=${sdp.description.length}" } Log.d(TAG) { "setRemoteDescription type=${sdp.type} sdpLength=${sdp.description.length}" }
peerConnection?.setRemoteDescription( peerConnection?.setRemoteDescription(
object : SdpObserver { object : SdpObserver {
override fun onCreateSuccess(sdp: SessionDescription?) {} override fun onCreateSuccess(sdp: SessionDescription?) {
// no-op: setRemoteDescription fires only onSet*.
}
override fun onCreateFailure(error: String?) {} override fun onCreateFailure(error: String?) {
// no-op: setRemoteDescription fires only onSet*.
}
override fun onSetSuccess() { override fun onSetSuccess() {
Log.d(TAG) { "setRemoteDescription SUCCESS (type=${sdp.type})" } Log.d(TAG) { "setRemoteDescription SUCCESS (type=${sdp.type})" }
@@ -301,9 +319,13 @@ class WebRtcCallSession(
onDisconnected() onDisconnected()
} }
override fun onSetSuccess() {} override fun onSetSuccess() {
// no-op: createOffer fires only onCreate*; setLocalDescription uses loggingSdpObserver.
}
override fun onSetFailure(error: String?) {} override fun onSetFailure(error: String?) {
// no-op: createOffer fires only onCreate*; setLocalDescription uses loggingSdpObserver.
}
}, },
constraints, constraints,
) )
@@ -328,9 +350,13 @@ class WebRtcCallSession(
val rollbackSdp = SessionDescription(SessionDescription.Type.ROLLBACK, "") val rollbackSdp = SessionDescription(SessionDescription.Type.ROLLBACK, "")
peerConnection?.setLocalDescription( peerConnection?.setLocalDescription(
object : SdpObserver { object : SdpObserver {
override fun onCreateSuccess(sdp: SessionDescription?) {} override fun onCreateSuccess(sdp: SessionDescription?) {
// no-op: setLocalDescription fires only onSet*.
}
override fun onCreateFailure(error: String?) {} override fun onCreateFailure(error: String?) {
// no-op: setLocalDescription fires only onSet*.
}
override fun onSetSuccess() { override fun onSetSuccess() {
Log.d(TAG) { "Rollback SUCCESS" } Log.d(TAG) { "Rollback SUCCESS" }
@@ -48,6 +48,9 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
private const val LABEL_HANG_UP = "Hang up"
private const val LABEL_CALLING = "Calling…"
// ---- Shared building blocks for previews ---- // ---- Shared building blocks for previews ----
@Composable @Composable
@@ -172,7 +175,7 @@ private fun PreviewCallControls(
shape = CircleShape, shape = CircleShape,
modifier = Modifier.size(64.dp), modifier = Modifier.size(64.dp),
) { ) {
Icon(MaterialSymbols.CallEnd, "Hang up", tint = Color.White, modifier = Modifier.size(32.dp)) Icon(MaterialSymbols.CallEnd, LABEL_HANG_UP, tint = Color.White, modifier = Modifier.size(32.dp))
} }
} }
} }
@@ -207,7 +210,7 @@ private fun PreviewCallInProgress(
shape = CircleShape, shape = CircleShape,
modifier = Modifier.size(64.dp), modifier = Modifier.size(64.dp),
) { ) {
Icon(MaterialSymbols.CallEnd, "Hang up", tint = Color.White, modifier = Modifier.size(32.dp)) Icon(MaterialSymbols.CallEnd, LABEL_HANG_UP, tint = Color.White, modifier = Modifier.size(32.dp))
} }
} }
} }
@@ -217,7 +220,7 @@ private fun PreviewCallInProgress(
@Composable @Composable
fun PreviewCallingScreen() { fun PreviewCallingScreen() {
ThemeComparisonColumn { ThemeComparisonColumn {
PreviewCallInProgress("Alice", "Calling\u2026") PreviewCallInProgress("Alice", LABEL_CALLING)
} }
} }
@@ -242,7 +245,7 @@ fun PreviewCallingGroupScreen() {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Text("Alice, Bob +1", fontWeight = FontWeight.Bold, fontSize = 20.sp) Text("Alice, Bob +1", fontWeight = FontWeight.Bold, fontSize = 20.sp)
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text("Calling\u2026", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 16.sp) Text(LABEL_CALLING, color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 16.sp)
Spacer(modifier = Modifier.height(48.dp)) Spacer(modifier = Modifier.height(48.dp))
FloatingActionButton( FloatingActionButton(
onClick = {}, onClick = {},
@@ -250,7 +253,7 @@ fun PreviewCallingGroupScreen() {
shape = CircleShape, shape = CircleShape,
modifier = Modifier.size(64.dp), modifier = Modifier.size(64.dp),
) { ) {
Icon(MaterialSymbols.CallEnd, "Hang up", tint = Color.White, modifier = Modifier.size(32.dp)) Icon(MaterialSymbols.CallEnd, LABEL_HANG_UP, tint = Color.White, modifier = Modifier.size(32.dp))
} }
} }
} }
@@ -580,7 +583,7 @@ fun PreviewPipCallUI() {
) { ) {
Icon(MaterialSymbols.Person, contentDescription = null, modifier = Modifier.size(48.dp)) Icon(MaterialSymbols.Person, contentDescription = null, modifier = Modifier.size(48.dp))
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Text("Calling\u2026", fontSize = 10.sp, color = MaterialTheme.colorScheme.onSurfaceVariant) Text(LABEL_CALLING, fontSize = 10.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
} }
} }
} }
@@ -39,6 +39,8 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlin.reflect.KClass import kotlin.reflect.KClass
private const val NOSTR_URI_PREFIX = "nostr:"
/** /**
* INav for screens that live inside a free-standing Activity (no Compose * INav for screens that live inside a free-standing Activity (no Compose
* NavHost in scope) and need to dispatch navigation requests back to * NavHost in scope) and need to dispatch navigation requests back to
@@ -127,31 +129,31 @@ class BouncingIntentNav(
private fun routeToBouncingUri(route: Route): String? = private fun routeToBouncingUri(route: Route): String? =
when (route) { when (route) {
is Route.Profile -> { is Route.Profile -> {
"nostr:" + NPub.create(route.id) NOSTR_URI_PREFIX + NPub.create(route.id)
} }
is Route.Note -> { is Route.Note -> {
"nostr:" + NEvent.create(route.id, null, null, null) NOSTR_URI_PREFIX + NEvent.create(route.id, null, null, null)
} }
is Route.EventRedirect -> { is Route.EventRedirect -> {
"nostr:" + NEvent.create(route.id, null, null, null) NOSTR_URI_PREFIX + NEvent.create(route.id, null, null, null)
} }
is Route.Hashtag -> { is Route.Hashtag -> {
"nostr:hashtag?id=" + route.hashtag NOSTR_URI_PREFIX + "hashtag?id=" + route.hashtag
} }
is Route.LiveActivityChannel -> { is Route.LiveActivityChannel -> {
"nostr:" + NAddress.create(route.kind, route.pubKeyHex, route.dTag, null) NOSTR_URI_PREFIX + NAddress.create(route.kind, route.pubKeyHex, route.dTag, null)
} }
is Route.Community -> { is Route.Community -> {
"nostr:" + NAddress.create(route.kind, route.pubKeyHex, route.dTag, null) NOSTR_URI_PREFIX + NAddress.create(route.kind, route.pubKeyHex, route.dTag, null)
} }
is Route.PublicChatChannel -> { is Route.PublicChatChannel -> {
"nostr:" + NEvent.create(route.id, null, ChannelCreateEvent.KIND, null) NOSTR_URI_PREFIX + NEvent.create(route.id, null, ChannelCreateEvent.KIND, null)
} }
else -> { else -> {
@@ -39,21 +39,33 @@ class EmptyNav : INav {
override fun openDrawer() = runBlocking { drawerState.open() } override fun openDrawer() = runBlocking { drawerState.open() }
// All navigation methods are intentionally no-op; this is a stub for previews and tests // All navigation methods are intentionally no-op; this is a stub for previews and tests
override fun nav(route: Route) {} override fun nav(route: Route) {
// no-op: EmptyNav is a preview/test stub with no navigation host.
}
override fun nav(computeRoute: suspend () -> Route?) {} override fun nav(computeRoute: suspend () -> Route?) {
// no-op: EmptyNav is a preview/test stub with no navigation host.
}
override fun newStack(route: Route) {} override fun newStack(route: Route) {
// no-op: EmptyNav is a preview/test stub with no back stack to reset.
}
override fun navBottomBar(route: Route) {} override fun navBottomBar(route: Route) {
// no-op: EmptyNav is a preview/test stub with no bottom-bar host.
}
@Composable @Composable
override fun canPop(): Boolean = false override fun canPop(): Boolean = false
override fun popBack() {} override fun popBack() {
// no-op: EmptyNav is a preview/test stub with no back stack to pop.
}
override fun <T : Route> popUpTo( override fun <T : Route> popUpTo(
route: Route, route: Route,
klass: KClass<T>, klass: KClass<T>,
) {} ) {
// no-op: EmptyNav is a preview/test stub with no back stack.
}
} }
@@ -179,12 +179,16 @@ interface EventHandler<T : IEvent> {
event: T, event: T,
eventNote: Note, eventNote: Note,
publicNote: Note, publicNote: Note,
) {} ) {
// no-op default: handlers that only care about deletes (or only adds) skip overriding this.
}
suspend fun delete( suspend fun delete(
event: T, event: T,
eventNote: Note, eventNote: Note,
) {} ) {
// no-op default: handlers that only care about adds (or only deletes) skip overriding this.
}
} }
class ChatHandler( class ChatHandler(
@@ -44,11 +44,16 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
private const val SAMPLE_PUBKEY_FRAGMENT =
"\"pubkey\":\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\","
private const val SAMPLE_KIND_20_FRAGMENT = "\"kind\":20,"
private const val SAMPLE_PICTURE_EVENT_JSON = private const val SAMPLE_PICTURE_EVENT_JSON =
"{\"id\":\"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\"," + "{\"id\":\"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\"," +
"\"pubkey\":\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\"," + SAMPLE_PUBKEY_FRAGMENT +
"\"created_at\":1708695717," + "\"created_at\":1708695717," +
"\"kind\":20," + SAMPLE_KIND_20_FRAGMENT +
"\"tags\":[[\"title\",\"Sunset at the Beach\"]," + "\"tags\":[[\"title\",\"Sunset at the Beach\"]," +
"[\"imeta\",\"url https://image.nostr.build/sample-sunset.jpg\"," + "[\"imeta\",\"url https://image.nostr.build/sample-sunset.jpg\"," +
"\"m image/jpeg\",\"dim 1200x800\",\"alt A beautiful sunset over the ocean\"," + "\"m image/jpeg\",\"dim 1200x800\",\"alt A beautiful sunset over the ocean\"," +
@@ -58,9 +63,9 @@ private const val SAMPLE_PICTURE_EVENT_JSON =
private const val SAMPLE_PICTURE_EVENT_NO_TITLE_JSON = private const val SAMPLE_PICTURE_EVENT_NO_TITLE_JSON =
"{\"id\":\"b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3\"," + "{\"id\":\"b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3\"," +
"\"pubkey\":\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\"," + SAMPLE_PUBKEY_FRAGMENT +
"\"created_at\":1708695000," + "\"created_at\":1708695000," +
"\"kind\":20," + SAMPLE_KIND_20_FRAGMENT +
"\"tags\":[[\"imeta\",\"url https://image.nostr.build/sample-mountain.jpg\"," + "\"tags\":[[\"imeta\",\"url https://image.nostr.build/sample-mountain.jpg\"," +
"\"m image/jpeg\",\"dim 1080x1080\",\"alt Mountain landscape\"]]," + "\"m image/jpeg\",\"dim 1080x1080\",\"alt Mountain landscape\"]]," +
"\"content\":\"Mountain vibes today. Fresh air and clear skies.\"," + "\"content\":\"Mountain vibes today. Fresh air and clear skies.\"," +
@@ -68,9 +73,9 @@ private const val SAMPLE_PICTURE_EVENT_NO_TITLE_JSON =
private const val SAMPLE_MULTI_IMAGE_EVENT_JSON = private const val SAMPLE_MULTI_IMAGE_EVENT_JSON =
"{\"id\":\"c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\"," + "{\"id\":\"c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\"," +
"\"pubkey\":\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\"," + SAMPLE_PUBKEY_FRAGMENT +
"\"created_at\":1708694000," + "\"created_at\":1708694000," +
"\"kind\":20," + SAMPLE_KIND_20_FRAGMENT +
"\"tags\":[[\"title\",\"Travel Photos\"]," + "\"tags\":[[\"title\",\"Travel Photos\"]," +
"[\"imeta\",\"url https://image.nostr.build/sample-travel1.jpg\"," + "[\"imeta\",\"url https://image.nostr.build/sample-travel1.jpg\"," +
"\"m image/jpeg\",\"dim 800x600\",\"alt City street\"]," + "\"m image/jpeg\",\"dim 800x600\",\"alt City street\"]," +
@@ -98,9 +98,16 @@ fun RelayUrlEditFieldPreview() {
override val results: Flow<List<BasicRelaySetupInfo>> = override val results: Flow<List<BasicRelaySetupInfo>> =
MutableStateFlow(suggestions) MutableStateFlow(suggestions)
override fun processInput(input: String) {} override fun processInput(input: String) {
// No-op: this anonymous IRelaySuggestionState is preview-only and
// serves the static suggestions flow above. Live input filtering
// would only matter in an interactive run, which a @Preview never
// reaches.
}
override fun reset() {} override fun reset() {
// No-op: see processInput above.
}
} }
} }
@@ -44,6 +44,8 @@ import java.time.format.DateTimeFormatter
* - paints the result with ANSI colour when stdout is a TTY (disabled * - paints the result with ANSI colour when stdout is a TTY (disabled
* by `NO_COLOR`, forced on by `CLICOLOR_FORCE`). * by `NO_COLOR`, forced on by `CLICOLOR_FORCE`).
*/ */
private const val EMPTY_LABEL = "(empty)"
object Output { object Output {
enum class Mode { TEXT, JSON } enum class Mode { TEXT, JSON }
@@ -137,7 +139,7 @@ object Output {
.append(coloredKey) .append(coloredKey)
.append(":") .append(":")
.append(padding) .append(padding)
out.append(' ').append(color.dim("(empty)")).append('\n') out.append(' ').append(color.dim(EMPTY_LABEL)).append('\n')
} else { } else {
out.append(prefix).append(coloredKey).append(":\n") out.append(prefix).append(coloredKey).append(":\n")
renderMapBody(out, v, "$prefix ", color) renderMapBody(out, v, "$prefix ", color)
@@ -190,7 +192,7 @@ object Output {
.append(prefix) .append(prefix)
.append(dash) .append(dash)
.append(' ') .append(' ')
.append(color.dim("(empty)")) .append(color.dim(EMPTY_LABEL))
.append('\n') .append('\n')
continue continue
} }
@@ -224,7 +226,7 @@ object Output {
.append(':') .append(':')
.append(rPad) .append(rPad)
.append(' ') .append(' ')
.append(color.dim("(empty)")) .append(color.dim(EMPTY_LABEL))
.append('\n') .append('\n')
} else { } else {
out.append("$prefix ").append(color.bold(rKey)).append(":\n") out.append("$prefix ").append(color.bold(rKey)).append(":\n")
@@ -211,6 +211,7 @@ internal object MacosKeychainBackend : SecretBackend {
internal object SecretServiceBackend : SecretBackend { internal object SecretServiceBackend : SecretBackend {
const val BACKEND_ID = "secret-service" const val BACKEND_ID = "secret-service"
private const val SERVICE_ATTR = "amy-nostr" private const val SERVICE_ATTR = "amy-nostr"
private const val SECRET_TOOL_BIN = "secret-tool"
override val name: String = "keychain:$BACKEND_ID" override val name: String = "keychain:$BACKEND_ID"
@@ -224,7 +225,7 @@ internal object SecretServiceBackend : SecretBackend {
) { ) {
return false return false
} }
return which("secret-tool") != null return which(SECRET_TOOL_BIN) != null
} }
override fun store( override fun store(
@@ -233,7 +234,7 @@ internal object SecretServiceBackend : SecretBackend {
): IdentitySecret { ): IdentitySecret {
val res = val res =
runProc( runProc(
"secret-tool", SECRET_TOOL_BIN,
"store", "store",
"--label=amy Nostr identity ${pubKeyHex.take(8)}", "--label=amy Nostr identity ${pubKeyHex.take(8)}",
"service", "service",
@@ -250,7 +251,7 @@ internal object SecretServiceBackend : SecretBackend {
override fun resolve(secret: IdentitySecret): String { override fun resolve(secret: IdentitySecret): String {
require(secret is IdentitySecret.Keychain) require(secret is IdentitySecret.Keychain)
val res = runProc("secret-tool", "lookup", "service", secret.service, "account", secret.account) val res = runProc(SECRET_TOOL_BIN, "lookup", "service", secret.service, "account", secret.account)
if (res.exit != 0 || res.stdout.isBlank()) { if (res.exit != 0 || res.stdout.isBlank()) {
throw RuntimeException("secret-tool lookup failed (exit=${res.exit}): ${res.stderr.trim()}") throw RuntimeException("secret-tool lookup failed (exit=${res.exit}): ${res.stderr.trim()}")
} }
@@ -259,7 +260,7 @@ internal object SecretServiceBackend : SecretBackend {
override fun delete(secret: IdentitySecret) { override fun delete(secret: IdentitySecret) {
require(secret is IdentitySecret.Keychain) require(secret is IdentitySecret.Keychain)
runProc("secret-tool", "clear", "service", secret.service, "account", secret.account) runProc(SECRET_TOOL_BIN, "clear", "service", secret.service, "account", secret.account)
} }
private fun which(cmd: String): File? { private fun which(cmd: String): File? {