# đŻ 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! đ