fix(android) detekt: shrink AdminUsersScreen, real regenerate fix, suppress TooManyFunctions
The previous push tried to fix detekt but missed two things:
* regenerate() in PlaylistDetailViewModel had its 3 returns "fixed"
in name only — the if(!refreshable)return was still there. Now
folded into the variant Elvis chain with takeIf{refreshable}.
* The helper-composable extractions I just shipped pushed three
screens over detekt's 11-function-per-file cap. Compose screens
naturally produce many small private composables; per the
established pattern, suppress TooManyFunctions at the file level
with a one-line rationale rather than fight the cap.
* AdminUsersScreen main body was 94 lines (cap 60) because I
rebuilt the Scaffold inline with the new Invites section. Extracted
AdminUsersScaffold helper so the main function only owns state
hoisting and dialog dispatch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
@file:Suppress("TooManyFunctions") // Compose screen + private helper composables and dialogs
|
||||||
|
|
||||||
package com.fabledsword.minstrel.admin.ui
|
package com.fabledsword.minstrel.admin.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -70,64 +72,21 @@ fun AdminUsersScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
AdminUsersScaffold(
|
||||||
modifier = Modifier.fillMaxSize(),
|
navController = navController,
|
||||||
topBar = {
|
usersState = state,
|
||||||
TopAppBar(
|
invitesState = invitesState,
|
||||||
title = { Text("Admin · Users") },
|
onRefresh = {
|
||||||
navigationIcon = {
|
viewModel.refresh().join()
|
||||||
IconButton(onClick = { navController.popBackStack() }) {
|
invitesViewModel.refresh()
|
||||||
Icon(Lucide.ArrowLeft, contentDescription = "Back")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions = {
|
|
||||||
MainAppBarActions(
|
|
||||||
navController = navController,
|
|
||||||
currentRouteName = AdminUsers::class.qualifiedName,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
) { inner ->
|
onSetAdmin = viewModel::setAdmin,
|
||||||
PullToRefreshScaffold(
|
onSetAutoApprove = viewModel::setAutoApprove,
|
||||||
onRefresh = {
|
onAskResetPassword = { resetPasswordFor = it },
|
||||||
viewModel.refresh().join()
|
onAskDelete = { deleteCandidate = it },
|
||||||
invitesViewModel.refresh()
|
onAskGenerateInvite = { showGenerateInvite = true },
|
||||||
},
|
onRevokeInvite = invitesViewModel::revoke,
|
||||||
modifier = Modifier.fillMaxSize().padding(inner),
|
)
|
||||||
) {
|
|
||||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
|
||||||
item { SectionHeader("Users") }
|
|
||||||
usersSection(
|
|
||||||
state = state,
|
|
||||||
onSetAdmin = viewModel::setAdmin,
|
|
||||||
onSetAutoApprove = viewModel::setAutoApprove,
|
|
||||||
onAskResetPassword = { resetPasswordFor = it },
|
|
||||||
onAskDelete = { deleteCandidate = it },
|
|
||||||
)
|
|
||||||
item { HorizontalDivider() }
|
|
||||||
item {
|
|
||||||
SectionHeader(
|
|
||||||
label = "Invites",
|
|
||||||
trailing = {
|
|
||||||
TextButton(onClick = { showGenerateInvite = true }) {
|
|
||||||
Icon(
|
|
||||||
Lucide.Plus,
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.size(16.dp),
|
|
||||||
)
|
|
||||||
Text("Generate")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
invitesSection(
|
|
||||||
state = invitesState,
|
|
||||||
onRevoke = invitesViewModel::revoke,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingDialogs(
|
PendingDialogs(
|
||||||
resetPasswordFor = resetPasswordFor,
|
resetPasswordFor = resetPasswordFor,
|
||||||
@@ -155,6 +114,74 @@ fun AdminUsersScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun AdminUsersScaffold(
|
||||||
|
navController: NavHostController,
|
||||||
|
usersState: AdminUsersUiState,
|
||||||
|
invitesState: AdminInvitesUiState,
|
||||||
|
onRefresh: suspend () -> Unit,
|
||||||
|
onSetAdmin: (String, Boolean) -> Unit,
|
||||||
|
onSetAutoApprove: (String, Boolean) -> Unit,
|
||||||
|
onAskResetPassword: (AdminUserRef) -> Unit,
|
||||||
|
onAskDelete: (AdminUserRef) -> Unit,
|
||||||
|
onAskGenerateInvite: () -> Unit,
|
||||||
|
onRevokeInvite: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Admin · Users") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = { navController.popBackStack() }) {
|
||||||
|
Icon(Lucide.ArrowLeft, contentDescription = "Back")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
MainAppBarActions(
|
||||||
|
navController = navController,
|
||||||
|
currentRouteName = AdminUsers::class.qualifiedName,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { inner ->
|
||||||
|
PullToRefreshScaffold(
|
||||||
|
onRefresh = onRefresh,
|
||||||
|
modifier = Modifier.fillMaxSize().padding(inner),
|
||||||
|
) {
|
||||||
|
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||||
|
item { SectionHeader("Users") }
|
||||||
|
usersSection(
|
||||||
|
state = usersState,
|
||||||
|
onSetAdmin = onSetAdmin,
|
||||||
|
onSetAutoApprove = onSetAutoApprove,
|
||||||
|
onAskResetPassword = onAskResetPassword,
|
||||||
|
onAskDelete = onAskDelete,
|
||||||
|
)
|
||||||
|
item { HorizontalDivider() }
|
||||||
|
item {
|
||||||
|
SectionHeader(
|
||||||
|
label = "Invites",
|
||||||
|
trailing = {
|
||||||
|
TextButton(onClick = onAskGenerateInvite) {
|
||||||
|
Icon(
|
||||||
|
Lucide.Plus,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
)
|
||||||
|
Text("Generate")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
invitesSection(state = invitesState, onRevoke = onRevokeInvite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SectionHeader(label: String, trailing: (@Composable () -> Unit)? = null) {
|
private fun SectionHeader(label: String, trailing: (@Composable () -> Unit)? = null) {
|
||||||
Row(
|
Row(
|
||||||
|
|||||||
+4
-2
@@ -1,3 +1,5 @@
|
|||||||
|
@file:Suppress("TooManyFunctions") // Compose screen + private helper composables
|
||||||
|
|
||||||
package com.fabledsword.minstrel.playlists.ui
|
package com.fabledsword.minstrel.playlists.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -197,8 +199,8 @@ class PlaylistDetailViewModel @Inject constructor(
|
|||||||
fun regenerate() {
|
fun regenerate() {
|
||||||
val playlist = (internal.value as? PlaylistDetailUiState.Success)
|
val playlist = (internal.value as? PlaylistDetailUiState.Success)
|
||||||
?.detail?.playlist ?: return
|
?.detail?.playlist ?: return
|
||||||
val variant = playlist.systemVariant ?: return
|
val variant = playlist.systemVariant
|
||||||
if (!playlist.refreshable) return
|
?.takeIf { playlist.refreshable } ?: return
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
runCatching { repository.refreshSystemPlaylist(variant) }
|
runCatching { repository.refreshSystemPlaylist(variant) }
|
||||||
.onSuccess { newId ->
|
.onSuccess { newId ->
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@file:Suppress("TooManyFunctions") // Compose screen + private helper composables
|
||||||
|
|
||||||
package com.fabledsword.minstrel.requests.ui
|
package com.fabledsword.minstrel.requests.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
|||||||
Reference in New Issue
Block a user