mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
select a server on tap and refuse to delete the active one
This commit is contained in:
@@ -20,9 +20,6 @@ interface SourcesDao {
|
||||
@Query("SELECT * FROM sources WHERE id = :id")
|
||||
suspend fun sourceOnce(id: Long): Source?
|
||||
|
||||
@Query("SELECT COUNT(*) FROM sources")
|
||||
suspend fun sourceCount(): Int
|
||||
|
||||
@Query("SELECT id FROM sources WHERE isActive = 1 LIMIT 1")
|
||||
fun activeSourceId(): Flow<Long?>
|
||||
|
||||
@@ -32,9 +29,6 @@ interface SourcesDao {
|
||||
@Query("SELECT id FROM sources WHERE isActive = 1 LIMIT 1")
|
||||
suspend fun activeSourceIdOnce(): Long?
|
||||
|
||||
@Query("SELECT id FROM sources ORDER BY createdAt LIMIT 1")
|
||||
suspend fun firstSourceId(): Long?
|
||||
|
||||
@Insert
|
||||
suspend fun insertSource(source: Source): Long
|
||||
|
||||
|
||||
@@ -175,13 +175,8 @@ class SourceRepository(
|
||||
}
|
||||
|
||||
suspend fun deleteSource(id: Long): Boolean {
|
||||
val dao = db.sourcesDao()
|
||||
if (dao.sourceCount() <= 1) return false
|
||||
val wasActive = dao.activeSourceIdOnce() == id
|
||||
dao.deleteSource(id)
|
||||
if (wasActive) {
|
||||
dao.firstSourceId()?.let { dao.setActiveSource(it) }
|
||||
}
|
||||
if (db.sourcesDao().activeSourceIdOnce() == id) return false
|
||||
db.sourcesDao().deleteSource(id)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ fun AddSourceScreen(
|
||||
)
|
||||
if (state.isEditing && !state.canDelete) {
|
||||
Text(
|
||||
"This is the only server. Add another before you can remove this one.",
|
||||
"This is the active server. Switch to another server before deleting it.",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
||||
@@ -59,7 +59,8 @@ class AddSourceViewModel(
|
||||
}
|
||||
viewModelScope.launch {
|
||||
sourceRepository.sources().collect { sources ->
|
||||
_state.update { it.copy(canDelete = sources.size > 1) }
|
||||
val active = sources.any { it.id == sourceId && it.isActive }
|
||||
_state.update { it.copy(canDelete = !active) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,7 +146,7 @@ class AddSourceViewModel(
|
||||
viewModelScope.launch {
|
||||
if (!sourceRepository.deleteSource(id)) {
|
||||
_state.update {
|
||||
it.copy(busy = false, message = "At least one server is required", isError = true)
|
||||
it.copy(busy = false, message = "The active server can't be deleted; switch to another server first", isError = true)
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.rounded.Add
|
||||
import androidx.compose.material.icons.rounded.Edit
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@@ -140,9 +140,11 @@ fun SettingsScreen(
|
||||
)
|
||||
},
|
||||
trailingContent = {
|
||||
Icon(Icons.AutoMirrored.Rounded.KeyboardArrowRight, contentDescription = null)
|
||||
IconButton(onClick = { onEditServer(source.id) }) {
|
||||
Icon(Icons.Rounded.Edit, contentDescription = "Edit ${source.name}")
|
||||
}
|
||||
},
|
||||
modifier = Modifier.clickable(onClickLabel = "Edit ${source.name}") { onEditServer(source.id) },
|
||||
modifier = Modifier.clickable(onClickLabel = "Use ${source.name}") { onSelectSource(source.id) },
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -105,19 +105,21 @@ class SourceRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theLastSourceCannotBeDeleted() =
|
||||
fun theActiveSourceCannotBeDeleted() =
|
||||
runTest {
|
||||
repository.addSource("only", "http://a.example", "u", "p", true)
|
||||
val id = repository.activeSourceId().first()!!
|
||||
|
||||
assertFalse("the last source must survive deletion", repository.deleteSource(id))
|
||||
assertEquals(1, repository.sources().first().size)
|
||||
|
||||
repository.addSource("first", "http://a.example", "u", "p", true)
|
||||
val firstId = repository.activeSourceId().first()!!
|
||||
repository.addSource("second", "http://b.example", "u", "p", true)
|
||||
val secondId = repository.activeSourceId().first()!!
|
||||
|
||||
assertTrue(repository.deleteSource(id))
|
||||
assertEquals(listOf("second"), repository.sources().first().map { it.name })
|
||||
assertEquals("second", repository.activeConfig().first()?.name)
|
||||
assertFalse("the active source must survive deletion", repository.deleteSource(secondId))
|
||||
assertEquals(2, repository.sources().first().size)
|
||||
|
||||
repository.selectSource(firstId)
|
||||
|
||||
assertTrue(repository.deleteSource(secondId))
|
||||
assertEquals(listOf("first"), repository.sources().first().map { it.name })
|
||||
assertEquals("first", repository.activeConfig().first()?.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user