chore(quality): resolve all detekt findings for v1.8.1 release

Changes:
- UpdateChangelogSheet.kt: Remove 3 unused imports (Intent, Uri, withStyle)
- NoteEditorScreen.kt: Extract DRAGGING_ELEVATION_DP and AUTO_SCROLL_DELAY_MS constants
- NoteEditorScreen.kt: Add @Suppress("LongParameterList") to DraggableChecklistItem
- NoteEditorViewModel.kt: Refactor loadNote() into loadExistingNote(), loadChecklistData(), initNewNote()
- NoteEditorViewModel.kt: Extract parseSortOption() utility for safe enum parsing
- NoteEditorViewModel.kt: Fix NestedBlockDepth and SwallowedException findings
- ChecklistPreviewHelper.kt: Suppress SwallowedException for intentional fallback
- NoteWidgetActions.kt: Suppress SwallowedException for intentional fallback
- NoteWidgetContent.kt: Suppress SwallowedException in ChecklistCompactView + ChecklistFullView
- SyncWorker.kt: Suppress LongMethod on doWork() (linear flow, debug logging)
- detekt.yml: Update maxIssues from 100 to 0, update version comment

All 12 detekt findings resolved. Build compiles clean, 0 lint errors.
This commit is contained in:
inventory69
2026-02-11 11:22:10 +01:00
parent 27e6b9d4ac
commit 1a6617a4ec
8 changed files with 87 additions and 68 deletions

View File

