package com.syncflow.ui.shared import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material.icons.outlined.Circle import androidx.compose.material3.* 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.unit.dp import com.syncflow.data.db.entities.SyncEventEntity import com.syncflow.domain.model.SyncEventType import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.format.FormatStyle @Composable fun SyncEventRow(event: SyncEventEntity, showDivider: Boolean = true) { val (icon, tint) = event.eventType.iconAndTint() val timeFmt = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) val timeStr = timeFmt.format(event.timestamp.atZone(ZoneId.systemDefault())) Row( modifier = Modifier .fillMaxWidth() .padding(vertical = 10.dp), verticalAlignment = Alignment.Top, ) { Surface( shape = RoundedCornerShape(10.dp), color = tint.copy(alpha = 0.12f), modifier = Modifier.size(36.dp), ) { Box(contentAlignment = Alignment.Center) { Icon(icon, contentDescription = null, Modifier.size(18.dp), tint = tint) } } Spacer(Modifier.width(12.dp)) Column(modifier = Modifier.weight(1f)) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { Text( event.eventType.label(), style = MaterialTheme.typography.labelMedium, ) Text( timeStr, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } val detail = event.filePath ?: event.message if (detail != null) { Spacer(Modifier.height(2.dp)) Text( text = detail, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, ) } } } if (showDivider) { HorizontalDivider( color = MaterialTheme.colorScheme.outline.copy(alpha = 0.3f), modifier = Modifier.padding(start = 48.dp), ) } } @Composable fun SyncEventType.iconAndTint(): Pair = when (this) { SyncEventType.SYNC_STARTED -> Icons.Default.Sync to MaterialTheme.colorScheme.secondary SyncEventType.SYNC_COMPLETED -> Icons.Default.CheckCircle to MaterialTheme.colorScheme.primary SyncEventType.SYNC_FAILED -> Icons.Default.Error to MaterialTheme.colorScheme.error SyncEventType.FILE_UPLOADED -> Icons.Default.CloudUpload to MaterialTheme.colorScheme.secondary SyncEventType.FILE_DOWNLOADED -> Icons.Default.CloudDownload to MaterialTheme.colorScheme.secondary SyncEventType.FILE_DELETED -> Icons.Default.DeleteForever to MaterialTheme.colorScheme.tertiary SyncEventType.FILE_SKIPPED -> Icons.Outlined.Circle to MaterialTheme.colorScheme.onSurfaceVariant SyncEventType.CONFLICT_DETECTED -> Icons.Default.Warning to MaterialTheme.colorScheme.tertiary SyncEventType.CONFLICT_RESOLVED -> Icons.Default.CheckCircle to MaterialTheme.colorScheme.primary } fun SyncEventType.label(): String = when (this) { SyncEventType.SYNC_STARTED -> "Sync started" SyncEventType.SYNC_COMPLETED -> "Sync completed" SyncEventType.SYNC_FAILED -> "Sync failed" SyncEventType.FILE_UPLOADED -> "File uploaded" SyncEventType.FILE_DOWNLOADED -> "File downloaded" SyncEventType.FILE_DELETED -> "File deleted" SyncEventType.FILE_SKIPPED -> "File skipped" SyncEventType.CONFLICT_DETECTED -> "Conflict detected" SyncEventType.CONFLICT_RESOLVED -> "Conflict resolved" }