feat: sauvegarde du compte CalDAV même si la connexion échoue, avec indicateur visuel

This commit is contained in:
2026-06-06 07:18:34 +02:00
parent dc6847d205
commit 2e59d54de6
2 changed files with 47 additions and 4 deletions
@@ -15,6 +15,7 @@ import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Download
import androidx.compose.material.icons.outlined.Sync
import androidx.compose.material.icons.outlined.Warning
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -23,6 +24,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.SegmentedButton
@@ -185,9 +187,10 @@ fun SettingsScreen(
}
discovery.second?.let { error ->
Text(
text = error,
text = "Connexion échouée — le compte a été ajouté sans synchronisation : $error",
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(horizontal = 16.dp),
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
)
}
@@ -240,10 +243,28 @@ private fun SectionTitle(text: String) {
@Composable
private fun CalDavSourceRow(source: Source, onDelete: () -> Unit) {
val connectionFailed = source.caldavData?.calendarHomeUrl == null
ListItem(
leadingContent = { Icon(Icons.Outlined.AccountCircle, contentDescription = null) },
leadingContent = {
if (connectionFailed) {
Icon(Icons.Outlined.Warning, contentDescription = "Connexion échouée", tint = MaterialTheme.colorScheme.error)
} else {
Icon(Icons.Outlined.AccountCircle, contentDescription = null)
}
},
headlineContent = { Text(source.displayName) },
supportingContent = { Text(source.caldavData?.serverUrl ?: "") },
supportingContent = {
Column {
Text(source.caldavData?.serverUrl ?: "")
if (connectionFailed) {
Text(
text = "Non connecté",
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.labelSmall,
)
}
}
},
trailingContent = {
IconButton(onClick = onDelete) {
Icon(Icons.Outlined.Delete, contentDescription = "Supprimer", tint = MaterialTheme.colorScheme.error)
@@ -11,6 +11,8 @@ import com.planify.mobile.data.preferences.AppPreferences
import com.planify.mobile.data.preferences.ThemeMode
import com.planify.mobile.data.sync.SyncScheduler
import com.planify.mobile.domain.model.Source
import com.planify.mobile.domain.model.SourceCalDavData
import com.planify.mobile.domain.model.SourceType
import com.planify.mobile.domain.repository.ProjectRepository
import com.planify.mobile.domain.repository.SourceRepository
import com.planify.mobile.domain.repository.TaskRepository
@@ -23,6 +25,9 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.UUID
import javax.inject.Inject
data class SettingsUiState(
@@ -98,6 +103,23 @@ class SettingsViewModel @Inject constructor(
if (uiState.value.syncEnabled) syncScheduler.schedule()
}
is DiscoveryResult.Failure -> {
// Save the account anyway so the user keeps their credentials
val now = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val sourceId = UUID.randomUUID().toString()
val fallback = Source(
id = sourceId,
type = SourceType.CALDAV,
displayName = username,
addedAt = now,
updatedAt = now,
caldavData = SourceCalDavData(
serverUrl = baseUrl,
username = username,
calendarHomeUrl = null,
),
)
credentialStore.savePassword(sourceId, password)
sourceRepository.insertSource(fallback)
_discoveryState.update { false to result.message }
}
}