@@ -73,6 +73,7 @@ class SyncWorker(
}
}
@Suppress("LongMethod") // Linear sync flow with debug logging — splitting would hurt readability
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
if (BuildConfig.DEBUG) {
Logger.d(TAG, "═══════════════════════════════════════")

View File

@@ -66,8 +66,10 @@ import dev.dettmer.simplenotes.utils.showToast
import kotlin.math.roundToInt
private const val LAYOUT_DELAY_MS = 100L
private const val AUTO_SCROLL_DELAY_MS = 50L
private const val ITEM_CORNER_RADIUS_DP = 8
private const val DRAGGING_ITEM_Z_INDEX = 10f
private val DRAGGING_ELEVATION_DP = 8.dp
/**
* Main Composable for the Note Editor screen.
@@ -327,6 +329,7 @@ private fun TextNoteContent(
* 🆕 v1.8.1 IMPL_14: Extrahiertes Composable für ein einzelnes draggbares Checklist-Item.
* Entkoppelt von der Separator-Logik — wiederverwendbar für unchecked und checked Items.
*/
@Suppress("LongParameterList") // Compose callbacks — cannot be reduced without wrapper class
@Composable
private fun LazyItemScope.DraggableChecklistItem(
item: ChecklistItemState,
@@ -342,7 +345,7 @@ private fun LazyItemScope.DraggableChecklistItem(
) {
val isDragging = dragDropState.draggingItemIndex == visualIndex
val elevation by animateDpAsState(
targetValue = if (isDragging) 8.dp else 0.dp,
targetValue = if (isDragging) DRAGGING_ELEVATION_DP else 0.dp,
label = "elevation"
)
@@ -426,7 +429,7 @@ private fun ChecklistEditor(
// 🆕 v1.8.1 (IMPL_05): Auto-Scroll wenn ein Item durch Zeilenumbruch wächst
LaunchedEffect(scrollToItemIndex) {
scrollToItemIndex?.let { index ->
delay(50) // Warten bis Layout-Pass abgeschlossen
delay(AUTO_SCROLL_DELAY_MS) // Warten bis Layout-Pass abgeschlossen
val lastVisibleIndex = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0
if (index >= lastVisibleIndex - 1) {
listState.animateScrollToItem(

View File

@@ -91,74 +91,92 @@ class NoteEditorViewModel(
val noteTypeString = savedStateHandle.get<String>(ARG_NOTE_TYPE) ?: NoteType.TEXT.name
if (noteId != null) {
// Load existing note
existingNote = storage.loadNote(noteId)
existingNote?.let { note ->
currentNoteType = note.noteType
_uiState.update { state ->
state.copy(
title = note.title,
content = note.content,
noteType = note.noteType,
isNewNote = false,
toolbarTitle = if (note.noteType == NoteType.CHECKLIST) {
ToolbarTitle.EDIT_CHECKLIST
} else {
ToolbarTitle.EDIT_NOTE
}
)
}
if (note.noteType == NoteType.CHECKLIST) {
// 🆕 v1.8.1 (IMPL_03): Gespeicherte Sortierung laden
note.checklistSortOption?.let { sortName ->
try {
_lastChecklistSortOption.value = ChecklistSortOption.valueOf(sortName)
} catch (e: IllegalArgumentException) {
Logger.w(TAG, "Unknown sort option '$sortName', using MANUAL")
_lastChecklistSortOption.value = ChecklistSortOption.MANUAL
}
}
val items = note.checklistItems?.sortedBy { it.order }?.map {
ChecklistItemState(
id = it.id,
text = it.text,
isChecked = it.isChecked,
order = it.order
)
} ?: emptyList()
// 🆕 v1.8.0 (IMPL_017): Sortierung sicherstellen (falls alte Daten unsortiert sind)
_checklistItems.value = sortChecklistItems(items)
}
}
loadExistingNote(noteId)
} else {
// New note
currentNoteType = try {
NoteType.valueOf(noteTypeString)
} catch (e: IllegalArgumentException) {
Logger.w(TAG, "Invalid note type '$noteTypeString', defaulting to TEXT: ${e.message}")
NoteType.TEXT
}
initNewNote(noteTypeString)
}
}
private fun loadExistingNote(noteId: String) {
existingNote = storage.loadNote(noteId)
existingNote?.let { note ->
currentNoteType = note.noteType
_uiState.update { state ->
state.copy(
noteType = currentNoteType,
isNewNote = true,
toolbarTitle = if (currentNoteType == NoteType.CHECKLIST) {
ToolbarTitle.NEW_CHECKLIST
title = note.title,
content = note.content,
noteType = note.noteType,
isNewNote = false,
toolbarTitle = if (note.noteType == NoteType.CHECKLIST) {
ToolbarTitle.EDIT_CHECKLIST
} else {
ToolbarTitle.NEW_NOTE
ToolbarTitle.EDIT_NOTE
}
)
}
// Add first empty item for new checklists
if (currentNoteType == NoteType.CHECKLIST) {
_checklistItems.value = listOf(ChecklistItemState.createEmpty(0))
if (note.noteType == NoteType.CHECKLIST) {
loadChecklistData(note)
}
}
}
private fun loadChecklistData(note: Note) {
// 🆕 v1.8.1 (IMPL_03): Gespeicherte Sortierung laden
note.checklistSortOption?.let { sortName ->
_lastChecklistSortOption.value = parseSortOption(sortName)
}
val items = note.checklistItems?.sortedBy { it.order }?.map {
ChecklistItemState(
id = it.id,
text = it.text,
isChecked = it.isChecked,
order = it.order
)
} ?: emptyList()
// 🆕 v1.8.0 (IMPL_017): Sortierung sicherstellen (falls alte Daten unsortiert sind)
_checklistItems.value = sortChecklistItems(items)
}
private fun initNewNote(noteTypeString: String) {
currentNoteType = try {
NoteType.valueOf(noteTypeString)
} catch (@Suppress("SwallowedException") e: IllegalArgumentException) {
Logger.w(TAG, "Invalid note type '$noteTypeString', defaulting to TEXT")
NoteType.TEXT
}
_uiState.update { state ->
state.copy(
noteType = currentNoteType,
isNewNote = true,
toolbarTitle = if (currentNoteType == NoteType.CHECKLIST) {
ToolbarTitle.NEW_CHECKLIST
} else {
ToolbarTitle.NEW_NOTE
}
)
}
// Add first empty item for new checklists
if (currentNoteType == NoteType.CHECKLIST) {
_checklistItems.value = listOf(ChecklistItemState.createEmpty(0))
}
}
/**
* Safely parse a ChecklistSortOption from its string name.
* Falls back to MANUAL if the name is unknown (e.g., from older app versions).
*/
private fun parseSortOption(sortName: String): ChecklistSortOption {
return try {
ChecklistSortOption.valueOf(sortName)
} catch (@Suppress("SwallowedException") e: IllegalArgumentException) {
Logger.w(TAG, "Unknown sort option '$sortName', using MANUAL")
ChecklistSortOption.MANUAL
}
}
// ═══════════════════════════════════════════════════════════════════════
// Actions

View File

@@ -1,8 +1,6 @@
package dev.dettmer.simplenotes.ui.main
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -32,7 +30,6 @@ import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withLink
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import dev.dettmer.simplenotes.BuildConfig
import dev.dettmer.simplenotes.R

View File

@@ -21,7 +21,7 @@ fun sortChecklistItemsForPreview(
): List<ChecklistItem> {
val sortOption = try {
sortOptionName?.let { ChecklistSortOption.valueOf(it) }
} catch (e: IllegalArgumentException) {
} catch (@Suppress("SwallowedException") e: IllegalArgumentException) {
null
} ?: ChecklistSortOption.MANUAL

View File

@@ -56,7 +56,7 @@ class ToggleChecklistItemAction : ActionCallback {
// Konsistent mit NoteEditorViewModel.updateChecklistItemChecked
val sortOption = try {
note.checklistSortOption?.let { ChecklistSortOption.valueOf(it) }
} catch (e: IllegalArgumentException) { null }
} catch (@Suppress("SwallowedException") e: IllegalArgumentException) { null }
?: ChecklistSortOption.MANUAL
val sortedItems = if (sortOption == ChecklistSortOption.MANUAL ||

View File

@@ -439,7 +439,7 @@ private fun ChecklistCompactView(
val checkedCount = items.count { it.isChecked }
val sortOption = try {
note.checklistSortOption?.let { ChecklistSortOption.valueOf(it) }
} catch (e: IllegalArgumentException) { null }
} catch (@Suppress("SwallowedException") e: IllegalArgumentException) { null }
?: ChecklistSortOption.MANUAL
val showSeparator = (sortOption == ChecklistSortOption.MANUAL ||
@@ -534,7 +534,7 @@ private fun ChecklistFullView(
val checkedCount = items.count { it.isChecked }
val sortOption = try {
note.checklistSortOption?.let { ChecklistSortOption.valueOf(it) }
} catch (e: IllegalArgumentException) { null }
} catch (@Suppress("SwallowedException") e: IllegalArgumentException) { null }
?: ChecklistSortOption.MANUAL
val showSeparator = (sortOption == ChecklistSortOption.MANUAL ||