diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/MainScreen.kt b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/MainScreen.kt
index ff9f437..99602aa 100644
--- a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/MainScreen.kt
+++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/MainScreen.kt
@@ -17,6 +17,7 @@ import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.SelectAll
import androidx.compose.material.icons.filled.Settings
+import androidx.compose.material.icons.automirrored.outlined.HelpOutline
import androidx.compose.material3.ExperimentalMaterial3Api
// FabPosition nicht mehr benötigt - FAB wird manuell platziert
import androidx.compose.material3.Icon
@@ -53,6 +54,7 @@ import dev.dettmer.simplenotes.ui.main.components.NoteTypeFAB
import dev.dettmer.simplenotes.ui.main.components.NotesList
import dev.dettmer.simplenotes.ui.main.components.NotesStaggeredGrid
import dev.dettmer.simplenotes.ui.main.components.SyncStatusBanner
+import dev.dettmer.simplenotes.ui.main.components.SyncStatusLegendDialog
import kotlinx.coroutines.launch
private const val TIMESTAMP_UPDATE_INTERVAL_MS = 30_000L
@@ -92,6 +94,9 @@ fun MainScreen(
// Delete confirmation dialog state
var showBatchDeleteDialog by remember { mutableStateOf(false) }
+ // 🆕 v1.8.0: Sync status legend dialog
+ var showSyncLegend by remember { mutableStateOf(false) }
+
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
val listState = rememberLazyListState()
@@ -170,6 +175,8 @@ fun MainScreen(
) {
MainTopBar(
syncEnabled = canSync,
+ showSyncLegend = isSyncAvailable, // 🆕 v1.8.0: Nur wenn Sync verfügbar
+ onSyncLegendClick = { showSyncLegend = true }, // 🆕 v1.8.0
onSyncClick = { viewModel.triggerManualSync("toolbar") },
onSettingsClick = onOpenSettings
)
@@ -276,6 +283,13 @@ fun MainScreen(
}
)
}
+
+ // 🆕 v1.8.0: Sync Status Legend Dialog
+ if (showSyncLegend) {
+ SyncStatusLegendDialog(
+ onDismiss = { showSyncLegend = false }
+ )
+ }
}
}
@@ -283,6 +297,8 @@ fun MainScreen(
@Composable
private fun MainTopBar(
syncEnabled: Boolean,
+ showSyncLegend: Boolean, // 🆕 v1.8.0: Ob der Hilfe-Button sichtbar sein soll
+ onSyncLegendClick: () -> Unit, // 🆕 v1.8.0
onSyncClick: () -> Unit,
onSettingsClick: () -> Unit
) {
@@ -294,6 +310,15 @@ private fun MainTopBar(
)
},
actions = {
+ // 🆕 v1.8.0: Sync Status Legend Button (nur wenn Sync verfügbar)
+ if (showSyncLegend) {
+ IconButton(onClick = onSyncLegendClick) {
+ Icon(
+ imageVector = Icons.AutoMirrored.Outlined.HelpOutline,
+ contentDescription = stringResource(R.string.sync_legend_button)
+ )
+ }
+ }
IconButton(
onClick = onSyncClick,
enabled = syncEnabled
diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/SyncStatusLegendDialog.kt b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/SyncStatusLegendDialog.kt
new file mode 100644
index 0000000..9db62d8
--- /dev/null
+++ b/android/app/src/main/java/dev/dettmer/simplenotes/ui/main/components/SyncStatusLegendDialog.kt
@@ -0,0 +1,148 @@
+package dev.dettmer.simplenotes.ui.main.components
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Warning
+import androidx.compose.material.icons.outlined.CloudDone
+import androidx.compose.material.icons.outlined.CloudOff
+import androidx.compose.material.icons.outlined.CloudSync
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import dev.dettmer.simplenotes.R
+
+/**
+ * 🆕 v1.8.0: Dialog showing the sync status icon legend
+ *
+ * Displays all 5 SyncStatus values with their icons, colors,
+ * and descriptions. Helps users understand what each icon means.
+ */
+@Composable
+fun SyncStatusLegendDialog(
+ onDismiss: () -> Unit
+) {
+ AlertDialog(
+ onDismissRequest = onDismiss,
+ title = {
+ Text(
+ text = stringResource(R.string.sync_legend_title),
+ style = MaterialTheme.typography.headlineSmall
+ )
+ },
+ text = {
+ Column(
+ verticalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ // Optional: Kurze Einleitung
+ Text(
+ text = stringResource(R.string.sync_legend_description),
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+
+ HorizontalDivider()
+
+ // ☁️✓ SYNCED
+ LegendRow(
+ icon = Icons.Outlined.CloudDone,
+ tint = MaterialTheme.colorScheme.primary,
+ label = stringResource(R.string.sync_legend_synced_label),
+ description = stringResource(R.string.sync_legend_synced_desc)
+ )
+
+ // ☁️↻ PENDING
+ LegendRow(
+ icon = Icons.Outlined.CloudSync,
+ tint = MaterialTheme.colorScheme.outline,
+ label = stringResource(R.string.sync_legend_pending_label),
+ description = stringResource(R.string.sync_legend_pending_desc)
+ )
+
+ // ⚠️ CONFLICT
+ LegendRow(
+ icon = Icons.Default.Warning,
+ tint = MaterialTheme.colorScheme.error,
+ label = stringResource(R.string.sync_legend_conflict_label),
+ description = stringResource(R.string.sync_legend_conflict_desc)
+ )
+
+ // ☁️✗ LOCAL_ONLY
+ LegendRow(
+ icon = Icons.Outlined.CloudOff,
+ tint = MaterialTheme.colorScheme.outline,
+ label = stringResource(R.string.sync_legend_local_only_label),
+ description = stringResource(R.string.sync_legend_local_only_desc)
+ )
+
+ // ☁️✗ DELETED_ON_SERVER
+ LegendRow(
+ icon = Icons.Outlined.CloudOff,
+ tint = MaterialTheme.colorScheme.outline.copy(alpha = 0.5f),
+ label = stringResource(R.string.sync_legend_deleted_label),
+ description = stringResource(R.string.sync_legend_deleted_desc)
+ )
+ }
+ },
+ confirmButton = {
+ TextButton(onClick = onDismiss) {
+ Text(stringResource(R.string.ok))
+ }
+ }
+ )
+}
+
+/**
+ * Single row in the sync status legend
+ * Shows icon + label + description
+ */
+@Composable
+private fun LegendRow(
+ icon: ImageVector,
+ tint: Color,
+ label: String,
+ description: String
+) {
+ Row(
+ verticalAlignment = Alignment.Top,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Icon(
+ imageVector = icon,
+ contentDescription = null, // Dekorativ, Label reicht
+ tint = tint,
+ modifier = Modifier
+ .size(20.dp)
+ .padding(top = 2.dp)
+ )
+ Spacer(modifier = Modifier.width(12.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = label,
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = description,
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ }
+}
diff --git a/android/app/src/main/res/values-de/strings.xml b/android/app/src/main/res/values-de/strings.xml
index f773ecd..9e99138 100644
--- a/android/app/src/main/res/values-de/strings.xml
+++ b/android/app/src/main/res/values-de/strings.xml
@@ -58,6 +58,21 @@
Synchronisierung fehlgeschlagen
Synchronisierung läuft bereits
+
+ Sync-Status Hilfe
+ Sync-Status Icons
+ Jede Notiz zeigt ein kleines Icon, das den Sync-Status anzeigt:
+ Synchronisiert
+ Diese Notiz ist auf allen Geräten aktuell.
+ Ausstehend
+ Diese Notiz hat lokale Änderungen, die noch synchronisiert werden müssen.
+ Konflikt
+ Diese Notiz wurde auf mehreren Geräten gleichzeitig geändert. Die neueste Version wurde beibehalten.
+ Nur lokal
+ Diese Notiz wurde noch nie mit dem Server synchronisiert.
+ Auf Server gelöscht
+ Diese Notiz wurde auf einem anderen Gerät oder direkt auf dem Server gelöscht. Sie existiert noch lokal.
+
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 8c70906..11b1a41 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -65,6 +65,21 @@
Not yet synced
Deleted on server
+
+ Sync status help
+ Sync Status Icons
+ Each note shows a small icon indicating its sync status:
+ Synced
+ This note is up to date on all devices.
+ Pending
+ This note has local changes waiting to be synced.
+ Conflict
+ This note was changed on multiple devices simultaneously. The latest version was kept.
+ Local only
+ This note has never been synced to the server yet.
+ Deleted on server
+ This note was deleted on another device or directly on the server. It still exists locally.
+