# 🎯 Simple Notes Sync - Verbesserungsplan **Erstellt am:** 21. Dezember 2025 **Ziel:** UX-Verbesserungen, Material Design 3, Deutsche Lokalisierung, F-Droid Release --- ## 📋 Übersicht der Probleme & Lösungen --- ## 🆕 NEU: Server-Backup Wiederherstellung ### ❗ Neue Anforderung: Notizen vom Server wiederherstellen **Problem:** - User kann keine vollständige Wiederherstellung vom Server machen - Wenn lokale Daten verloren gehen, keine einfache Recovery - Nützlich bei Gerätewechsel oder nach App-Neuinstallation **Lösung:** #### UI-Komponente (Settings) ```kotlin // SettingsActivity.kt - Button hinzufügen // Click Handler buttonRestoreFromServer.setOnClickListener { showRestoreConfirmationDialog() } private fun showRestoreConfirmationDialog() { MaterialAlertDialogBuilder(this) .setTitle("Vom Server wiederherstellen?") .setMessage( "⚠️ WARNUNG:\n\n" + "• Alle lokalen Notizen werden gelöscht\n" + "• Alle Notizen vom Server werden heruntergeladen\n" + "• Diese Aktion kann nicht rückgängig gemacht werden\n\n" + "Fortfahren?" ) .setIcon(R.drawable.ic_warning) .setPositiveButton("Wiederherstellen") { _, _ -> restoreFromServer() } .setNegativeButton("Abbrechen", null) .show() } private fun restoreFromServer() { lifecycleScope.launch { try { // Show progress dialog val progressDialog = MaterialAlertDialogBuilder(this@SettingsActivity) .setTitle("Wiederherstelle...") .setMessage("Lade Notizen vom Server...") .setCancelable(false) .create() progressDialog.show() val syncService = WebDavSyncService(this@SettingsActivity) val result = syncService.restoreFromServer() progressDialog.dismiss() if (result.isSuccess) { MaterialAlertDialogBuilder(this@SettingsActivity) .setTitle("✅ Wiederherstellung erfolgreich") .setMessage("${result.restoredCount} Notizen vom Server wiederhergestellt") .setPositiveButton("OK") { _, _ -> // Trigger MainActivity refresh val intent = Intent("dev.dettmer.simplenotes.NOTES_CHANGED") LocalBroadcastManager.getInstance(this@SettingsActivity) .sendBroadcast(intent) } .show() } else { showErrorDialog(result.errorMessage ?: "Unbekannter Fehler") } } catch (e: Exception) { showErrorDialog(e.message ?: "Wiederherstellung fehlgeschlagen") } } } ``` #### Backend-Logik (WebDavSyncService) ```kotlin // WebDavSyncService.kt data class RestoreResult( val isSuccess: Boolean, val restoredCount: Int = 0, val errorMessage: String? = null ) suspend fun restoreFromServer(): RestoreResult = withContext(Dispatchers.IO) { try { val serverUrl = prefs.getString(Constants.KEY_SERVER_URL, null) val username = prefs.getString(Constants.KEY_USERNAME, null) val password = prefs.getString(Constants.KEY_PASSWORD, null) if (serverUrl.isNullOrEmpty() || username.isNullOrEmpty() || password.isNullOrEmpty()) { return@withContext RestoreResult( isSuccess = false, errorMessage = "Server nicht konfiguriert" ) } // List all remote files val sardine = Sardine() sardine.setCredentials(username, password) val remoteFiles = sardine.list(serverUrl) .filter { it.name.endsWith(".json") && !it.isDirectory } if (remoteFiles.isEmpty()) { return@withContext RestoreResult( isSuccess = false, errorMessage = "Keine Notizen auf dem Server gefunden" ) } val restoredNotes = mutableListOf() // Download each note for (file in remoteFiles) { try { val content = sardine.get(file.href).toString(Charsets.UTF_8) val note = Note.fromJson(content) restoredNotes.add(note) } catch (e: Exception) { Log.w(TAG, "Failed to parse ${file.name}: ${e.message}") // Continue with other files } } if (restoredNotes.isEmpty()) { return@withContext RestoreResult( isSuccess = false, errorMessage = "Keine gültigen Notizen gefunden" ) } // Clear local storage and save all notes withContext(Dispatchers.Main) { storage.clearAll() restoredNotes.forEach { note -> storage.saveNote(note.copy(syncStatus = SyncStatus.SYNCED)) } } RestoreResult( isSuccess = true, restoredCount = restoredNotes.size ) } catch (e: Exception) { Log.e(TAG, "Restore failed", e) RestoreResult( isSuccess = false, errorMessage = e.message ?: "Verbindungsfehler" ) } } ``` #### Storage Update ```kotlin // NotesStorage.kt - Methode hinzufügen fun clearAll() { val file = File(context.filesDir, NOTES_FILE) if (file.exists()) { file.delete() } // Create empty notes list saveAllNotes(emptyList()) } ``` **Betroffene Dateien:** - `android/app/src/main/java/dev/dettmer/simplenotes/SettingsActivity.kt` - `android/app/src/main/java/dev/dettmer/simplenotes/sync/WebDavSyncService.kt` - `android/app/src/main/java/dev/dettmer/simplenotes/storage/NotesStorage.kt` - `android/app/src/main/res/layout/activity_settings.xml` - `android/app/src/main/res/values/strings.xml` - `android/app/src/main/res/drawable/ic_cloud_download.xml` (neu) **Zeitaufwand:** 2-3 Stunden **Strings hinzufügen:** ```xml Vom Server wiederherstellen Vom Server wiederherstellen? ⚠️ WARNUNG:\n\n• Alle lokalen Notizen werden gelöscht\n• Alle Notizen vom Server werden heruntergeladen\n• Diese Aktion kann nicht rückgängig gemacht werden\n\nFortfahren? Wiederherstelle... Lade Notizen vom Server... ✅ Wiederherstellung erfolgreich %d Notizen vom Server wiederhergestellt Server nicht konfiguriert Keine Notizen auf dem Server gefunden Keine gültigen Notizen gefunden ``` --- ### 1️⃣ Server-Status Aktualisierung ⚠️ HOCH **Problem:** - Server-Status wird nicht sofort nach erfolgreichem Verbindungstest grün - User muss App neu öffnen oder Focus ändern **Lösung:** ```kotlin // In SettingsActivity.kt nach testConnection() private fun testConnection() { lifecycleScope.launch { try { showToast("Teste Verbindung...") val syncService = WebDavSyncService(this@SettingsActivity) val result = syncService.testConnection() if (result.isSuccess) { showToast("Verbindung erfolgreich!") checkServerStatus() // ✅ HIER HINZUFÜGEN } else { showToast("Verbindung fehlgeschlagen: ${result.errorMessage}") checkServerStatus() // ✅ Auch bei Fehler aktualisieren } } catch (e: Exception) { showToast("Fehler: ${e.message}") checkServerStatus() // ✅ Auch bei Exception } } } ``` **Betroffene Dateien:** - `android/app/src/main/java/dev/dettmer/simplenotes/SettingsActivity.kt` **Zeitaufwand:** 15 Minuten --- ### 2️⃣ Auto-Save Indikator im Editor ⚠️ HOCH **Problem:** - User erkennt nicht, dass automatisch gespeichert wird - Save-Button fehlt → Verwirrung - Keine visuelle Rückmeldung über Speicher-Status **Lösung A: Auto-Save mit Indikator (Empfohlen)** ```kotlin // NoteEditorActivity.kt private var autoSaveJob: Job? = null private lateinit var saveStatusTextView: TextView private fun setupAutoSave() { val textWatcher = object : TextWatcher { override fun afterTextChanged(s: Editable?) { // Cancel previous save job autoSaveJob?.cancel() // Show "Speichere..." saveStatusTextView.text = "💾 Speichere..." saveStatusTextView.setTextColor(getColor(android.R.color.darker_gray)) // Debounce: Save after 2 seconds of no typing autoSaveJob = lifecycleScope.launch { delay(2000) saveNoteQuietly() // Show "Gespeichert ✓" saveStatusTextView.text = "✓ Gespeichert" saveStatusTextView.setTextColor(getColor(android.R.color.holo_green_dark)) // Hide after 2 seconds delay(2000) saveStatusTextView.text = "" } } // ... beforeTextChanged, onTextChanged } editTextTitle.addTextChangedListener(textWatcher) editTextContent.addTextChangedListener(textWatcher) } private fun saveNoteQuietly() { val title = editTextTitle.text?.toString()?.trim() ?: "" val content = editTextContent.text?.toString()?.trim() ?: "" if (title.isEmpty() && content.isEmpty()) return val note = if (existingNote != null) { existingNote!!.copy( title = title, content = content, updatedAt = System.currentTimeMillis(), syncStatus = SyncStatus.PENDING ) } else { Note( title = title, content = content, deviceId = DeviceIdGenerator.getDeviceId(this), syncStatus = SyncStatus.LOCAL_ONLY ).also { existingNote = it } } storage.saveNote(note) } ``` **Layout Update:** ```xml ``` **Alternative B: Save-Button behalten + Auto-Save** - Button zeigt "Gespeichert ✓" nach Auto-Save - Button disabled wenn keine Änderungen **Betroffene Dateien:** - `android/app/src/main/java/dev/dettmer/simplenotes/NoteEditorActivity.kt` - `android/app/src/main/res/layout/activity_editor.xml` - `android/app/src/main/res/values/strings.xml` **Zeitaufwand:** 1-2 Stunden --- ### 3️⃣ GitHub Releases auf Deutsch ⚠️ MITTEL **Problem:** - Release Notes sind auf Englisch - Asset-Namen teilweise englisch - Zielgruppe ist deutsch **Lösung:** ```yaml # .github/workflows/build-production-apk.yml # Asset-Namen schon auf Deutsch ✓ # Release Body übersetzen: body: | # 📝 Produktions-Release: Simple Notes Sync v${{ env.VERSION_NAME }} ## 📊 Build-Informationen - **Version:** ${{ env.VERSION_NAME }}+${{ env.BUILD_NUMBER }} - **Build-Datum:** ${{ env.COMMIT_DATE }} - **Commit:** ${{ env.SHORT_SHA }} - **Umgebung:** 🟢 **PRODUKTION** --- ## 📋 Änderungen ${{ env.COMMIT_MSG }} --- ## 📦 Download & Installation ### Welche APK sollte ich herunterladen? | Dein Gerät | Diese APK herunterladen | Größe | Kompatibilität | |------------|-------------------------|-------|----------------| | 🤷 Unsicher? | `simple-notes-sync-v${{ env.VERSION_NAME }}-universal.apk` | ~3 MB | Funktioniert auf allen Geräten | | Modern (ab 2018) | `simple-notes-sync-v${{ env.VERSION_NAME }}-arm64-v8a.apk` | ~2 MB | Schneller, kleiner | | Ältere Geräte | `simple-notes-sync-v${{ env.VERSION_NAME }}-armeabi-v7a.apk` | ~2 MB | Ältere ARM-Chips | ### 📲 Installationsschritte 1. Lade die passende APK aus den Assets herunter 2. Aktiviere "Aus unbekannten Quellen installieren" in den Android-Einstellungen 3. Öffne die heruntergeladene APK-Datei 4. Folge den Installationsanweisungen 5. Konfiguriere die WebDAV-Einstellungen in der App --- ## ⚙️ Funktionen - ✅ Automatische WebDAV-Synchronisation alle 30 Minuten (~0,4% Akku/Tag) - ✅ Intelligente Gateway-Erkennung (automatische Heimnetzwerk-Erkennung) - ✅ Material Design 3 Benutzeroberfläche - ✅ Privatsphäre-fokussiert (kein Tracking, keine Analytics) - ✅ Offline-First Architektur --- ## 🔄 Aktualisierung von vorheriger Version Installiere diese APK einfach über die bestehende Installation - alle Daten und Einstellungen bleiben erhalten. --- ## 📱 Obtanium - Automatische Updates Erhalte automatische Updates mit [Obtanium](https://github.com/ImranR98/Obtanium/releases/latest). **Einrichtung:** 1. Installiere Obtanium über den obigen Link 2. Füge die App mit dieser URL hinzu: `https://github.com/inventory69/simple-notes-sync` 3. Aktiviere automatische Updates --- ## 🆘 Support Bei Problemen oder Fragen bitte ein Issue auf GitHub öffnen. --- ## 🔒 Datenschutz & Sicherheit - Alle Daten werden über deinen eigenen WebDAV-Server synchronisiert - Keine Analytics oder Tracking von Drittanbietern - Keine Internet-Berechtigungen außer für WebDAV-Sync - Alle Sync-Vorgänge verschlüsselt (HTTPS) - Open Source - prüfe den Code selbst --- ## 🛠️ Technische Details - **Sprache:** Kotlin - **UI:** Material Design 3 - **Sync:** WorkManager + WebDAV - **Target SDK:** Android 16 (API 36) - **Min SDK:** Android 8.0 (API 26) ``` **Betroffene Dateien:** - `.github/workflows/build-production-apk.yml` **Zeitaufwand:** 30 Minuten --- ### 4️⃣ Material Design 3 - Vollständige Migration ⚠️ HOCH **Basierend auf:** `MATERIAL_DESIGN_3_MIGRATION.md` Plan **Problem:** - Aktuelles Design ist Material Design 2 - Keine Dynamic Colors (Material You) - Veraltete Komponenten und Farb-Palette - Keine Android 12+ Features **Ziel:** - ✨ Dynamische Farben aus Wallpaper (Material You) - 🎨 Modern Design Language - 🔲 Größere Corner Radius (16dp) - 📱 Material Symbols Icons - 📝 Material 3 Typography - 🌓 Perfekter Dark Mode - ♿ Bessere Accessibility --- #### Phase 4.1: Theme & Dynamic Colors (15 Min) **themes.xml:** ```xml ``` **colors.xml (Material 3 Baseline - Grün/Natur Theme):** ```xml #006C4C #FFFFFF #89F8C7 #002114 #4D6357 #FFFFFF #CFE9D9 #0A1F16 #3D6373 #FFFFFF #C1E8FB #001F29 #BA1A1A #FFFFFF #FFDAD6 #410002 #FBFDF9 #191C1A #FBFDF9 #191C1A #DCE5DD #404943 #707973 #BFC9C2 ``` **values-night/colors.xml (neu erstellen):** ```xml #6DDBAC #003826 #005138 #89F8C7 #B3CCBD #1F352A #354B40 #CFE9D9 #A5CCE0 #073543 #254B5B #C1E8FB #FFB4AB #690005 #93000A #FFDAD6 #191C1A #E1E3DF #191C1A #E1E3DF #404943 #BFC9C2 #8A938C #404943 ``` **MainActivity.kt - Dynamic Colors aktivieren:** ```kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Enable Dynamic Colors (Android 12+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { DynamicColors.applyToActivityIfAvailable(this) } setContentView(R.layout.activity_main) // ... } // Import hinzufügen: import com.google.android.material.color.DynamicColors import android.os.Build ``` **Betroffene Dateien:** - `android/app/src/main/res/values/themes.xml` - `android/app/src/main/res/values/colors.xml` - `android/app/src/main/res/values-night/colors.xml` (neu) - `android/app/src/main/java/dev/dettmer/simplenotes/MainActivity.kt` **Zeitaufwand:** 15 Minuten --- #### Phase 4.2: MainActivity Layout (10 Min) **activity_main.xml - Material 3 Update:** ```xml ``` **Betroffene Dateien:** - `android/app/src/main/res/layout/activity_main.xml` - `android/app/src/main/java/dev/dettmer/simplenotes/MainActivity.kt` **Zeitaufwand:** 10 Minuten --- #### Phase 4.3: Note Item Card (10 Min) **item_note.xml - Material 3 Card:** ```xml ``` **Betroffene Dateien:** - `android/app/src/main/res/layout/item_note.xml` **Zeitaufwand:** 10 Minuten --- #### Phase 4.4: Editor Layout (10 Min) **activity_editor.xml - Material 3 TextInputLayouts:** ```xml ``` **Betroffene Dateien:** - `android/app/src/main/res/layout/activity_editor.xml` **Zeitaufwand:** 10 Minuten --- #### Phase 4.5: Material Symbols Icons (15 Min) **Icons erstellen in `res/drawable/`:** 1. **ic_add_24.xml** ```xml ``` 2. **ic_sync_24.xml** 3. **ic_settings_24.xml** 4. **ic_cloud_done_24.xml** 5. **ic_cloud_sync_24.xml** 6. **ic_warning_24.xml** 7. **ic_server_24.xml** 8. **ic_person_24.xml** 9. **ic_lock_24.xml** 10. **ic_cloud_download_24.xml** 11. **ic_check_24.xml** Tool: https://fonts.google.com/icons **Betroffene Dateien:** - `android/app/src/main/res/drawable/` (11 neue Icons) **Zeitaufwand:** 15 Minuten --- #### Phase 4.6: Splash Screen (30 Min) **themes.xml - Splash Screen hinzufügen:** ```xml ``` **AndroidManifest.xml:** ```xml ``` **MainActivity.kt:** ```kotlin override fun onCreate(savedInstanceState: Bundle?) { // Handle splash screen installSplashScreen() super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } // Import: import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen ``` **build.gradle.kts:** ```kotlin dependencies { implementation("androidx.core:core-splashscreen:1.0.1") } ``` **Betroffene Dateien:** - `android/app/src/main/res/values/themes.xml` - `android/app/src/main/AndroidManifest.xml` - `android/app/src/main/java/dev/dettmer/simplenotes/MainActivity.kt` - `android/app/build.gradle.kts` **Zeitaufwand:** 30 Minuten --- ### Material 3 Gesamtaufwand: ~90 Minuten --- ### 5️⃣ F-Droid Release Vorbereitung ⚠️ MITTEL **Problem:** - Keine F-Droid Metadata vorhanden - Keine Build-Variante ohne Google-Dependencies **Lösung - Verzeichnisstruktur:** ``` simple-notes-sync/ ├── metadata/ │ └── de-DE/ │ ├── full_description.txt │ ├── short_description.txt │ ├── title.txt │ └── changelogs/ │ ├── 1.txt │ ├── 2.txt │ └── 3.txt └── fastlane/ └── metadata/ └── android/ └── de-DE/ ├── images/ │ ├── icon.png │ ├── featureGraphic.png │ └── phoneScreenshots/ │ ├── 1.png │ ├── 2.png │ └── 3.png ├── full_description.txt ├── short_description.txt └── title.txt ``` **metadata/de-DE/full_description.txt:** ``` Simple Notes Sync - Deine privaten Notizen, selbst gehostet Eine minimalistische, datenschutzfreundliche Notizen-App mit automatischer WebDAV-Synchronisation. HAUPTMERKMALE: 🔒 Datenschutz • Alle Daten auf deinem eigenen Server • Keine Cloud-Dienste von Drittanbietern • Kein Tracking oder Analytics • Open Source - transparent und überprüfbar ☁️ Automatische Synchronisation • WebDAV-Sync alle 30 Minuten • Intelligente Netzwerkerkennung • Nur im WLAN (konfigurierbar) • Minimaler Akkuverbrauch (~0,4%/Tag) ✨ Einfach & Schnell • Klare, aufgeräumte Benutzeroberfläche • Blitzschnelle Notiz-Erfassung • Offline-First Design • Material Design 3 🔧 Flexibel • Funktioniert mit jedem WebDAV-Server • Nextcloud, ownCloud, Apache, etc. • Docker-Setup verfügbar • Konflikterkennung und -lösung TECHNISCHE DETAILS: • Keine Google Services benötigt • Keine unnötigen Berechtigungen • Minimale App-Größe (~2-3 MB) • Android 8.0+ kompatibel • Kotlin + Material Design 3 PERFECT FÜR: • Schnelle Notizen und Ideen • Einkaufslisten • Todo-Listen • Persönliche Gedanken • Alle, die Wert auf Datenschutz legen Der Quellcode ist verfügbar auf: https://github.com/inventory69/simple-notes-sync ``` **metadata/de-DE/short_description.txt:** ``` Minimalistische Notizen-App mit selbst-gehosteter WebDAV-Synchronisation ``` **metadata/de-DE/title.txt:** ``` Simple Notes Sync ``` **Build-Flavor ohne Google:** ```kotlin // build.gradle.kts android { flavorDimensions += "version" productFlavors { create("fdroid") { dimension = "version" // Keine Google/Firebase Dependencies } create("playstore") { dimension = "version" // Optional: Google Services für Analytics etc. } } } dependencies { // Base dependencies (alle Flavors) implementation(libs.androidx.core.ktx) implementation(libs.material) // PlayStore specific (optional) "playstoreImplementation"("com.google.firebase:firebase-analytics:21.5.0") } ``` **Betroffene Dateien:** - `metadata/` (neu) - `fastlane/` (neu) - `android/app/build.gradle.kts` (Flavors hinzufügen) - Screenshots erstellen (phone + tablet) **Zeitaufwand:** 3-4 Stunden (inkl. Screenshots) --- ### 5️⃣ Material Design 3 Theme ⚠️ HOCH **Problem:** - Aktuelles Theme ist Material Design 2 - Keine Dynamic Colors (Material You) - Veraltete Farb-Palette **Lösung - themes.xml:** ```xml ``` **colors.xml (Material 3 Baseline):** ```xml #006C4C #FFFFFF #89F8C7 #002114 #4D6357 #FFFFFF #CFE9D9 #0A1F16 #3D6373 #FFFFFF #C1E8FB #001F29 #BA1A1A #FFFFFF #FFDAD6 #410002 #FBFDF9 #191C1A #FBFDF9 #191C1A #DCE5DD #404943 #707973 #BFC9C2 ``` **Dynamic Colors aktivieren (MainActivity.kt):** ```kotlin override fun onCreate(savedInstanceState: Bundle?) { // Enable dynamic colors (Android 12+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { DynamicColors.applyToActivityIfAvailable(this) } super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // ... } ``` **Dependency hinzufügen:** ```kotlin // build.gradle.kts dependencies { implementation("com.google.android.material:material:1.11.0") } ``` **Betroffene Dateien:** - `android/app/src/main/res/values/themes.xml` - `android/app/src/main/res/values/colors.xml` - `android/app/src/main/res/values-night/colors.xml` (neu) - `android/app/src/main/java/dev/dettmer/simplenotes/MainActivity.kt` - `android/app/build.gradle.kts` **Zeitaufwand:** 2-3 Stunden --- ### 6️⃣ Settings UI mit Material 3 ⚠️ MITTEL **Problem:** - Plain TextInputLayouts ohne Icons - Keine visuellen Gruppierungen - Server-Status Wechsel nicht animiert **Lösung - activity_settings.xml:** ```xml ``` **Animierter Server-Status (SettingsActivity.kt):** ```kotlin private fun updateServerStatus(status: ServerStatus) { val chip = findViewById(R.id.chipServerStatus) // Animate transition chip.animate() .alpha(0f) .setDuration(150) .withEndAction { when (status) { ServerStatus.CHECKING -> { chip.text = "🔍 Prüfe Server..." chip.chipBackgroundColor = ColorStateList.valueOf( getColor(R.color.md_theme_surfaceVariant) ) chip.setChipIconResource(R.drawable.ic_sync) } ServerStatus.REACHABLE -> { chip.text = "✅ Server erreichbar" chip.chipBackgroundColor = ColorStateList.valueOf( getColor(R.color.md_theme_primaryContainer) ) chip.setChipIconResource(R.drawable.ic_check_circle) } ServerStatus.UNREACHABLE -> { chip.text = "❌ Nicht erreichbar" chip.chipBackgroundColor = ColorStateList.valueOf( getColor(R.color.md_theme_errorContainer) ) chip.setChipIconResource(R.drawable.ic_error) } ServerStatus.NOT_CONFIGURED -> { chip.text = "⚠️ Nicht konfiguriert" chip.chipBackgroundColor = ColorStateList.valueOf( getColor(R.color.md_theme_surfaceVariant) ) chip.setChipIconResource(R.drawable.ic_warning) } } chip.animate() .alpha(1f) .setDuration(150) .start() } .start() } enum class ServerStatus { CHECKING, REACHABLE, UNREACHABLE, NOT_CONFIGURED } ``` **Icons benötigt (drawable/):** - `ic_server.xml` - `ic_person.xml` - `ic_lock.xml` - `ic_check_circle.xml` - `ic_sync.xml` - `ic_error.xml` - `ic_warning.xml` **Betroffene Dateien:** - `android/app/src/main/res/layout/activity_settings.xml` - `android/app/src/main/java/dev/dettmer/simplenotes/SettingsActivity.kt` - `android/app/src/main/res/drawable/` (Icons) **Zeitaufwand:** 3-4 Stunden --- ### 7️⃣ Main Activity mit Material 3 Cards ⚠️ HOCH **Problem:** - Notizen in einfachen ListItems - Keine Elevation/Shadow - Swipe-to-Delete fehlt **Lösung - item_note.xml:** ```xml ``` **Swipe-to-Delete (MainActivity.kt):** ```kotlin private fun setupRecyclerView() { recyclerView = findViewById(R.id.recyclerView) adapter = NotesAdapter { note -> openNoteEditor(note.id) } recyclerView.adapter = adapter recyclerView.layoutManager = LinearLayoutManager(this) // Swipe-to-Delete val swipeHandler = object : ItemTouchHelper.SimpleCallback( 0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT ) { override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean = false override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { val position = viewHolder.adapterPosition val note = adapter.notes[position] // Delete with undo adapter.removeNote(position) storage.deleteNote(note.id) Snackbar.make( findViewById(R.id.coordinator), "Notiz gelöscht", Snackbar.LENGTH_LONG ).setAction("RÜCKGÄNGIG") { adapter.addNote(position, note) storage.saveNote(note) }.show() } override fun onChildDraw( c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean ) { val itemView = viewHolder.itemView val paint = Paint() paint.color = getColor(R.color.md_theme_errorContainer) // Draw background if (dX > 0) { c.drawRect( itemView.left.toFloat(), itemView.top.toFloat(), dX, itemView.bottom.toFloat(), paint ) } else { c.drawRect( itemView.right.toFloat() + dX, itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat(), paint ) } super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) } } ItemTouchHelper(swipeHandler).attachToRecyclerView(recyclerView) } ``` **Empty State (activity_main.xml):** ```xml ``` **Extended FAB (activity_main.xml):** ```xml ``` **Betroffene Dateien:** - `android/app/src/main/res/layout/activity_main.xml` - `android/app/src/main/res/layout/item_note.xml` - `android/app/src/main/java/dev/dettmer/simplenotes/MainActivity.kt` - `android/app/src/main/java/dev/dettmer/simplenotes/adapters/NotesAdapter.kt` **Zeitaufwand:** 4-5 Stunden --- ### 8️⃣ Editor mit Material 3 ⚠️ MITTEL **Problem:** - Einfache EditText-Felder - Kein Character Counter - Keine visuelle Trennung **Lösung - activity_editor.xml:** ```xml ``` **Betroffene Dateien:** - `android/app/src/main/res/layout/activity_editor.xml` - `android/app/src/main/java/dev/dettmer/simplenotes/NoteEditorActivity.kt` **Zeitaufwand:** 2 Stunden --- ### 9️⃣ Splash Screen mit Material 3 ⚠️ NIEDRIG **Problem:** - Kein moderner Splash Screen **Lösung:** ```xml ``` ```xml ``` ```kotlin // MainActivity.kt override fun onCreate(savedInstanceState: Bundle?) { // Handle the splash screen transition installSplashScreen() super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } ``` **Dependency:** ```kotlin implementation("androidx.core:core-splashscreen:1.0.1") ``` **Betroffene Dateien:** - `android/app/src/main/res/values/themes.xml` - `android/app/src/main/AndroidManifest.xml` - `android/app/src/main/java/dev/dettmer/simplenotes/MainActivity.kt` - `android/app/build.gradle.kts` **Zeitaufwand:** 30 Minuten --- ### 🔟 Deutsche Lokalisierung ⚠️ MITTEL **Problem:** - Einige Strings noch auf Englisch - Release Notes englisch - Error Messages englisch **Lösung - strings.xml vervollständigen:** ```xml Simple Notes Noch keine Notizen.\nTippe + um eine zu erstellen. Notiz hinzufügen Synchronisieren Einstellungen Notiz bearbeiten Neue Notiz Titel Inhalt Speichern Löschen Speichere… ✓ Gespeichert Änderungen werden automatisch gespeichert Server-Einstellungen Server URL z.B. https://cloud.example.com/remote.php/dav/files/username/notes Benutzername Passwort WLAN-Einstellungen Heim-WLAN SSID Auto-Sync aktiviert Synchronisiert alle 30 Minuten Auto-Sync funktioniert nur im selben WLAN-Netzwerk wie dein Server. Minimaler Akkuverbrauch (~0.4%/Tag). Verbindung testen Jetzt synchronisieren Sync-Status 🔍 Prüfe Server… ✅ Server erreichbar ❌ Nicht erreichbar ⚠️ Nicht konfiguriert Teste Verbindung… Verbindung erfolgreich! Verbindung fehlgeschlagen: %s Synchronisiere… Erfolgreich! %d Notizen synchronisiert Sync fehlgeschlagen: %s Sync abgeschlossen. %d Konflikte erkannt! Notiz gespeichert Notiz gelöscht RÜCKGÄNGIG Notiz löschen? Diese Aktion kann nicht rückgängig gemacht werden. Abbrechen Hintergrund-Synchronisation Damit die App im Hintergrund synchronisieren kann, muss die Akku-Optimierung deaktiviert werden.\n\nBitte wähle \'Nicht optimieren\' für Simple Notes. Einstellungen öffnen Später Titel oder Inhalt darf nicht leer sein Netzwerkfehler: %s Server-Fehler: %s Authentifizierung fehlgeschlagen Unbekannter Fehler: %s Notizen Synchronisierung Benachrichtigungen über Sync-Status Sync erfolgreich %d Notizen synchronisiert Sync fehlgeschlagen %s ``` **Betroffene Dateien:** - `android/app/src/main/res/values/strings.xml` - `.github/workflows/build-production-apk.yml` - Alle `.kt` Dateien mit hardcoded strings **Zeitaufwand:** 2 Stunden --- ## 📊 Zusammenfassung & Prioritäten ### Phase 1: Kritische UX-Fixes (Sofort) ⚡ **Zeitaufwand: ~3-4 Stunden** 1. ✅ Server-Status Aktualisierung (15 min) 2. ✅ Auto-Save Indikator (1-2 h) 3. ✅ GitHub Releases auf Deutsch (30 min) 4. ✅ Server-Backup Wiederherstellung (2-3 h) ### Phase 2: Material Design 3 Migration (1 Tag) 🎨 **Zeitaufwand: ~90 Minuten** 5. ✅ Theme & Dynamic Colors (15 min) 6. ✅ MainActivity Layout (10 min) 7. ✅ Note Item Card (10 min) 8. ✅ Editor Layout (10 min) 9. ✅ Settings Layout (10 min) - aus Phase 3 vorgezogen 10. ✅ Material Icons (15 min) 11. ✅ Splash Screen (30 min) ### Phase 3: Advanced UI Features (2-3 Tage) 🚀 **Zeitaufwand: ~4-5 Stunden** 12. ✅ Swipe-to-Delete (1 h) 13. ✅ Empty State (30 min) 14. ✅ Animierte Server-Status Änderung (1 h) 15. ✅ Deutsche Lokalisierung vervollständigen (1-2 h) ### Phase 4: F-Droid Release (1 Tag) 📦 **Zeitaufwand: ~4 Stunden** 16. ✅ F-Droid Metadata (3-4 h) 17. ✅ F-Droid Build-Flavor (30 min) --- ## 🎯 Empfohlene Reihenfolge ### Woche 1: Fundament & Kritische Fixes **Tag 1 (3-4h):** Phase 1 - Kritische UX-Fixes - Server-Status sofort grün nach Test - Auto-Save mit visuellem Feedback - Deutsche Release Notes - **Server-Backup Funktion** ← NEU & WICHTIG **Tag 2 (1.5h):** Phase 2 Start - Material Design 3 Foundation - Theme & Dynamic Colors aktivieren - MainActivity Layout modernisieren - Note Item Cards verbessern **Tag 3 (1.5h):** Phase 2 Fortführung - Material Design 3 - Editor Layout upgraden - Settings Layout modernisieren - Material Icons erstellen - Splash Screen implementieren ### Woche 2: Polish & Release **Tag 4 (2-3h):** Phase 3 - Advanced Features - Swipe-to-Delete mit Animation - Empty State mit Illustration - Server-Status Animationen - Deutsche Strings vervollständigen **Tag 5 (4h):** Phase 4 - F-Droid Vorbereitung - Metadata erstellen - Screenshots machen - Build-Flavor konfigurieren --- ## 🆕 Neue Features Zusammenfassung ### Server-Backup Wiederherstellung **Warum wichtig:** - ✅ Gerätewechsel einfach - ✅ Recovery nach App-Neuinstallation - ✅ Datensicherheit erhöht - ✅ User-Vertrauen gestärkt **Wo in der UI:** - Settings Activity → neuer Button "Vom Server wiederherstellen" - Warn-Dialog vor Ausführung - Progress-Dialog während Download - Success-Dialog mit Anzahl wiederhergestellter Notizen **Backend:** - `WebDavSyncService.restoreFromServer()` - `NotesStorage.clearAll()` - Vollständiger Download aller Server-Notizen - Überschreibt lokale Daten komplett --- ## 📝 Material Design 3 - Schnellreferenz ### Umgesetzt wird: ✅ **Dynamic Colors** - Farben aus Wallpaper (Android 12+) ✅ **Material 3 Components** - Cards, Buttons, TextInputs ✅ **16dp Corner Radius** - Modernere abgerundete Ecken ✅ **Material Symbols** - Neue Icon-Familie ✅ **Typography Scale** - Material 3 Text-Styles ✅ **Dark Mode** - Perfekt abgestimmte Nacht-Farben ✅ **Splash Screen API** - Android 12+ Native Splash ### Design-Token: - **Primary:** Grün (#006C4C) - Natur, Notizen, Wachstum - **Secondary:** Grau-Grün - Subtil, harmonisch - **Surface:** Hell/Dunkel - Abhängig von Theme - **Shapes:** Small 12dp, Medium 16dp, Large 24dp --- ## 📋 Checkliste vor Start - [ ] Branch erstellen: `git checkout -b feature/ux-improvements` - [ ] Backup vom aktuellen Stand - [ ] Material 3 Dependency prüfen: `com.google.android.material:material:1.11.0` - [ ] Android Studio aktualisiert - [ ] Testgerät mit Android 12+ für Dynamic Colors --- ## 🧪 Testing nach Abschluss ### Manuell: - [ ] Alle Layouts auf Smartphone (Phone) - [ ] Alle Layouts auf Tablet - [ ] Dark Mode überall - [ ] Light Mode überall - [ ] Dynamic Colors (Android 12+) - [ ] Server-Backup: Restore funktioniert - [ ] Server-Backup: Dialog-Texte korrekt - [ ] Auto-Save: Indikator erscheint - [ ] Auto-Save: Speichert nach 2s - [ ] Server-Status: Wird sofort aktualisiert - [ ] Swipe-to-Delete: Animation smooth - [ ] Empty State: Zeigt sich bei 0 Notizen - [ ] Splash Screen: Erscheint beim Start - [ ] Alle Icons: Richtige Farbe (Tint) - [ ] Alle Buttons: Funktionieren - [ ] Deutsch: Keine englischen Strings mehr ### Automatisch: - [ ] Build erfolgreich (Debug) - [ ] Build erfolgreich (Release) - [ ] APK Size akzeptabel (<5 MB) - [ ] Keine Lint-Errors - [ ] ProGuard-Regeln funktionieren --- ## 📚 Referenzen & Tools ### Material Design 3: - [Material Design 3 Guidelines](https://m3.material.io/) - [Material Theme Builder](https://material-foundation.github.io/material-theme-builder/) - [Material Symbols Icons](https://fonts.google.com/icons) ### Android: - [Splash Screen API](https://developer.android.com/develop/ui/views/launch/splash-screen) - [Dynamic Colors](https://developer.android.com/develop/ui/views/theming/dynamic-colors) --- ## 📝 Nächste Schritte Soll ich mit **Phase 1** (kritische UX-Fixes + Server-Backup) beginnen? ### Was ich jetzt machen würde: 1. **Server-Backup implementieren** (2-3h) - Höchste Priorität: User-requested Feature - Kritisch für Datensicherheit 2. **Server-Status sofort aktualisieren** (15 min) - Schneller Win - Verbessert UX sofort 3. **Auto-Save Indikator** (1-2h) - Eliminiert Verwirrung - Modernes Pattern 4. **Material 3 Foundation** (90 min) - Theme & Colors - Basis für alles weitere Diese 4 Tasks würden den größten Impact haben und sind in ~4-6 Stunden machbar! 🚀