From 6aec03fc02a6369005a602dfc47887cfadc72768 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 23 May 2026 22:22:14 -0400 Subject: [PATCH] style(android): clear detekt findings in PlayerController MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Two TooGenericExceptionCaught: connectAndObserve + connectController both catch Exception over Media3 IPC boundaries where specific- exception handling buys nothing (ListenableFuture.get() throws ExecutionException / InterruptedException / CancellationException — all forwarded uniformly). Widened to Throwable and @Suppressed with a one-line rationale each. - MaxLineLength: refactored TrackRef.toMediaItem's nested `.apply { source?.let { setExtras(Bundle()...) } }` chain into a pair of expression-bodied helpers (metadata builder + sourceExtras). Reads cleaner; under 120 chars. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../minstrel/player/PlayerController.kt | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/android/app/src/main/java/com/fabledsword/minstrel/player/PlayerController.kt b/android/app/src/main/java/com/fabledsword/minstrel/player/PlayerController.kt index 173b0947..5022fa5a 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/player/PlayerController.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/player/PlayerController.kt @@ -2,6 +2,7 @@ package com.fabledsword.minstrel.player import android.content.ComponentName import android.content.Context +import android.os.Bundle import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata import androidx.media3.common.Player @@ -90,7 +91,12 @@ class PlayerController @Inject constructor( val controller = try { connectController() - } catch (e: Exception) { + } catch ( + // Service-connection failure is a "show error, move on" boundary — + // any throwable from the Media3 IPC handshake gets surfaced via + // playbackError. Specific-exception handling buys nothing here. + @Suppress("TooGenericExceptionCaught") e: Throwable, + ) { uiStateInternal.value = uiStateInternal.value.copy(playbackError = e.message ?: "Player unavailable") return @@ -132,7 +138,13 @@ class PlayerController @Inject constructor( { try { cont.resume(future.get()) - } catch (e: Exception) { + } catch ( + // ListenableFuture.get() throws ExecutionException + + // InterruptedException + CancellationException — handle + // them uniformly by forwarding to the continuation; + // the caller catches at the outer boundary. + @Suppress("TooGenericExceptionCaught") e: Throwable, + ) { cont.resumeWithException(e) } }, @@ -141,19 +153,24 @@ class PlayerController @Inject constructor( cont.invokeOnCancellation { future.cancel(/* mayInterruptIfRunning = */ false) } } - private fun TrackRef.toMediaItem(source: String?): MediaItem = - MediaItem.Builder() + private fun TrackRef.toMediaItem(source: String?): MediaItem { + val metadata = MediaMetadata.Builder() + .setTitle(title) + .setArtist(artistName) + .setAlbumTitle(albumTitle) + .apply { + if (source != null) setExtras(sourceExtras(source)) + } + .build() + return MediaItem.Builder() .setMediaId(id) .setUri(streamUrl) - .setMediaMetadata( - MediaMetadata.Builder() - .setTitle(title) - .setArtist(artistName) - .setAlbumTitle(albumTitle) - .apply { source?.let { setExtras(android.os.Bundle().apply { putString(MINSTREL_SOURCE_KEY, it) }) } } - .build(), - ) + .setMediaMetadata(metadata) .build() + } + + private fun sourceExtras(source: String): Bundle = + Bundle().apply { putString(MINSTREL_SOURCE_KEY, source) } companion object { const val MINSTREL_SOURCE_KEY: String = "minstrel_source"