diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/sync/SyncWorker.kt b/android/app/src/main/java/dev/dettmer/simplenotes/sync/SyncWorker.kt index 36ca5d2..1c6f2a8 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/sync/SyncWorker.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/sync/SyncWorker.kt @@ -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, "═══════════════════════════════════════") diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/ui/editor/NoteEditorScreen.kt b/android/app/src/main/java/dev/dettmer/simplenotes/ui/editor/NoteEditorScreen.kt index 3a4b966..f071bcc 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/ui/editor/NoteEditorScreen.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/editor/NoteEditorScreen.kt @@ -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( diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/ui/editor/NoteEditorViewModel.kt b/android/app/src/main/java/dev/dettmer/simplenotes/ui/editor/NoteEditorViewModel.kt index 9e31e71..6dcbaad 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/ui/editor/NoteEditorViewModel.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/editor/NoteEditorViewModel.kt @@ -91,74 +91,92 @@ class NoteEditorViewModel( val noteTypeString = savedStateHandle.get(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 diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/UpdateChangelogSheet.kt b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/UpdateChangelogSheet.kt index 429c468..9aad79b 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/UpdateChangelogSheet.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/UpdateChangelogSheet.kt @@ -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 diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/ChecklistPreviewHelper.kt b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/ChecklistPreviewHelper.kt index 5f70fb5..e67ab37 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/ChecklistPreviewHelper.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/ChecklistPreviewHelper.kt @@ -21,7 +21,7 @@ fun sortChecklistItemsForPreview( ): List { val sortOption = try { sortOptionName?.let { ChecklistSortOption.valueOf(it) } - } catch (e: IllegalArgumentException) { + } catch (@Suppress("SwallowedException") e: IllegalArgumentException) { null } ?: ChecklistSortOption.MANUAL diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/widget/NoteWidgetActions.kt b/android/app/src/main/java/dev/dettmer/simplenotes/widget/NoteWidgetActions.kt index c85e14f..386e8bf 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/widget/NoteWidgetActions.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/widget/NoteWidgetActions.kt @@ -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 || diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/widget/NoteWidgetContent.kt b/android/app/src/main/java/dev/dettmer/simplenotes/widget/NoteWidgetContent.kt index 986d0f6..09c2111 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/widget/NoteWidgetContent.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/widget/NoteWidgetContent.kt @@ -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 || diff --git a/android/config/detekt/detekt.yml b/android/config/detekt/detekt.yml index fbd5409..0c3a7d7 100644 --- a/android/config/detekt/detekt.yml +++ b/android/config/detekt/detekt.yml @@ -1,8 +1,8 @@ -# ⚡ v1.3.1: detekt Configuration +# ⚡ v1.8.1: detekt Configuration # Pragmatic rules for simple-notes-sync 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 config: