diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/models/Note.kt b/android/app/src/main/java/dev/dettmer/simplenotes/models/Note.kt index 467cc68..0245293 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/models/Note.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/models/Note.kt @@ -24,7 +24,9 @@ data class Note( val syncStatus: SyncStatus = SyncStatus.LOCAL_ONLY, // v1.4.0: Checklisten-Felder val noteType: NoteType = NoteType.TEXT, - val checklistItems: List? = null + val checklistItems: List? = null, + // 🆕 v1.8.1 (IMPL_03): Persistierte Sortierung + val checklistSortOption: String? = null ) { /** * Serialisiert Note zu JSON @@ -71,13 +73,20 @@ data class Note( * v1.4.0: Unterstützt jetzt auch Checklisten-Format */ fun toMarkdown(): String { + // 🆕 v1.8.1 (IMPL_03): Sortierung im Frontmatter + val sortLine = if (noteType == NoteType.CHECKLIST && checklistSortOption != null) { + "\nsort: $checklistSortOption" + } else { + "" + } + val header = """ --- id: $id created: ${formatISO8601(createdAt)} updated: ${formatISO8601(updatedAt)} device: $deviceId -type: ${noteType.name.lowercase()} +type: ${noteType.name.lowercase()}$sortLine --- # $title @@ -119,6 +128,14 @@ type: ${noteType.name.lowercase()} NoteType.TEXT } + // 🆕 v1.8.1 (IMPL_03): Gespeicherte Sortierung laden + val checklistSortOption = if (jsonObject.has("checklistSortOption") && + !jsonObject.get("checklistSortOption").isJsonNull) { + jsonObject.get("checklistSortOption").asString + } else { + null + } + // Parsen der Basis-Note val rawNote = gson.fromJson(json, NoteRaw::class.java) @@ -158,7 +175,8 @@ type: ${noteType.name.lowercase()} deviceId = rawNote.deviceId, syncStatus = rawNote.syncStatus ?: SyncStatus.LOCAL_ONLY, noteType = noteType, - checklistItems = checklistItems + checklistItems = checklistItems, + checklistSortOption = checklistSortOption // 🆕 v1.8.1 (IMPL_03) ) } catch (e: Exception) { Logger.w(TAG, "Failed to parse JSON: ${e.message}") @@ -246,6 +264,9 @@ type: ${noteType.name.lowercase()} else -> NoteType.TEXT } + // 🆕 v1.8.1 (IMPL_03): Gespeicherte Sortierung aus YAML laden + val checklistSortOption = metadata["sort"] + // v1.4.0: Parse Content basierend auf Typ // FIX: Robusteres Parsing - suche nach dem Titel-Header und extrahiere den Rest val titleLineIndex = contentBlock.lines().indexOfFirst { it.startsWith("# ") } @@ -300,7 +321,8 @@ type: ${noteType.name.lowercase()} deviceId = metadata["device"] ?: "desktop", syncStatus = SyncStatus.SYNCED, // Annahme: Vom Server importiert noteType = noteType, - checklistItems = checklistItems + checklistItems = checklistItems, + checklistSortOption = checklistSortOption // 🆕 v1.8.1 (IMPL_03) ) } catch (e: Exception) { Logger.w(TAG, "Failed to parse Markdown: ${e.message}") 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 341d9d9..610a571 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 @@ -109,6 +109,16 @@ class NoteEditorViewModel( } 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, @@ -351,6 +361,7 @@ class NoteEditorViewModel( content = "", // Empty for checklists noteType = NoteType.CHECKLIST, checklistItems = validItems, + checklistSortOption = _lastChecklistSortOption.value.name, // 🆕 v1.8.1 (IMPL_03) updatedAt = System.currentTimeMillis(), syncStatus = SyncStatus.PENDING ) @@ -360,6 +371,7 @@ class NoteEditorViewModel( content = "", noteType = NoteType.CHECKLIST, checklistItems = validItems, + checklistSortOption = _lastChecklistSortOption.value.name, // 🆕 v1.8.1 (IMPL_03) deviceId = DeviceIdGenerator.getDeviceId(getApplication()), syncStatus = SyncStatus.LOCAL_ONLY ) 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 new file mode 100644 index 0000000..5f70fb5 --- /dev/null +++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/ChecklistPreviewHelper.kt @@ -0,0 +1,63 @@ +package dev.dettmer.simplenotes.ui.main.components + +import dev.dettmer.simplenotes.models.ChecklistItem +import dev.dettmer.simplenotes.models.ChecklistSortOption + +/** + * 🆕 v1.8.1 (IMPL_03): Helper-Funktionen für die Checklisten-Vorschau in Main Activity. + * + * Stellt sicher, dass die Sortierung aus dem Editor konsistent + * in allen Preview-Components (NoteCard, NoteCardCompact, NoteCardGrid) + * angezeigt wird. + */ + +/** + * Sortiert Checklist-Items für die Vorschau basierend auf der + * gespeicherten Sortier-Option. + */ +fun sortChecklistItemsForPreview( + items: List, + sortOptionName: String? +): List { + val sortOption = try { + sortOptionName?.let { ChecklistSortOption.valueOf(it) } + } catch (e: IllegalArgumentException) { + null + } ?: ChecklistSortOption.MANUAL + + return when (sortOption) { + ChecklistSortOption.MANUAL, + ChecklistSortOption.UNCHECKED_FIRST -> + items.sortedBy { it.isChecked } + + ChecklistSortOption.CHECKED_FIRST -> + items.sortedByDescending { it.isChecked } + + ChecklistSortOption.ALPHABETICAL_ASC -> + items.sortedBy { it.text.lowercase() } + + ChecklistSortOption.ALPHABETICAL_DESC -> + items.sortedByDescending { it.text.lowercase() } + } +} + +/** + * Generiert den Vorschau-Text für eine Checkliste mit korrekter + * Sortierung und passenden Emojis. + * + * @param items Die Checklisten-Items + * @param sortOptionName Der Name der ChecklistSortOption (oder null für MANUAL) + * @return Formatierter Preview-String mit Emojis und Zeilenumbrüchen + * + * 🆕 v1.8.1 (IMPL_06): Emoji-Änderung (☑️ statt ✅ für checked items) + */ +fun generateChecklistPreview( + items: List, + sortOptionName: String? +): String { + val sorted = sortChecklistItemsForPreview(items, sortOptionName) + return sorted.joinToString("\n") { item -> + val prefix = if (item.isChecked) "☑️" else "☐" + "$prefix ${item.text}" + } +} diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/NoteCardCompact.kt b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/NoteCardCompact.kt index d04a2f3..4f90014 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/NoteCardCompact.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/NoteCardCompact.kt @@ -149,11 +149,10 @@ fun NoteCardCompact( text = when (note.noteType) { NoteType.TEXT -> note.content NoteType.CHECKLIST -> { - note.checklistItems - ?.joinToString("\n") { item -> - val prefix = if (item.isChecked) "✅" else "☐" - "$prefix ${item.text}" - } ?: "" + // 🆕 v1.8.1 (IMPL_03 + IMPL_06): Sortierte Preview mit neuen Emojis + note.checklistItems?.let { items -> + generateChecklistPreview(items, note.checklistSortOption) + } ?: "" } }, style = MaterialTheme.typography.bodySmall, diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/NoteCardGrid.kt b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/NoteCardGrid.kt index 606b0e7..bf1aec2 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/NoteCardGrid.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/NoteCardGrid.kt @@ -163,11 +163,10 @@ fun NoteCardGrid( text = when (note.noteType) { NoteType.TEXT -> note.content NoteType.CHECKLIST -> { - note.checklistItems - ?.joinToString("\n") { item -> - val prefix = if (item.isChecked) "✅" else "☐" - "$prefix ${item.text}" - } ?: "" + // 🆕 v1.8.1 (IMPL_03 + IMPL_06): Sortierte Preview mit neuen Emojis + note.checklistItems?.let { items -> + generateChecklistPreview(items, note.checklistSortOption) + } ?: "" } }, style = MaterialTheme.typography.bodySmall,