Merge branch 'main' into release/v1.8.1

This commit is contained in:
inventory69
2026-02-11 08:39:21 +01:00
4 changed files with 65 additions and 16 deletions

View File

@@ -10,6 +10,22 @@ Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [1.8.0] - 2026-02-10 ## [1.8.0] - 2026-02-10
### 🚨 CRITICAL BUGFIX (Tag neu erstellt)
**R8/ProGuard Obfuscation Fix - Verhindert Datenverlust**
- 🔧 **KRITISCH:** Falscher ProGuard-Klassenpfad für `Note$Companion$NoteRaw` korrigiert
- Original v1.8.0 hatte spezifische `-keep` Regeln die nicht griffen
- R8 obfuskierte alle NoteRaw-Felder (id→a, title→b, ...)
- Gson konnte JSON nicht mehr parsen → **ALLE Notizen erschienen verschwunden**
- Zurück zur sicheren breiten Regel: `-keep class dev.dettmer.simplenotes.** { *; }`
- 🛡️ Safety-Guards in `detectServerDeletions()` hinzugefügt
- Verhindert Massenlöschung bei leeren `serverNoteIds` (Netzwerkfehler)
- Abort wenn ALLE lokalen Notizen als gelöscht erkannt würden
- ✅ Notizen waren nie wirklich verloren (JSON-Dateien intakt auf Disk + Server)
- ✅ Downgrade auf v1.7.2 holte alle Notizen zurück
**⚠️ Falls du v1.8.0 erste Version installiert hattest:** Deine Notizen sind sicher! Einfach updaten.
### 🎉 Major: Widgets, Sortierung & Erweiterte Sync-Features ### 🎉 Major: Widgets, Sortierung & Erweiterte Sync-Features
Komplettes Widget-System mit interaktiven Checklisten, Notiz-Sortierung und umfangreiche Sync-Verbesserungen! Komplettes Widget-System mit interaktiven Checklisten, Notiz-Sortierung und umfangreiche Sync-Verbesserungen!

View File

@@ -10,6 +10,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [1.8.0] - 2026-02-10 ## [1.8.0] - 2026-02-10
### 🚨 CRITICAL BUGFIX (Tag recreated)
**R8/ProGuard Obfuscation Fix - Prevents Data Loss**
- 🔧 **CRITICAL:** Fixed incorrect ProGuard class path for `Note$Companion$NoteRaw`
- Original v1.8.0 had specific `-keep` rules that didn't match
- R8 obfuscated all NoteRaw fields (id→a, title→b, ...)
- Gson couldn't parse JSON anymore → **ALL notes appeared lost**
- Reverted to safe broad rule: `-keep class dev.dettmer.simplenotes.** { *; }`
- 🛡️ Added safety-guards in `detectServerDeletions()`
- Prevents mass deletion when `serverNoteIds` is empty (network errors)
- Aborts if ALL local notes would be marked as deleted
- ✅ Notes were never actually lost (JSON files intact on disk + server)
- ✅ Downgrade to v1.7.2 restored all notes
**⚠️ If you installed original v1.8.0:** Your notes are safe! Just update.
### 🎉 Major: Widgets, Sorting & Advanced Sync ### 🎉 Major: Widgets, Sorting & Advanced Sync
Complete widget system with interactive checklists, note sorting, and major sync improvements! Complete widget system with interactive checklists, note sorting, and major sync improvements!

View File

@@ -63,21 +63,16 @@
# App-specific rules: Only keep what Gson/reflection needs # App-specific rules: Only keep what Gson/reflection needs
# ═══════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════
# Gson data models (serialized/deserialized via reflection) # 🔧 v1.8.1 FIX: Breite Regel verwenden statt spezifischer Klassen
-keep class dev.dettmer.simplenotes.models.Note { *; } #
-keep class dev.dettmer.simplenotes.models.Note$NoteRaw { *; } # GRUND: NoteRaw ist eine private data class innerhalb von Note.Companion.
-keep class dev.dettmer.simplenotes.models.ChecklistItem { *; } # Der JVM-Klassenname ist Note$Companion$NoteRaw, NICHT Note$NoteRaw.
-keep class dev.dettmer.simplenotes.models.DeletionRecord { *; } # Die spezifische Regel griff nicht R8 obfuskierte NoteRaw-Felder
-keep class dev.dettmer.simplenotes.models.DeletionTracker { *; } # Gson konnte keine JSON-Felder matchen ALLE Notizen unlesbar!
-keep class dev.dettmer.simplenotes.backup.BackupData { *; } #
-keep class dev.dettmer.simplenotes.backup.BackupResult { *; } # Sichere Lösung: Alle App-Klassen behalten (wie in v1.7.2).
# APK-Größenoptimierung kann in v1.9.0 sicher evaluiert werden.
# Keep enum values (used in serialization and widget state) -keep class dev.dettmer.simplenotes.** { *; }
-keepclassmembers enum dev.dettmer.simplenotes.** {
<fields>;
public static **[] values();
public static ** valueOf(java.lang.String);
}
# v1.7.1: Suppress TextInclusionStrategy warnings on older Android versions # v1.7.1: Suppress TextInclusionStrategy warnings on older Android versions
# This class only exists on API 35+ but Compose handles the fallback gracefully # This class only exists on API 35+ but Compose handles the fallback gracefully

