diff --git a/app/src/main/kotlin/com/subtracks/data/db/SourcesDao.kt b/app/src/main/kotlin/com/subtracks/data/db/SourcesDao.kt index 845e852e..2e8edc86 100644 --- a/app/src/main/kotlin/com/subtracks/data/db/SourcesDao.kt +++ b/app/src/main/kotlin/com/subtracks/data/db/SourcesDao.kt @@ -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 @@ -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 diff --git a/app/src/main/kotlin/com/subtracks/data/repo/SourceRepository.kt b/app/src/main/kotlin/com/subtracks/data/repo/SourceRepository.kt index 1009d6a2..c526ceb3 100644 --- a/app/src/main/kotlin/com/subtracks/data/repo/SourceRepository.kt +++ b/app/src/main/kotlin/com/subtracks/data/repo/SourceRepository.kt @@ -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 } diff --git a/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt b/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt index 4d862261..e58cecd3 100644 --- a/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt @@ -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, ) diff --git a/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceViewModel.kt b/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceViewModel.kt index 9ef35d68..85d08511 100644 --- a/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceViewModel.kt +++ b/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceViewModel.kt @@ -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 } diff --git a/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt b/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt index 2ffe7349..5682d2ed 100644 --- a/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt @@ -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), ) } diff --git a/app/src/test/kotlin/com/subtracks/data/repo/SourceRepositoryTest.kt b/app/src/test/kotlin/com/subtracks/data/repo/SourceRepositoryTest.kt index b7165d4e..3d7e71b6 100644 --- a/app/src/test/kotlin/com/subtracks/data/repo/SourceRepositoryTest.kt +++ b/app/src/test/kotlin/com/subtracks/data/repo/SourceRepositoryTest.kt @@ -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