feat(auth): show delete-local-data dialog on logout for logged-in users

This commit is contained in:
Jens Reinemann 2026-05-19 00:10:17 +02:00
parent 320f0e8880
commit 557a4bcaf8
4 changed files with 47 additions and 4 deletions

View file

@ -324,13 +324,33 @@ internal fun SettingsScreen(
)
Spacer(modifier = Modifier.height(8.dp))
OutlinedButton(
onClick = viewModel::logout,
onClick = viewModel::onLogoutClicked,
modifier = Modifier.fillMaxWidth()
) {
Text("Abmelden")
}
}
}
if (uiState.showLogoutDialog) {
AlertDialog(
onDismissRequest = viewModel::onLogoutDialogDismissed,
title = { Text("Lokale Daten löschen?") },
text = {
Text("Möchtest du alle lokal gespeicherten Daten (Inventar, Nachrichten, …) von diesem Gerät entfernen?")
},
confirmButton = {
TextButton(onClick = { viewModel.logout(deleteLocalData = true) }) {
Text("Löschen")
}
},
dismissButton = {
TextButton(onClick = { viewModel.logout(deleteLocalData = false) }) {
Text("Behalten")
}
}
)
}
} else {
OutlinedTextField(
value = uiState.loginUsername,

View file

@ -27,7 +27,8 @@ internal data class SettingsUiState(
val pendingQueueCount: Int = 0,
val isSyncing: Boolean = false,
val lastSyncTime: String? = null,
val openAiApiKey: String = ""
val openAiApiKey: String = "",
val showLogoutDialog: Boolean = false
)
internal sealed interface ImportResult {

View file

@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import de.bollwerk.app.data.db.BollwerkDatabase
import de.bollwerk.app.data.db.dao.PendingSyncOpDao
import de.bollwerk.app.data.sync.ConnectionState
import de.bollwerk.app.data.sync.WebSocketClient
@ -22,6 +23,7 @@ import de.bollwerk.app.domain.repository.ImportExportRepository
import de.bollwerk.app.domain.repository.SettingsRepository
import de.bollwerk.app.domain.repository.SyncService
import de.bollwerk.app.notification.MessagingService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
@ -29,6 +31,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.time.Instant
import java.time.ZoneId
@ -43,6 +46,7 @@ internal class SettingsViewModel @Inject constructor(
private val syncService: SyncService,
private val webSocketClient: WebSocketClient,
private val pendingSyncOpDao: PendingSyncOpDao,
private val database: BollwerkDatabase,
@ApplicationContext private val context: Context
) : ViewModel() {
@ -227,8 +231,21 @@ internal class SettingsViewModel @Inject constructor(
}
}
fun logout() {
fun onLogoutClicked() {
_uiState.update { it.copy(showLogoutDialog = true) }
}
fun onLogoutDialogDismissed() {
_uiState.update { it.copy(showLogoutDialog = false) }
}
fun logout(deleteLocalData: Boolean = false) {
viewModelScope.launch {
if (deleteLocalData) {
withContext(Dispatchers.IO) {
database.clearAllTables()
}
}
syncService.logout()
webSocketClient.disconnect()
MessagingService.stop(context)
@ -237,7 +254,8 @@ internal class SettingsViewModel @Inject constructor(
isLoggedIn = false,
loggedInUsername = "",
connectionState = ConnectionState.NotConfigured,
syncActivity = null
syncActivity = null,
showLogoutDialog = false
)
}
}

View file

@ -4,6 +4,7 @@ import android.content.Context
import androidx.core.content.FileProvider
import android.content.ContentResolver
import android.net.Uri
import de.bollwerk.app.data.db.BollwerkDatabase
import de.bollwerk.app.data.db.dao.PendingSyncOpDao
import de.bollwerk.app.data.db.entity.PendingSyncOpEntity
import de.bollwerk.app.data.sync.WebSocketClient
@ -53,6 +54,7 @@ class SettingsViewModelTest {
private lateinit var fakeSyncService: FakeSyncService
private lateinit var fakeWebSocketClient: FakeWebSocketClient
private lateinit var fakePendingSyncOpDao: FakePendingSyncOpDao
private lateinit var mockDatabase: BollwerkDatabase
private lateinit var mockContext: Context
private lateinit var tempDir: File
private lateinit var viewModel: SettingsViewModel
@ -65,6 +67,7 @@ class SettingsViewModelTest {
fakeSyncService = FakeSyncService()
fakeWebSocketClient = FakeWebSocketClient()
fakePendingSyncOpDao = FakePendingSyncOpDao()
mockDatabase = mockk(relaxed = true)
tempDir = File(System.getProperty("java.io.tmpdir"), "test_exports")
tempDir.mkdirs()
mockContext = mockk(relaxed = true) {
@ -85,6 +88,7 @@ class SettingsViewModelTest {
syncService = fakeSyncService,
webSocketClient = fakeWebSocketClient,
pendingSyncOpDao = fakePendingSyncOpDao,
database = mockDatabase,
context = mockContext
)