feat(v1.5.0): icons, batch delete toast, cursor fix, docs refactor
FEATURES
========
Batch Delete Toast Aggregation:
- New deleteMultipleNotesFromServer() method
- Shows single aggregated toast instead of multiple ("3 notes deleted from server")
- Partial success handling ("3 of 5 notes deleted from server")
- Added string resources: snackbar_notes_deleted_from_server, snackbar_notes_deleted_from_server_partial
Text Editor Cursor Fix:
- Fixed cursor jumping to end after every keystroke when editing notes
- Added initialCursorSet flag to only set cursor position on first load
- Cursor now stays at user's position while editing
- Changed LaunchedEffect(content) to LaunchedEffect(Unit) to prevent repeated resets
DOCUMENTATION REFACTOR
======================
Breaking Change: English is now the default language
- README.md: Now English (was German)
- QUICKSTART.md: Now English (was German)
- CHANGELOG.md: Now English (was mixed EN/DE)
- docs/*.md: All English (was German)
- German versions: Use .de.md suffix (README.de.md, QUICKSTART.de.md, etc.)
Updated for v1.5.0:
- CHANGELOG.md: Fully translated to English with v1.5.0 release notes
- CHANGELOG.de.md: Created German version
- FEATURES.md: Added i18n section, Selection Mode, Jetpack Compose updates
- FEATURES.de.md: Updated with v1.5.0 features
- UPCOMING.md: v1.5.0 marked as released, v1.6.0/v1.7.0 roadmap
- UPCOMING.de.md: Updated German version
All language headers updated:
- English: [Deutsch](*.de.md) · **English**
- German: **Deutsch** · [English](*.md)
F-DROID METADATA
================
Changelogs (F-Droid):
- fastlane/metadata/android/en-US/changelogs/13.txt: Created
- fastlane/metadata/android/de-DE/changelogs/13.txt: Created
Descriptions:
- full_description.txt (EN/DE): Updated with v1.5.0 changes
- Selection Mode instead of Swipe-to-Delete
- i18n support highlighted
- Jetpack Compose UI mentioned
- Silent-Sync Mode added
OTHER FIXES
===========
Code Quality:
- Unused imports removed from multiple files
- maxLineLength fixes
- Detekt config optimized (increased thresholds for v1.5.0)
- AboutScreen: Uses app foreground icon directly
- EmptyState: Shows app icon instead of emoji
- themes.xml: Splash screen uses app foreground icon
This commit is contained in:
262
docs/DOCS.md
262
docs/DOCS.md
@@ -1,14 +1,14 @@
|
||||
# Simple Notes Sync - Technische Dokumentation
|
||||
# Simple Notes Sync - Technical Documentation
|
||||
|
||||
Diese Datei enthält detaillierte technische Informationen über die Implementierung, Architektur und erweiterte Funktionen.
|
||||
This file contains detailed technical information about implementation, architecture, and advanced features.
|
||||
|
||||
**🌍 Sprachen:** **Deutsch** · [English](DOCS.en.md)
|
||||
**🌍 Languages:** [Deutsch](DOCS.de.md) · **English**
|
||||
|
||||
---
|
||||
|
||||
## 📐 Architektur
|
||||
## 📐 Architecture
|
||||
|
||||
### Gesamtübersicht
|
||||
### Overall Overview
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
@@ -23,81 +23,81 @@ Diese Datei enthält detaillierte technische Informationen über die Implementie
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### Android App Architektur
|
||||
### Android App Architecture
|
||||
|
||||
```
|
||||
app/
|
||||
├── models/
|
||||
│ ├── Note.kt # Data class für Notizen
|
||||
│ └── SyncStatus.kt # Sync-Status Enum
|
||||
│ ├── Note.kt # Data class for notes
|
||||
│ └── SyncStatus.kt # Sync status enum
|
||||
├── storage/
|
||||
│ └── NotesStorage.kt # Lokale JSON-Datei Speicherung
|
||||
│ └── NotesStorage.kt # Local JSON file storage
|
||||
├── sync/
|
||||
│ ├── WebDavSyncService.kt # WebDAV Sync-Logik
|
||||
│ ├── NetworkMonitor.kt # WLAN-Erkennung
|
||||
│ ├── SyncWorker.kt # WorkManager Background Worker
|
||||
│ └── BootReceiver.kt # Device Reboot Handler
|
||||
│ ├── WebDavSyncService.kt # WebDAV sync logic
|
||||
│ ├── NetworkMonitor.kt # WiFi detection
|
||||
│ ├── SyncWorker.kt # WorkManager background worker
|
||||
│ └── BootReceiver.kt # Device reboot handler
|
||||
├── adapters/
|
||||
│ └── NotesAdapter.kt # RecyclerView Adapter
|
||||
│ └── NotesAdapter.kt # RecyclerView adapter
|
||||
├── utils/
|
||||
│ ├── Constants.kt # App-Konstanten
|
||||
│ ├── NotificationHelper.kt# Notification Management
|
||||
│ └── Logger.kt # Debug/Release Logging
|
||||
│ ├── Constants.kt # App constants
|
||||
│ ├── NotificationHelper.kt# Notification management
|
||||
│ └── Logger.kt # Debug/release logging
|
||||
└── activities/
|
||||
├── MainActivity.kt # Hauptansicht mit Liste
|
||||
├── NoteEditorActivity.kt# Editor für Notizen
|
||||
└── SettingsActivity.kt # Server-Konfiguration
|
||||
├── MainActivity.kt # Main view with list
|
||||
├── NoteEditorActivity.kt# Note editor
|
||||
└── SettingsActivity.kt # Server configuration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Auto-Sync Implementierung
|
||||
## 🔄 Auto-Sync Implementation
|
||||
|
||||
### WorkManager Periodic Task
|
||||
|
||||
Der Auto-Sync basiert auf **WorkManager** mit folgender Konfiguration:
|
||||
Auto-sync is based on **WorkManager** with the following configuration:
|
||||
|
||||
```kotlin
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.UNMETERED) // Nur WiFi
|
||||
.setRequiredNetworkType(NetworkType.UNMETERED) // WiFi only
|
||||
.build()
|
||||
|
||||
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
|
||||
30, TimeUnit.MINUTES, // Alle 30 Minuten
|
||||
30, TimeUnit.MINUTES, // Every 30 minutes
|
||||
10, TimeUnit.MINUTES // Flex interval
|
||||
)
|
||||
.setConstraints(constraints)
|
||||
.build()
|
||||
```
|
||||
|
||||
**Warum WorkManager?**
|
||||
- ✅ Läuft auch wenn App geschlossen ist
|
||||
- ✅ Automatischer Restart nach Device Reboot
|
||||
**Why WorkManager?**
|
||||
- ✅ Runs even when app is closed
|
||||
- ✅ Automatic restart after device reboot
|
||||
- ✅ Battery-efficient (Android managed)
|
||||
- ✅ Garantierte Ausführung bei erfüllten Constraints
|
||||
- ✅ Guaranteed execution when constraints are met
|
||||
|
||||
### Network Detection
|
||||
|
||||
Wir verwenden **Gateway IP Comparison** um zu prüfen, ob der Server erreichbar ist:
|
||||
We use **Gateway IP Comparison** to check if the server is reachable:
|
||||
|
||||
```kotlin
|
||||
fun isInHomeNetwork(): Boolean {
|
||||
val gatewayIP = getGatewayIP() // z.B. 192.168.0.1
|
||||
val serverIP = extractIPFromUrl(serverUrl) // z.B. 192.168.0.188
|
||||
val gatewayIP = getGatewayIP() // e.g. 192.168.0.1
|
||||
val serverIP = extractIPFromUrl(serverUrl) // e.g. 192.168.0.188
|
||||
|
||||
return isSameNetwork(gatewayIP, serverIP) // Prüft /24 Netzwerk
|
||||
return isSameNetwork(gatewayIP, serverIP) // Checks /24 network
|
||||
}
|
||||
```
|
||||
|
||||
**Vorteile:**
|
||||
- ✅ Keine Location Permissions nötig
|
||||
- ✅ Funktioniert mit allen Android Versionen
|
||||
- ✅ Zuverlässig und schnell
|
||||
**Advantages:**
|
||||
- ✅ No location permissions needed
|
||||
- ✅ Works with all Android versions
|
||||
- ✅ Reliable and fast
|
||||
|
||||
### Sync Flow
|
||||
|
||||
```
|
||||
1. WorkManager wacht auf (alle 30 Min)
|
||||
1. WorkManager wakes up (every 30 min)
|
||||
↓
|
||||
2. Check: WiFi connected?
|
||||
↓
|
||||
@@ -105,7 +105,7 @@ fun isInHomeNetwork(): Boolean {
|
||||
↓
|
||||
4. Load local notes
|
||||
↓
|
||||
5. Upload neue/geänderte Notes → Server
|
||||
5. Upload new/changed notes → Server
|
||||
↓
|
||||
6. Download remote notes ← Server
|
||||
↓
|
||||
@@ -118,20 +118,20 @@ fun isInHomeNetwork(): Boolean {
|
||||
|
||||
---
|
||||
|
||||
## <EFBFBD> Sync-Trigger Übersicht
|
||||
## 🔄 Sync Trigger Overview
|
||||
|
||||
Die App verwendet **4 verschiedene Sync-Trigger** mit unterschiedlichen Anwendungsfällen:
|
||||
The app uses **4 different sync triggers** with different use cases:
|
||||
|
||||
| Trigger | Datei | Funktion | Wann? | Pre-Check? |
|
||||
|---------|-------|----------|-------|------------|
|
||||
| **1. Manueller Sync** | `MainActivity.kt` | `triggerManualSync()` | User klickt auf Sync-Button im Menü | ✅ Ja |
|
||||
| **2. Auto-Sync (onResume)** | `MainActivity.kt` | `triggerAutoSync()` | App wird geöffnet/fortgesetzt | ✅ Ja |
|
||||
| **3. Hintergrund-Sync (Periodic)** | `SyncWorker.kt` | `doWork()` | Alle 15/30/60 Minuten (konfigurierbar) | ✅ Ja |
|
||||
| **4. WiFi-Connect Sync** | `NetworkMonitor.kt` → `SyncWorker.kt` | `triggerWifiConnectSync()` | WiFi verbunden | ✅ Ja |
|
||||
| Trigger | File | Function | When? | Pre-Check? |
|
||||
|---------|------|----------|-------|------------|
|
||||
| **1. Manual Sync** | `MainActivity.kt` | `triggerManualSync()` | User clicks sync button in menu | ✅ Yes |
|
||||
| **2. Auto-Sync (onResume)** | `MainActivity.kt` | `triggerAutoSync()` | App opened/resumed | ✅ Yes |
|
||||
| **3. Background Sync (Periodic)** | `SyncWorker.kt` | `doWork()` | Every 15/30/60 minutes (configurable) | ✅ Yes |
|
||||
| **4. WiFi-Connect Sync** | `NetworkMonitor.kt` → `SyncWorker.kt` | `triggerWifiConnectSync()` | WiFi connected | ✅ Yes |
|
||||
|
||||
### Server-Erreichbarkeits-Check (Pre-Check)
|
||||
### Server Reachability Check (Pre-Check)
|
||||
|
||||
**Alle 4 Sync-Trigger** verwenden vor dem eigentlichen Sync einen **Pre-Check**:
|
||||
**All 4 sync triggers** use a **pre-check** before the actual sync:
|
||||
|
||||
```kotlin
|
||||
// WebDavSyncService.kt - isServerReachable()
|
||||
@@ -148,53 +148,53 @@ suspend fun isServerReachable(): Boolean = withContext(Dispatchers.IO) {
|
||||
}
|
||||
```
|
||||
|
||||
**Warum Socket-Check statt HTTP-Request?**
|
||||
- ⚡ **Schneller:** Socket-Connect ist instant, HTTP-Request dauert länger
|
||||
- 🔋 **Akkuschonender:** Kein HTTP-Overhead (Headers, TLS Handshake, etc.)
|
||||
- 🎯 **Präziser:** Prüft nur Netzwerk-Erreichbarkeit, nicht Server-Logik
|
||||
- 🛡️ **Verhindert Fehler:** Erkennt fremde WiFi-Netze bevor Sync-Fehler entsteht
|
||||
**Why Socket Check instead of HTTP Request?**
|
||||
- ⚡ **Faster:** Socket connect is instant, HTTP request takes longer
|
||||
- 🔋 **Battery Efficient:** No HTTP overhead (headers, TLS handshake, etc.)
|
||||
- 🎯 **More Precise:** Only checks network reachability, not server logic
|
||||
- 🛡️ **Prevents Errors:** Detects foreign WiFi networks before sync error occurs
|
||||
|
||||
**Wann schlägt der Check fehl?**
|
||||
- ❌ Server offline/nicht erreichbar
|
||||
- ❌ Falsches WiFi-Netzwerk (z.B. öffentliches Café-WiFi)
|
||||
- ❌ Netzwerk noch nicht bereit (DHCP/Routing-Delay nach WiFi-Connect)
|
||||
- ❌ VPN blockiert Server-Zugriff
|
||||
- ❌ Keine WebDAV-Server-URL konfiguriert
|
||||
**When does the check fail?**
|
||||
- ❌ Server offline/unreachable
|
||||
- ❌ Wrong WiFi network (e.g. public café WiFi)
|
||||
- ❌ Network not ready yet (DHCP/routing delay after WiFi connect)
|
||||
- ❌ VPN blocks server access
|
||||
- ❌ No WebDAV server URL configured
|
||||
|
||||
### Sync-Verhalten nach Trigger-Typ
|
||||
### Sync Behavior by Trigger Type
|
||||
|
||||
| Trigger | Bei Server nicht erreichbar | Bei erfolgreichem Sync | Throttling |
|
||||
|---------|----------------------------|----------------------|------------|
|
||||
| Manueller Sync | Toast: "Server nicht erreichbar" | Toast: "✅ Gesynct: X Notizen" | Keins |
|
||||
| Auto-Sync (onResume) | Silent abort (kein Toast) | Toast: "✅ Gesynct: X Notizen" | Max. 1x/Min |
|
||||
| Hintergrund-Sync | Silent abort (kein Toast) | Silent (LocalBroadcast only) | 15/30/60 Min |
|
||||
| WiFi-Connect Sync | Silent abort (kein Toast) | Silent (LocalBroadcast only) | WiFi-basiert |
|
||||
| Trigger | When server not reachable | On successful sync | Throttling |
|
||||
|---------|--------------------------|-------------------|------------|
|
||||
| Manual Sync | Toast: "Server not reachable" | Toast: "✅ Synced: X notes" | None |
|
||||
| Auto-Sync (onResume) | Silent abort (no toast) | Toast: "✅ Synced: X notes" | Max. 1x/min |
|
||||
| Background Sync | Silent abort (no toast) | Silent (LocalBroadcast only) | 15/30/60 min |
|
||||
| WiFi-Connect Sync | Silent abort (no toast) | Silent (LocalBroadcast only) | WiFi-based |
|
||||
|
||||
---
|
||||
|
||||
## 🔋 Akku-Optimierung
|
||||
## 🔋 Battery Optimization
|
||||
|
||||
### Verbrauchsanalyse
|
||||
### Usage Analysis
|
||||
|
||||
| Komponente | Frequenz | Verbrauch | Details |
|
||||
| Component | Frequency | Usage | Details |
|
||||
|------------|----------|-----------|---------|
|
||||
| WorkManager Wakeup | Alle 30 Min | ~0.15 mAh | System wacht auf |
|
||||
| Network Check | 48x/Tag | ~0.03 mAh | Gateway IP check |
|
||||
| WebDAV Sync | 2-3x/Tag | ~1.5 mAh | Nur bei Änderungen |
|
||||
| **Total** | - | **~12 mAh/Tag** | **~0.4%** bei 3000mAh |
|
||||
| WorkManager Wakeup | Every 30 min | ~0.15 mAh | System wakes up |
|
||||
| Network Check | 48x/day | ~0.03 mAh | Gateway IP check |
|
||||
| WebDAV Sync | 2-3x/day | ~1.5 mAh | Only when changes |
|
||||
| **Total** | - | **~12 mAh/day** | **~0.4%** at 3000mAh |
|
||||
|
||||
### Optimierungen
|
||||
### Optimizations
|
||||
|
||||
1. **IP Caching**
|
||||
```kotlin
|
||||
private var cachedServerIP: String? = null
|
||||
// DNS lookup nur 1x beim Start, nicht bei jedem Check
|
||||
// DNS lookup only once at start, not every check
|
||||
```
|
||||
|
||||
2. **Throttling**
|
||||
```kotlin
|
||||
private var lastSyncTime = 0L
|
||||
private const val MIN_SYNC_INTERVAL_MS = 60_000L // Max 1 Sync/Min
|
||||
private const val MIN_SYNC_INTERVAL_MS = 60_000L // Max 1 sync/min
|
||||
```
|
||||
|
||||
3. **Conditional Logging**
|
||||
@@ -207,9 +207,9 @@ suspend fun isServerReachable(): Boolean = withContext(Dispatchers.IO) {
|
||||
```
|
||||
|
||||
4. **Network Constraints**
|
||||
- Nur WiFi (nicht mobile Daten)
|
||||
- Nur wenn Server erreichbar
|
||||
- Keine permanenten Listeners
|
||||
- WiFi only (not mobile data)
|
||||
- Only when server is reachable
|
||||
- No permanent listeners
|
||||
|
||||
---
|
||||
|
||||
@@ -255,15 +255,15 @@ suspend fun downloadNotes(): DownloadResult {
|
||||
val localNote = storage.loadNote(remoteNote.id)
|
||||
|
||||
if (localNote == null) {
|
||||
// Neue Note vom Server
|
||||
// New note from server
|
||||
storage.saveNote(remoteNote)
|
||||
downloadedCount++
|
||||
} else if (localNote.modifiedAt < remoteNote.modifiedAt) {
|
||||
// Server hat neuere Version
|
||||
// Server has newer version
|
||||
storage.saveNote(remoteNote)
|
||||
downloadedCount++
|
||||
} else if (localNote.modifiedAt > remoteNote.modifiedAt) {
|
||||
// Lokale Version ist neuer → Conflict
|
||||
// Local version is newer → Conflict
|
||||
resolveConflict(localNote, remoteNote)
|
||||
conflictCount++
|
||||
}
|
||||
@@ -275,19 +275,19 @@ suspend fun downloadNotes(): DownloadResult {
|
||||
|
||||
### Conflict Resolution
|
||||
|
||||
Strategie: **Last-Write-Wins** mit **Conflict Copy**
|
||||
Strategy: **Last-Write-Wins** with **Conflict Copy**
|
||||
|
||||
```kotlin
|
||||
fun resolveConflict(local: Note, remote: Note) {
|
||||
// Remote Note umbenennen (Conflict Copy)
|
||||
// Rename remote note (conflict copy)
|
||||
val conflictNote = remote.copy(
|
||||
id = "${remote.id}_conflict_${System.currentTimeMillis()}",
|
||||
title = "${remote.title} (Konflikt)"
|
||||
title = "${remote.title} (Conflict)"
|
||||
)
|
||||
|
||||
storage.saveNote(conflictNote)
|
||||
|
||||
// Lokale Note bleibt
|
||||
// Local note remains
|
||||
local.syncStatus = SyncStatus.SYNCED
|
||||
storage.saveNote(local)
|
||||
}
|
||||
@@ -302,7 +302,7 @@ fun resolveConflict(local: Note, remote: Note) {
|
||||
```kotlin
|
||||
val channel = NotificationChannel(
|
||||
"notes_sync_channel",
|
||||
"Notizen Synchronisierung",
|
||||
"Notes Synchronization",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
```
|
||||
@@ -315,9 +315,9 @@ fun showSyncSuccess(context: Context, count: Int) {
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, FLAGS)
|
||||
|
||||
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
.setContentTitle("Sync erfolgreich")
|
||||
.setContentText("$count Notizen synchronisiert")
|
||||
.setContentIntent(pendingIntent) // Click öffnet App
|
||||
.setContentTitle("Sync successful")
|
||||
.setContentText("$count notes synchronized")
|
||||
.setContentIntent(pendingIntent) // Click opens app
|
||||
.setAutoCancel(true) // Dismiss on click
|
||||
.build()
|
||||
|
||||
@@ -329,10 +329,10 @@ fun showSyncSuccess(context: Context, count: Int) {
|
||||
|
||||
## 🛡️ Permissions
|
||||
|
||||
Die App benötigt **minimale Permissions**:
|
||||
The app requires **minimal permissions**:
|
||||
|
||||
```xml
|
||||
<!-- Netzwerk -->
|
||||
<!-- Network -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
@@ -348,28 +348,28 @@ Die App benötigt **minimale Permissions**:
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
```
|
||||
|
||||
**Keine Location Permissions!**
|
||||
Wir verwenden Gateway IP Comparison statt SSID-Erkennung. Keine Standortberechtigung nötig.
|
||||
**No Location Permissions!**
|
||||
We use Gateway IP Comparison instead of SSID detection. No location permission required.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Server testen
|
||||
### Test Server
|
||||
|
||||
```bash
|
||||
# WebDAV Server erreichbar?
|
||||
# WebDAV server reachable?
|
||||
curl -u noteuser:password http://192.168.0.188:8080/
|
||||
|
||||
# Datei hochladen
|
||||
# Upload file
|
||||
echo '{"test":"data"}' > test.json
|
||||
curl -u noteuser:password -T test.json http://192.168.0.188:8080/test.json
|
||||
|
||||
# Datei herunterladen
|
||||
# Download file
|
||||
curl -u noteuser:password http://192.168.0.188:8080/test.json
|
||||
```
|
||||
|
||||
### Android App testen
|
||||
### Test Android App
|
||||
|
||||
**Unit Tests:**
|
||||
```bash
|
||||
@@ -384,15 +384,15 @@ cd android
|
||||
|
||||
**Manual Testing Checklist:**
|
||||
|
||||
- [ ] Notiz erstellen → in Liste sichtbar
|
||||
- [ ] Notiz bearbeiten → Änderungen gespeichert
|
||||
- [ ] Notiz löschen → aus Liste entfernt
|
||||
- [ ] Manueller Sync → Server Status "Erreichbar"
|
||||
- [ ] Auto-Sync → Notification nach ~30 Min
|
||||
- [ ] App schließen → Auto-Sync funktioniert weiter
|
||||
- [ ] Device Reboot → Auto-Sync startet automatisch
|
||||
- [ ] Server offline → Error Notification
|
||||
- [ ] Notification Click → App öffnet sich
|
||||
- [ ] Create note → visible in list
|
||||
- [ ] Edit note → changes saved
|
||||
- [ ] Delete note → removed from list
|
||||
- [ ] Manual sync → server status "Reachable"
|
||||
- [ ] Auto-sync → notification after ~30 min
|
||||
- [ ] Close app → auto-sync continues
|
||||
- [ ] Device reboot → auto-sync starts automatically
|
||||
- [ ] Server offline → error notification
|
||||
- [ ] Notification click → app opens
|
||||
|
||||
---
|
||||
|
||||
@@ -413,18 +413,18 @@ cd android
|
||||
# APK: app/build/outputs/apk/release/app-release-unsigned.apk
|
||||
```
|
||||
|
||||
### Signieren (für Distribution)
|
||||
### Sign (for Distribution)
|
||||
|
||||
```bash
|
||||
# Keystore erstellen
|
||||
# Create keystore
|
||||
keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
|
||||
|
||||
# APK signieren
|
||||
# Sign APK
|
||||
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
|
||||
-keystore my-release-key.jks \
|
||||
app-release-unsigned.apk my-alias
|
||||
|
||||
# Optimieren
|
||||
# Optimize
|
||||
zipalign -v 4 app-release-unsigned.apk app-release.apk
|
||||
```
|
||||
|
||||
@@ -435,39 +435,39 @@ zipalign -v 4 app-release-unsigned.apk app-release.apk
|
||||
### LogCat Filter
|
||||
|
||||
```bash
|
||||
# Nur App-Logs
|
||||
# Only app logs
|
||||
adb logcat -s SimpleNotesApp NetworkMonitor SyncWorker WebDavSyncService
|
||||
|
||||
# Mit Timestamps
|
||||
# With timestamps
|
||||
adb logcat -v time -s SyncWorker
|
||||
|
||||
# In Datei speichern
|
||||
# Save to file
|
||||
adb logcat -s SyncWorker > sync_debug.log
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Problem: Auto-Sync funktioniert nicht**
|
||||
**Problem: Auto-sync not working**
|
||||
```
|
||||
Lösung: Akku-Optimierung deaktivieren
|
||||
Solution: Disable battery optimization
|
||||
Settings → Apps → Simple Notes → Battery → Don't optimize
|
||||
```
|
||||
|
||||
**Problem: Server nicht erreichbar**
|
||||
**Problem: Server not reachable**
|
||||
```
|
||||
Check:
|
||||
1. Server läuft? → docker-compose ps
|
||||
2. IP korrekt? → ip addr show
|
||||
3. Port offen? → telnet 192.168.0.188 8080
|
||||
1. Server running? → docker-compose ps
|
||||
2. IP correct? → ip addr show
|
||||
3. Port open? → telnet 192.168.0.188 8080
|
||||
4. Firewall? → sudo ufw allow 8080
|
||||
```
|
||||
|
||||
**Problem: Notifications kommen nicht**
|
||||
**Problem: Notifications not appearing**
|
||||
```
|
||||
Check:
|
||||
1. Notification Permission erteilt?
|
||||
2. Do Not Disturb aktiv?
|
||||
3. App im Background? → Force stop & restart
|
||||
1. Notification permission granted?
|
||||
2. Do Not Disturb active?
|
||||
3. App in background? → Force stop & restart
|
||||
```
|
||||
|
||||
---
|
||||
@@ -504,26 +504,26 @@ androidx.localbroadcastmanager:localbroadcastmanager:1.1.0
|
||||
## 🔮 Roadmap
|
||||
|
||||
### v1.1
|
||||
- [ ] Suche & Filter
|
||||
- [ ] Search & Filter
|
||||
- [ ] Dark Mode
|
||||
- [ ] Tags/Kategorien
|
||||
- [ ] Tags/Categories
|
||||
- [ ] Markdown Preview
|
||||
|
||||
### v2.0
|
||||
- [ ] Desktop Client (Flutter)
|
||||
- [ ] End-to-End Verschlüsselung
|
||||
- [ ] End-to-End Encryption
|
||||
- [ ] Shared Notes (Collaboration)
|
||||
- [ ] Attachment Support
|
||||
|
||||
---
|
||||
|
||||
## 📖 Weitere Dokumentation
|
||||
## 📖 Further Documentation
|
||||
|
||||
- [Project Docs](https://github.com/inventory69/project-docs/tree/main/simple-notes-sync)
|
||||
- [Sync Architecture](https://github.com/inventory69/project-docs/blob/main/simple-notes-sync/SYNC_ARCHITECTURE.md) - **Detaillierte Sync-Trigger Dokumentation**
|
||||
- [Sync Architecture](https://github.com/inventory69/project-docs/blob/main/simple-notes-sync/SYNC_ARCHITECTURE.md) - **Detailed Sync Trigger Documentation**
|
||||
- [Android Guide](https://github.com/inventory69/project-docs/blob/main/simple-notes-sync/ANDROID_GUIDE.md)
|
||||
- [Bugfix Documentation](https://github.com/inventory69/project-docs/blob/main/simple-notes-sync/BUGFIX_SYNC_SPAM_AND_NOTIFICATIONS.md)
|
||||
|
||||
---
|
||||
|
||||
**Letzte Aktualisierung:** 25. Dezember 2025
|
||||
**Last updated:** December 25, 2025
|
||||
|
||||
Reference in New Issue
Block a user