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) { override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
Logger.d(TAG, "═══════════════════════════════════════") Logger.d(TAG, "═══════════════════════════════════════")

View File

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

View File

@@ -91,7 +91,13 @@ class NoteEditorViewModel(
val noteTypeString = savedStateHandle.get<String>(ARG_NOTE_TYPE) ?: NoteType.TEXT.name val noteTypeString = savedStateHandle.get<String>(ARG_NOTE_TYPE) ?: NoteType.TEXT.name
if (noteId != null) { if (noteId != null) {
// Load existing note loadExistingNote(noteId)
} else {
initNewNote(noteTypeString)
}
}
private fun loadExistingNote(noteId: String) {
existingNote = storage.loadNote(noteId) existingNote = storage.loadNote(noteId)
existingNote?.let { note -> existingNote?.let { note ->
currentNoteType = note.noteType currentNoteType = note.noteType
@@ -110,14 +116,15 @@ class NoteEditorViewModel(
} }
if (note.noteType == NoteType.CHECKLIST) { if (note.noteType == NoteType.CHECKLIST) {
loadChecklistData(note)
}
}
}
private fun loadChecklistData(note: Note) {
// 🆕 v1.8.1 (IMPL_03): Gespeicherte Sortierung laden // 🆕 v1.8.1 (IMPL_03): Gespeicherte Sortierung laden
note.checklistSortOption?.let { sortName -> note.checklistSortOption?.let { sortName ->
try { _lastChecklistSortOption.value = parseSortOption(sortName)
_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 { val items = note.checklistItems?.sortedBy { it.order }?.map {
@@ -131,13 +138,12 @@ class NoteEditorViewModel(
// 🆕 v1.8.0 (IMPL_017): Sortierung sicherstellen (falls alte Daten unsortiert sind) // 🆕 v1.8.0 (IMPL_017): Sortierung sicherstellen (falls alte Daten unsortiert sind)
_checklistItems.value = sortChecklistItems(items) _checklistItems.value = sortChecklistItems(items)
} }
}
} else { private fun initNewNote(noteTypeString: String) {
// New note
currentNoteType = try { currentNoteType = try {
NoteType.valueOf(noteTypeString) NoteType.valueOf(noteTypeString)
} catch (e: IllegalArgumentException) { } catch (@Suppress("SwallowedException") e: IllegalArgumentException) {
Logger.w(TAG, "Invalid note type '$noteTypeString', defaulting to TEXT: ${e.message}") Logger.w(TAG, "Invalid note type '$noteTypeString', defaulting to TEXT")
NoteType.TEXT NoteType.TEXT
} }
@@ -158,6 +164,18 @@ class NoteEditorViewModel(
_checklistItems.value = listOf(ChecklistItemState.createEmpty(0)) _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
}
} }
// ═══════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
# ⚡ v1.3.1: detekt Configuration # ⚡ v1.8.1: detekt Configuration
# Pragmatic rules for simple-notes-sync # Pragmatic rules for simple-notes-sync
build: build:
maxIssues: 100 # Allow existing issues for v1.3.1 release, fix in v1.4.0 maxIssues: 0 # v1.8.1: All issues resolved
excludeCorrectable: false excludeCorrectable: false
config: config: