diff --git a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/api/AccountDataSource.kt b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/api/AccountDataSource.kt index dd97dd4..de077c5 100644 --- a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/api/AccountDataSource.kt +++ b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/api/AccountDataSource.kt @@ -9,6 +9,7 @@ interface AccountDataSource { fun saveAccessToken(accessToken: String) fun getAccessToken(): String? + fun deleteAccessToken() fun saveAccount(account: Account) fun getAccount(): Account? @@ -19,6 +20,8 @@ interface AccountDataSource { suspend fun createSessionId(username: String, password: String): Outcome + suspend fun deleteSessionId(sessionId: String): Outcome + suspend fun getAccountDetails(sessionToken: String): Outcome } diff --git a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/local/AccountLocalDataSource.kt b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/local/AccountLocalDataSource.kt index 9e42640..ff0d1f5 100644 --- a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/local/AccountLocalDataSource.kt +++ b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/local/AccountLocalDataSource.kt @@ -24,6 +24,11 @@ class AccountLocalDataSource @Inject constructor( return sharedPreferences.getString("access_token", null) } + override fun deleteAccessToken() { + val sharedPreferences = context.getSharedPreferences("Account", Context.MODE_PRIVATE) + sharedPreferences.edit().remove("access_token").apply() + } + override fun saveAccount(account: Account) { val sharedPreferences = context.getSharedPreferences("Account", Context.MODE_PRIVATE) sharedPreferences.edit().putString("account_name", account.name).apply() diff --git a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountRemoteDataSource.kt b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountRemoteDataSource.kt index 128ec43..bfc63fd 100644 --- a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountRemoteDataSource.kt +++ b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountRemoteDataSource.kt @@ -42,6 +42,12 @@ class AccountRemoteDataSource @Inject constructor( } } + override suspend fun deleteSessionId(sessionId: String): Outcome { + return runCatchingApi { + accountService.deleteSession(createDeleteSessionRequestBody(sessionId)) + }.map { it.success } + } + override suspend fun getAccountDetails(sessionToken: String): Outcome { return runCatchingApi { accountService.getAccountDetails(sessionToken) @@ -67,3 +73,12 @@ private fun createValidateRequestTokenWithLoginRequestBody( } return body.toString().toRequestBody("application/json; charset=UTF-8".toMediaType()) } + +private fun createDeleteSessionRequestBody( + sessionId: String, +): RequestBody { + val body = buildJsonObject { + put("session_id", sessionId) + } + return body.toString().toRequestBody("application/json; charset=UTF-8".toMediaType()) +} diff --git a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountService.kt b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountService.kt index 9cb98c8..3dee892 100644 --- a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountService.kt +++ b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountService.kt @@ -3,15 +3,18 @@ package com.zsoltbertalan.flickslate.account.data.network import com.zsoltbertalan.flickslate.account.data.network.model.AccountDetailsReplyDto import com.zsoltbertalan.flickslate.account.data.network.model.CreateRequestTokenReplyDto import com.zsoltbertalan.flickslate.account.data.network.model.CreateSessionReplyDto +import com.zsoltbertalan.flickslate.account.data.network.model.DeleteSessionReplyDto import okhttp3.RequestBody import retrofit2.http.Body import retrofit2.http.GET +import retrofit2.http.HTTP import retrofit2.http.POST import retrofit2.http.Query const val URL_CREATE_REQUEST_TOKEN = "authentication/token/new" const val URL_VALIDATE_REQUEST_TOKEN_WITH_LOGIN = "authentication/token/validate_with_login" const val URL_CREATE_SESSION = "authentication/session/new" +const val URL_DELETE_SESSION = "authentication/session" const val URL_GET_ACCOUNT_DETAILS = "account" /** @@ -39,6 +42,11 @@ interface AccountService { @Query("request_token") requestToken: String, ): CreateSessionReplyDto + @HTTP(method = "DELETE", path = URL_DELETE_SESSION, hasBody = true) + suspend fun deleteSession( + @Body requestBody: RequestBody + ): DeleteSessionReplyDto + @GET(URL_GET_ACCOUNT_DETAILS) suspend fun getAccountDetails( @Query("session_id") sessionToken: String, diff --git a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/model/DeleteSessionReplyDto.kt b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/model/DeleteSessionReplyDto.kt new file mode 100644 index 0000000..e17408e --- /dev/null +++ b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/model/DeleteSessionReplyDto.kt @@ -0,0 +1,7 @@ +package com.zsoltbertalan.flickslate.account.data.network.model + +import kotlinx.serialization.Serializable + +@Suppress("ConstructorParameterNaming") +@Serializable +data class DeleteSessionReplyDto(val success: Boolean) diff --git a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/repository/AccountAccessor.kt b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/repository/AccountAccessor.kt index 7bdc103..64ca899 100644 --- a/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/repository/AccountAccessor.kt +++ b/account/account-data/src/main/java/com/zsoltbertalan/flickslate/account/data/repository/AccountAccessor.kt @@ -23,13 +23,18 @@ class AccountAccessor @Inject constructor( override suspend fun login(username: String, password: String): Outcome { return accountRemoteDataSource.createSessionId(username, password) .andThen { + accountLocalDataSource.saveAccessToken(it) val account = accountRemoteDataSource.getAccountDetails(it) accountLocalDataSource.saveAccount(account.value) account } } - override fun logout() { - // Do nothing + override suspend fun logout() { + val accessToken = accountLocalDataSource.getAccessToken() + if (accessToken != null) { + val success = accountRemoteDataSource.deleteSessionId(accessToken) + if(success.isOk) accountLocalDataSource.getAccessToken() + } } } diff --git a/account/account-domain/src/main/java/com/zsoltbertalan/flickslate/account/domain/api/AccountRepository.kt b/account/account-domain/src/main/java/com/zsoltbertalan/flickslate/account/domain/api/AccountRepository.kt index 3bd51bb..8eb2296 100644 --- a/account/account-domain/src/main/java/com/zsoltbertalan/flickslate/account/domain/api/AccountRepository.kt +++ b/account/account-domain/src/main/java/com/zsoltbertalan/flickslate/account/domain/api/AccountRepository.kt @@ -7,6 +7,6 @@ interface AccountRepository { suspend fun getAccount(): Account? suspend fun login(username: String, password: String): Outcome - fun logout() + suspend fun logout() } diff --git a/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/AccountScreen.kt b/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/AccountScreen.kt index 6cca6a0..1f4a8a2 100644 --- a/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/AccountScreen.kt +++ b/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/AccountScreen.kt @@ -9,10 +9,11 @@ import com.zsoltbertalan.flickslate.shared.model.Account fun AccountScreen( account: Account?, login: (String, String) -> Unit, + logout: () -> Unit, modifier: Modifier = Modifier, ) { if (account != null) { - LoggedInComponent(Colors, account, modifier) + LoggedInComponent(Colors, account, modifier, logout) } else { LoginComponent(Colors, modifier, login) } diff --git a/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/AccountViewModel.kt b/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/AccountViewModel.kt index 5842985..a2f68af 100644 --- a/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/AccountViewModel.kt +++ b/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/AccountViewModel.kt @@ -33,4 +33,12 @@ class AccountViewModel @Inject constructor(private val accountRepository: Accoun } } } + + fun logout() { + viewModelScope.launch { + accountRepository.logout() + _loggedInEvent.emit(null) + } + } + } diff --git a/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/LoggedInComponent.kt b/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/LoggedInComponent.kt index 19f05bb..6ecfcf0 100644 --- a/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/LoggedInComponent.kt +++ b/account/account-ui/src/main/java/com/zsoltbertalan/flickslate/account/ui/main/LoggedInComponent.kt @@ -4,14 +4,12 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button import androidx.compose.material3.ColorScheme -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -19,14 +17,14 @@ import com.zsoltbertalan.flickslate.shared.compose.component.ListTitle import com.zsoltbertalan.flickslate.shared.compose.component.autosizetext.AutoSizeText import com.zsoltbertalan.flickslate.shared.compose.design.Colors import com.zsoltbertalan.flickslate.shared.compose.design.FlickSlateTheme -import com.zsoltbertalan.flickslate.shared.compose.design.FlickSlateTypography import com.zsoltbertalan.flickslate.shared.model.Account @Composable fun LoggedInComponent( colorScheme: ColorScheme, account: Account, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + logout: () -> Unit ) { Column( modifier = modifier @@ -42,17 +40,22 @@ fun LoggedInComponent( alignment = Alignment.Center, maxLines = 1, ) + + Button(logout) { + Text("Logout") + } } } -@Preview() +@Preview @Composable private fun PreviewAutoSizeTextWithMaxLinesSetToOne() { FlickSlateTheme { LoggedInComponent( modifier = Modifier.fillMaxSize(), colorScheme = Colors, - account = Account(name="John Doe"), + account = Account(name = "John Doe"), + logout = {}, ) } } diff --git a/app/src/main/java/com/zsoltbertalan/flickslate/main/navigation/NavHostContainer.kt b/app/src/main/java/com/zsoltbertalan/flickslate/main/navigation/NavHostContainer.kt index 72bfff9..587b497 100644 --- a/app/src/main/java/com/zsoltbertalan/flickslate/main/navigation/NavHostContainer.kt +++ b/app/src/main/java/com/zsoltbertalan/flickslate/main/navigation/NavHostContainer.kt @@ -98,7 +98,8 @@ fun NavHostContainer( val account by accountViewModel.loggedInEvent.collectAsStateWithLifecycle(null) AccountScreen( account = account, - login = { username, password -> accountViewModel.login(username, password) } + login = { username, password -> accountViewModel.login(username, password) }, + logout = { accountViewModel.logout() } ) } composable(