View File

@@ -1115,6 +1115,7 @@ class WebDavSyncService(private val context: Context) {
/** /**
* 🆕 v1.8.0: Erkennt Notizen, die auf dem Server gelöscht wurden * 🆕 v1.8.0: Erkennt Notizen, die auf dem Server gelöscht wurden
* 🔧 v1.8.1: Safety-Guard gegen leere serverNoteIds (verhindert Massenlöschung)
* *
* Keine zusätzlichen HTTP-Requests! Nutzt die bereits geladene * Keine zusätzlichen HTTP-Requests! Nutzt die bereits geladene
* serverNoteIds-Liste aus dem PROPFIND-Request. * serverNoteIds-Liste aus dem PROPFIND-Request.
@@ -1131,15 +1132,36 @@ class WebDavSyncService(private val context: Context) {
serverNoteIds: Set<String>, serverNoteIds: Set<String>,
localNotes: List<Note> localNotes: List<Note>
): Int { ): Int {
var deletedCount = 0
val syncedNotes = localNotes.filter { it.syncStatus == SyncStatus.SYNCED } val syncedNotes = localNotes.filter { it.syncStatus == SyncStatus.SYNCED }
// 🔧 v1.8.1 SAFETY: Wenn serverNoteIds leer ist, NIEMALS Notizen als gelöscht markieren!
// Ein leeres Set bedeutet wahrscheinlich: PROPFIND fehlgeschlagen, /notes/ nicht gefunden,
// oder Netzwerkfehler — NICHT dass alle Notizen gelöscht wurden.
if (serverNoteIds.isEmpty()) {
Logger.w(TAG, "⚠️ detectServerDeletions: serverNoteIds is EMPTY! " +
"Skipping deletion detection to prevent data loss. " +
"localSynced=${syncedNotes.size}, localTotal=${localNotes.size}")
return 0
}
// 🔧 v1.8.1 SAFETY: Wenn ALLE lokalen SYNCED-Notizen als gelöscht erkannt werden,
// ist das fast sicher ein Fehler (z.B. falsche Server-URL oder partieller PROPFIND).
// Maximal 50% der Notizen dürfen als gelöscht markiert werden.
val potentialDeletions = syncedNotes.count { it.id !in serverNoteIds }
if (syncedNotes.size > 1 && potentialDeletions == syncedNotes.size) {
Logger.e(TAG, "🚨 detectServerDeletions: ALL ${syncedNotes.size} synced notes " +
"would be marked as deleted! This is almost certainly a bug. " +
"serverNoteIds=${serverNoteIds.size}. ABORTING deletion detection.")
return 0
}
// 🆕 v1.8.0 (IMPL_022): Statistik-Log für Debugging // 🆕 v1.8.0 (IMPL_022): Statistik-Log für Debugging
Logger.d(TAG, "🔍 detectServerDeletions: " + Logger.d(TAG, "🔍 detectServerDeletions: " +
"serverNotes=${serverNoteIds.size}, " + "serverNotes=${serverNoteIds.size}, " +
"localSynced=${syncedNotes.size}, " + "localSynced=${syncedNotes.size}, " +
"localTotal=${localNotes.size}") "localTotal=${localNotes.size}")
var deletedCount = 0
syncedNotes.forEach { note -> syncedNotes.forEach { note ->
// Nur SYNCED-Notizen prüfen: // Nur SYNCED-Notizen prüfen:
// - LOCAL_ONLY: War nie auf Server → irrelevant // - LOCAL_ONLY: War nie auf Server → irrelevant