fix(android): detekt — package naming, file rename, length caps
Twelve detekt findings from CI: * PackageNaming — `shared/widgets/track_actions/` → `trackactions/` (underscore violates [a-z]+(\.[a-z][A-Za-z0-9]*)*); 5 file moves + import updates across 7 caller files. * MatchingDeclarationName — `RadioWire.kt` → `RadioResponseWire.kt` to match its single top-level declaration. * TooManyFunctions on PlayerController (14/11) — @Suppress at class with rationale: transport + queue + radio + lifecycle are one cohesive controller; fragmenting would scatter related state. * TooManyFunctions in SearchScreen.kt (file 12/11) — @file:Suppress with rationale: legitimate per-screen section/row helpers. * LongMethod NowPlayingScreen (71/60) — extracted BottomActionsRow. * LongMethod TrackActionsSheet (77/60) — extracted TrackActionMenuItems + TrackActionSubSheets. * LongMethod HideTrackSheet (61/60) — extracted HideSheetButtons. No behavior change; all suppressions carry rationale comments. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@ import com.fabledsword.minstrel.models.TrackRef
|
||||
import com.fabledsword.minstrel.player.PlayerController
|
||||
import com.fabledsword.minstrel.shared.widgets.EmptyState
|
||||
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -56,8 +56,8 @@ import com.fabledsword.minstrel.nav.AlbumDetail
|
||||
import com.fabledsword.minstrel.nav.ArtistDetail
|
||||
import com.fabledsword.minstrel.shared.widgets.EmptyState
|
||||
import com.fabledsword.minstrel.shared.widgets.LikeButton
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.theme.FabledSwordFlatTokens
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
@@ -44,7 +44,7 @@ import com.fabledsword.minstrel.nav.Library
|
||||
import com.fabledsword.minstrel.shared.widgets.EmptyState
|
||||
import com.fabledsword.minstrel.shared.widgets.ErrorRetry
|
||||
import com.fabledsword.minstrel.shared.widgets.MainAppBarActions
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsViewModel
|
||||
|
||||
/**
|
||||
* Library tab. Five-tab TabBar (Artists / Albums / History / Liked /
|
||||
|
||||
@@ -41,7 +41,7 @@ import com.fabledsword.minstrel.player.PlayerController
|
||||
import com.fabledsword.minstrel.shared.widgets.EmptyState
|
||||
import com.fabledsword.minstrel.shared.widgets.HorizontalScrollRow
|
||||
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -38,6 +38,13 @@ import kotlin.coroutines.resumeWithException
|
||||
* the StateFlow projection means each ViewModel doesn't have to attach
|
||||
* its own Player.Listener.
|
||||
*/
|
||||
// PlayerController is the UI-side facade over the full Media3 surface
|
||||
// (transport + queue + radio + lifecycle). All the public methods are
|
||||
// legitimately part of one cohesive controller — splitting into
|
||||
// "TransportController", "QueueController", etc. would scatter related
|
||||
// state for no gain. Suppress the per-class function-count cap rather
|
||||
// than fragment.
|
||||
@Suppress("TooManyFunctions")
|
||||
@Singleton
|
||||
class PlayerController @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
|
||||
@@ -49,8 +49,8 @@ import com.fabledsword.minstrel.nav.AlbumDetail
|
||||
import com.fabledsword.minstrel.nav.ArtistDetail
|
||||
import com.fabledsword.minstrel.nav.Queue
|
||||
import com.fabledsword.minstrel.shared.widgets.EmptyState
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.theme.FabledSwordFlatTokens
|
||||
import com.fabledsword.minstrel.theme.LocalActionColors
|
||||
|
||||
@@ -121,28 +121,36 @@ fun NowPlayingScreen(
|
||||
onNext = viewModel::skipToNext,
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
ViewQueueButton(onClick = { navController.navigate(Queue) })
|
||||
TrackActionsButton(
|
||||
track = track,
|
||||
hideQueueActions = true,
|
||||
onNavigateToAlbum = { id ->
|
||||
navController.popBackStack()
|
||||
navController.navigate(AlbumDetail(id))
|
||||
},
|
||||
onNavigateToArtist = { id ->
|
||||
navController.popBackStack()
|
||||
navController.navigate(ArtistDetail(id))
|
||||
},
|
||||
)
|
||||
}
|
||||
BottomActionsRow(navController = navController, track = track)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomActionsRow(
|
||||
navController: NavHostController,
|
||||
track: com.fabledsword.minstrel.models.TrackRef,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
ViewQueueButton(onClick = { navController.navigate(Queue) })
|
||||
TrackActionsButton(
|
||||
track = track,
|
||||
hideQueueActions = true,
|
||||
onNavigateToAlbum = { id ->
|
||||
navController.popBackStack()
|
||||
navController.navigate(AlbumDetail(id))
|
||||
},
|
||||
onNavigateToArtist = { id ->
|
||||
navController.popBackStack()
|
||||
navController.navigate(ArtistDetail(id))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ViewQueueButton(onClick: () -> Unit) {
|
||||
IconButton(onClick = onClick) {
|
||||
|
||||
+2
-2
@@ -67,8 +67,8 @@ import com.fabledsword.minstrel.playlists.data.PlaylistDetailRef
|
||||
import com.fabledsword.minstrel.playlists.data.PlaylistsRepository
|
||||
import com.fabledsword.minstrel.shared.widgets.LikeButton
|
||||
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.theme.FabledSwordFlatTokens
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
@file:Suppress("TooManyFunctions")
|
||||
// SearchScreen legitimately owns the screen-shell composable + a handful
|
||||
// of small section/row helpers (ResultsPane, ResultsList, three section
|
||||
// builders, two row variants, hint, loader). Splitting into a widgets/
|
||||
// subdirectory for a single screen would be over-engineering.
|
||||
|
||||
package com.fabledsword.minstrel.search.ui
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -51,8 +57,8 @@ import com.fabledsword.minstrel.models.TrackRef
|
||||
import com.fabledsword.minstrel.nav.AlbumDetail
|
||||
import com.fabledsword.minstrel.nav.ArtistDetail
|
||||
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.fabledsword.minstrel.shared.widgets.track_actions
|
||||
package com.fabledsword.minstrel.shared.widgets.trackactions
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.fabledsword.minstrel.shared.widgets.track_actions
|
||||
package com.fabledsword.minstrel.shared.widgets.trackactions
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
+17
-11
@@ -1,4 +1,4 @@
|
||||
package com.fabledsword.minstrel.shared.widgets.track_actions
|
||||
package com.fabledsword.minstrel.shared.widgets.trackactions
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -93,17 +93,23 @@ fun HideTrackSheet(
|
||||
maxLines = 2,
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
) {
|
||||
TextButton(onClick = onDismiss) { Text("Cancel") }
|
||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||
Button(onClick = { onSubmit(reason, notes.trim()) }) {
|
||||
Text("Hide")
|
||||
}
|
||||
}
|
||||
HideSheetButtons(
|
||||
onCancel = onDismiss,
|
||||
onSubmit = { onSubmit(reason, notes.trim()) },
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HideSheetButtons(onCancel: () -> Unit, onSubmit: () -> Unit) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
) {
|
||||
TextButton(onClick = onCancel) { Text("Cancel") }
|
||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||
Button(onClick = onSubmit) { Text("Hide") }
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.fabledsword.minstrel.shared.widgets.track_actions
|
||||
package com.fabledsword.minstrel.shared.widgets.trackactions
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
+87
-48
@@ -1,4 +1,4 @@
|
||||
package com.fabledsword.minstrel.shared.widgets.track_actions
|
||||
package com.fabledsword.minstrel.shared.widgets.trackactions
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -63,7 +63,6 @@ fun TrackActionsSheet(
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
val isLiked by viewModel.isLikedFlow(track.id).collectAsStateWithLifecycle(initialValue = false)
|
||||
val isHidden by viewModel.isHiddenFlow(track.id).collectAsStateWithLifecycle(initialValue = false)
|
||||
|
||||
var showAddToPlaylist by remember { mutableStateOf(false) }
|
||||
var showHideSheet by remember { mutableStateOf(false) }
|
||||
|
||||
@@ -71,71 +70,111 @@ fun TrackActionsSheet(
|
||||
onDismissRequest = onDismiss,
|
||||
sheetState = sheetState,
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp)) {
|
||||
if (!hideQueueActions) {
|
||||
MenuItem(Lucide.ListVideo, "Play next") {
|
||||
viewModel.playNext(track)
|
||||
onDismiss()
|
||||
}
|
||||
MenuItem(Lucide.ListMusic, "Add to queue") {
|
||||
viewModel.enqueue(track)
|
||||
onDismiss()
|
||||
}
|
||||
HorizontalDivider()
|
||||
TrackActionMenuItems(
|
||||
track = track,
|
||||
hideQueueActions = hideQueueActions,
|
||||
isLiked = isLiked,
|
||||
isHidden = isHidden,
|
||||
viewModel = viewModel,
|
||||
onDismiss = onDismiss,
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
onShowAddToPlaylist = { showAddToPlaylist = true },
|
||||
onShowHideSheet = { showHideSheet = true },
|
||||
)
|
||||
}
|
||||
TrackActionSubSheets(
|
||||
track = track,
|
||||
showAddToPlaylist = showAddToPlaylist,
|
||||
showHideSheet = showHideSheet,
|
||||
viewModel = viewModel,
|
||||
onDismissParent = onDismiss,
|
||||
onCloseAddToPlaylist = { showAddToPlaylist = false },
|
||||
onCloseHideSheet = { showHideSheet = false },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrackActionMenuItems(
|
||||
track: TrackRef,
|
||||
hideQueueActions: Boolean,
|
||||
isLiked: Boolean,
|
||||
isHidden: Boolean,
|
||||
viewModel: TrackActionsViewModel,
|
||||
onDismiss: () -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
onShowAddToPlaylist: () -> Unit,
|
||||
onShowHideSheet: () -> Unit,
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp)) {
|
||||
if (!hideQueueActions) {
|
||||
MenuItem(Lucide.ListVideo, "Play next") {
|
||||
viewModel.playNext(track); onDismiss()
|
||||
}
|
||||
MenuItem(Lucide.Heart, if (isLiked) "Unlike" else "Like") {
|
||||
viewModel.toggleLike(track.id, isLiked)
|
||||
onDismiss()
|
||||
}
|
||||
MenuItem(Lucide.ListPlus, "Add to playlist…") {
|
||||
showAddToPlaylist = true
|
||||
}
|
||||
MenuItem(Lucide.Radio, "Start radio") {
|
||||
viewModel.startRadio(track.id)
|
||||
onDismiss()
|
||||
MenuItem(Lucide.ListMusic, "Add to queue") {
|
||||
viewModel.enqueue(track); onDismiss()
|
||||
}
|
||||
HorizontalDivider()
|
||||
MenuItem(Lucide.Disc3, "Go to album") {
|
||||
onDismiss()
|
||||
if (track.albumId.isNotEmpty()) onNavigateToAlbum(track.albumId)
|
||||
}
|
||||
MenuItem(Lucide.User, "Go to artist") {
|
||||
onDismiss()
|
||||
if (track.artistId.isNotEmpty()) onNavigateToArtist(track.artistId)
|
||||
}
|
||||
HorizontalDivider()
|
||||
MenuItem(
|
||||
icon = if (isHidden) Lucide.Eye else Lucide.EyeOff,
|
||||
label = if (isHidden) "Unhide" else "Hide",
|
||||
) {
|
||||
if (isHidden) {
|
||||
viewModel.unflag(track.id)
|
||||
onDismiss()
|
||||
} else {
|
||||
showHideSheet = true
|
||||
}
|
||||
}
|
||||
MenuItem(Lucide.Heart, if (isLiked) "Unlike" else "Like") {
|
||||
viewModel.toggleLike(track.id, isLiked); onDismiss()
|
||||
}
|
||||
MenuItem(Lucide.ListPlus, "Add to playlist…", onShowAddToPlaylist)
|
||||
MenuItem(Lucide.Radio, "Start radio") {
|
||||
viewModel.startRadio(track.id); onDismiss()
|
||||
}
|
||||
HorizontalDivider()
|
||||
MenuItem(Lucide.Disc3, "Go to album") {
|
||||
onDismiss()
|
||||
if (track.albumId.isNotEmpty()) onNavigateToAlbum(track.albumId)
|
||||
}
|
||||
MenuItem(Lucide.User, "Go to artist") {
|
||||
onDismiss()
|
||||
if (track.artistId.isNotEmpty()) onNavigateToArtist(track.artistId)
|
||||
}
|
||||
HorizontalDivider()
|
||||
MenuItem(
|
||||
icon = if (isHidden) Lucide.Eye else Lucide.EyeOff,
|
||||
label = if (isHidden) "Unhide" else "Hide",
|
||||
) {
|
||||
if (isHidden) {
|
||||
viewModel.unflag(track.id); onDismiss()
|
||||
} else {
|
||||
onShowHideSheet()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrackActionSubSheets(
|
||||
track: TrackRef,
|
||||
showAddToPlaylist: Boolean,
|
||||
showHideSheet: Boolean,
|
||||
viewModel: TrackActionsViewModel,
|
||||
onDismissParent: () -> Unit,
|
||||
onCloseAddToPlaylist: () -> Unit,
|
||||
onCloseHideSheet: () -> Unit,
|
||||
) {
|
||||
if (showAddToPlaylist) {
|
||||
AddToPlaylistSheet(
|
||||
onPick = { playlistId ->
|
||||
viewModel.appendToPlaylist(playlistId, track.id)
|
||||
showAddToPlaylist = false
|
||||
onDismiss()
|
||||
onCloseAddToPlaylist()
|
||||
onDismissParent()
|
||||
},
|
||||
onDismiss = { showAddToPlaylist = false },
|
||||
onDismiss = onCloseAddToPlaylist,
|
||||
)
|
||||
}
|
||||
if (showHideSheet) {
|
||||
HideTrackSheet(
|
||||
onSubmit = { reason, notes ->
|
||||
viewModel.flag(track, reason, notes)
|
||||
showHideSheet = false
|
||||
onDismiss()
|
||||
onCloseHideSheet()
|
||||
onDismissParent()
|
||||
},
|
||||
onDismiss = { showHideSheet = false },
|
||||
onDismiss = onCloseHideSheet,
|
||||
)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.fabledsword.minstrel.shared.widgets.track_actions
|
||||
package com.fabledsword.minstrel.shared.widgets.trackactions
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
Reference in New Issue
Block a user