Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ fun App() {
onNavigateBack = { navController.popBackStack() },
onNavigateToNotificationOptions = { navController.navigate(Route.NotificationOptions) },
onNavigateToCodeOptions = { navController.navigate(Route.CodeOptions) },
onNavigateToAddPat = { navController.navigate(Route.AddPat) }
onNavigateToAddPat = { navController.navigate(Route.AddPat) },
onSignOut = {
navController.navigate(Route.AddPat) {
popUpTo(Route.Settings) { inclusive = true }
}
Comment on lines +64 to +66
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current sign-out logic only pops up to Route.Settings, which leaves other authenticated screens (like Main and Profile) in the backstack. This contradicts the PR description's goal of clearing the application backstack and poses a security risk as users could navigate back to private data after signing out.

You should pop up to the root of the authenticated flow (typically Route.Main) with inclusive = true to ensure the backstack is properly cleared before navigating to the sign-in screen.

Suggested change
navController.navigate(Route.AddPat) {
popUpTo(Route.Settings) { inclusive = true }
}
navController.navigate(Route.AddPat) {
popUpTo(Route.Main) { inclusive = true }
}

}
)
}
composable<Route.NotificationOptions> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fun SettingsScreen(
onNavigateToNotificationOptions: () -> Unit,
onNavigateToCodeOptions: () -> Unit,
onNavigateToAddPat: () -> Unit,
onSignOut: () -> Unit,
viewModel: SettingsViewModel = viewModel { SettingsViewModel() }
) {
val uiState by viewModel.uiState.collectAsState()
Expand All @@ -37,6 +38,12 @@ fun SettingsScreen(
if (lifecycleState == Lifecycle.State.RESUMED) viewModel.refresh()
}

LaunchedEffect(Unit) {
viewModel.signOutEvent.collect {
onSignOut()
}
}

if (showAccountsSheet) {
AccountsSheet(
accounts = uiState.accounts,
Expand Down Expand Up @@ -128,7 +135,7 @@ fun SettingsScreen(
SettingsRow(
title = stringResource(Res.string.settings_sign_out),
titleColor = MaterialTheme.colorScheme.error,
onClick = { /* TODO */ }
onClick = { viewModel.signOut() }
)
SectionDivider()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.therealashik.github.data.GitHubApiClient
import dev.therealashik.github.data.createTokenStorage
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

Expand All @@ -16,6 +19,9 @@ class SettingsViewModel : ViewModel() {
private val _uiState = MutableStateFlow(SettingsUiState())
val uiState: StateFlow<SettingsUiState> = _uiState.asStateFlow()

private val _signOutEvent = MutableSharedFlow<Unit>()
val signOutEvent: SharedFlow<Unit> = _signOutEvent.asSharedFlow()

init {
refresh()
}
Expand All @@ -37,6 +43,13 @@ class SettingsViewModel : ViewModel() {
}
}

fun signOut() {
viewModelScope.launch {
tokenStorage.clearToken()
_signOutEvent.emit(Unit)
}
}

override fun onCleared() {
super.onCleared()
apiClient.close()
Expand Down
Loading