feat: sauvegarde du compte CalDAV même si la connexion échoue, avec indicateur visuel
This commit is contained in:
@@ -15,6 +15,7 @@ import androidx.compose.material.icons.outlined.Add
|
|||||||
import androidx.compose.material.icons.outlined.Delete
|
import androidx.compose.material.icons.outlined.Delete
|
||||||
import androidx.compose.material.icons.outlined.Download
|
import androidx.compose.material.icons.outlined.Download
|
||||||
import androidx.compose.material.icons.outlined.Sync
|
import androidx.compose.material.icons.outlined.Sync
|
||||||
|
import androidx.compose.material.icons.outlined.Warning
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
@@ -23,6 +24,7 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.SegmentedButton
|
import androidx.compose.material3.SegmentedButton
|
||||||
@@ -185,9 +187,10 @@ fun SettingsScreen(
|
|||||||
}
|
}
|
||||||
discovery.second?.let { error ->
|
discovery.second?.let { error ->
|
||||||
Text(
|
Text(
|
||||||
text = error,
|
text = "Connexion échouée — le compte a été ajouté sans synchronisation : $error",
|
||||||
color = MaterialTheme.colorScheme.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
|
@Composable
|
||||||
private fun CalDavSourceRow(source: Source, onDelete: () -> Unit) {
|
private fun CalDavSourceRow(source: Source, onDelete: () -> Unit) {
|
||||||
|
val connectionFailed = source.caldavData?.calendarHomeUrl == null
|
||||||
ListItem(
|
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) },
|
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 = {
|
trailingContent = {
|
||||||
IconButton(onClick = onDelete) {
|
IconButton(onClick = onDelete) {
|
||||||
Icon(Icons.Outlined.Delete, contentDescription = "Supprimer", tint = MaterialTheme.colorScheme.error)
|
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.preferences.ThemeMode
|
||||||
import com.planify.mobile.data.sync.SyncScheduler
|
import com.planify.mobile.data.sync.SyncScheduler
|
||||||
import com.planify.mobile.domain.model.Source
|
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.ProjectRepository
|
||||||
import com.planify.mobile.domain.repository.SourceRepository
|
import com.planify.mobile.domain.repository.SourceRepository
|
||||||
import com.planify.mobile.domain.repository.TaskRepository
|
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.stateIn
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
data class SettingsUiState(
|
data class SettingsUiState(
|
||||||
@@ -98,6 +103,23 @@ class SettingsViewModel @Inject constructor(
|
|||||||
if (uiState.value.syncEnabled) syncScheduler.schedule()
|
if (uiState.value.syncEnabled) syncScheduler.schedule()
|
||||||
}
|
}
|
||||||
is DiscoveryResult.Failure -> {
|
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 }
|
_discoveryState.update { false to result.message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user