Extract login and credentials verification logic into usecases
This commit is contained in:
parent
511a36516b
commit
fac5a55251
20 changed files with 149 additions and 73 deletions
|
@ -8,8 +8,8 @@ import androidx.navigation.compose.NavHost
|
|||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import ing.bikeshedengineer.debtpirate.presentation.theme.DebtPirateTheme
|
||||
import ing.bikeshedengineer.debtpirate.presentation.ui.auth.AuthScreen
|
||||
import ing.bikeshedengineer.debtpirate.theme.DebtPirateTheme
|
||||
import ing.bikeshedengineer.debtpirate.auth.presentation.AuthScreen
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
|
@ -26,9 +26,7 @@ class MainActivity : ComponentActivity() {
|
|||
|
||||
DebtPirateTheme {
|
||||
NavHost(navController = navController, startDestination = AuthRoute) {
|
||||
composable<AuthRoute> {
|
||||
AuthScreen()
|
||||
}
|
||||
composable<AuthRoute>() { AuthScreen() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package ing.bikeshedengineer.debtpirate.data.remote.endpoint
|
||||
package ing.bikeshedengineer.debtpirate.auth.data.remote.endpoint
|
||||
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.ApiResponse
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.auth.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.auth.AuthLoginResponse
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.ApiResponse
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginResponse
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
|
@ -1,3 +1,3 @@
|
|||
package ing.bikeshedengineer.debtpirate.data.remote.model.auth
|
||||
package ing.bikeshedengineer.debtpirate.auth.data.remote.model
|
||||
|
||||
data class AuthLoginRequest(val username: String, val password: String)
|
|
@ -1,4 +1,4 @@
|
|||
package ing.bikeshedengineer.debtpirate.data.remote.model.auth
|
||||
package ing.bikeshedengineer.debtpirate.auth.data.remote.model
|
||||
|
||||
data class AuthLoginResponse(
|
||||
val userId: Int,
|
|
@ -0,0 +1,8 @@
|
|||
package ing.bikeshedengineer.debtpirate.auth.data.remote.repository
|
||||
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginResponse
|
||||
|
||||
interface AuthRepository {
|
||||
suspend fun submitLoginRequest(credentials: AuthLoginRequest): AuthLoginResponse
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package ing.bikeshedengineer.debtpirate.auth.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.repository.AuthRepository
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.repository.AuthRepositoryImpl
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.SubmitLoginCredentialsUseCase
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.ValidateLoginCredentialsUseCase
|
||||
import retrofit2.Retrofit
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object AuthDiModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAuthRepository(httpClient: Retrofit): AuthRepository {
|
||||
return AuthRepositoryImpl(httpClient)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSubmitLoginCredentialsUseCase(authRepository: AuthRepository): SubmitLoginCredentialsUseCase {
|
||||
return SubmitLoginCredentialsUseCase(authRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideValidateLoginCredentialsUseCase() = ValidateLoginCredentialsUseCase()
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package ing.bikeshedengineer.debtpirate.domain.repository
|
||||
package ing.bikeshedengineer.debtpirate.auth.domain.repository
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.endpoint.AuthEndpoint
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.ApiResponse
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.auth.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.auth.AuthLoginResponse
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.repository.AuthRepository
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.endpoint.AuthEndpoint
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.ApiResponse
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginResponse
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.repository.AuthRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import retrofit2.Retrofit
|
|
@ -0,0 +1,24 @@
|
|||
package ing.bikeshedengineer.debtpirate.auth.domain.usecase
|
||||
|
||||
import android.util.Log
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginResponse
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.repository.AuthRepository
|
||||
|
||||
class SubmitLoginCredentialsUseCase(
|
||||
private val authRepository: AuthRepository
|
||||
) {
|
||||
suspend operator fun invoke(username: String, password: String): AuthLoginResponse {
|
||||
val credentials = AuthLoginRequest(username, password)
|
||||
|
||||
try {
|
||||
val response = authRepository.submitLoginRequest(credentials)
|
||||
Log.d("AuthScreen", "Login successful! $response")
|
||||
return response
|
||||
} catch (err: Throwable) {
|
||||
// TODO...
|
||||
Log.e("AuthScreen", err.message!!)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package ing.bikeshedengineer.debtpirate.auth.domain.usecase
|
||||
|
||||
import android.util.Log
|
||||
|
||||
sealed class LoginCredentialsValidationResult {
|
||||
object EmptyCredentials : LoginCredentialsValidationResult()
|
||||
object EmptyUsernameField : LoginCredentialsValidationResult()
|
||||
object EmptyPasswordField : LoginCredentialsValidationResult()
|
||||
object ValidCredentials : LoginCredentialsValidationResult()
|
||||
}
|
||||
|
||||
class ValidateLoginCredentialsUseCase {
|
||||
operator fun invoke(username: String, password: String): LoginCredentialsValidationResult {
|
||||
return if (username.isEmpty() && password.isEmpty()) {
|
||||
LoginCredentialsValidationResult.EmptyCredentials;
|
||||
} else if (username.isEmpty() && password.isNotEmpty()) {
|
||||
LoginCredentialsValidationResult.EmptyUsernameField;
|
||||
} else if (username.isNotEmpty() && password.isEmpty()) {
|
||||
LoginCredentialsValidationResult.EmptyPasswordField
|
||||
} else {
|
||||
LoginCredentialsValidationResult.ValidCredentials
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package ing.bikeshedengineer.debtpirate.presentation.ui.auth
|
||||
package ing.bikeshedengineer.debtpirate.auth.presentation
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.foundation.background
|
|
@ -1,4 +1,4 @@
|
|||
package ing.bikeshedengineer.debtpirate.presentation.ui.auth
|
||||
package ing.bikeshedengineer.debtpirate.auth.presentation
|
||||
|
||||
import android.util.Log
|
||||
import androidx.datastore.core.DataStore
|
||||
|
@ -6,24 +6,41 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import ing.bikeshedengineer.debtpirate.PrefsDataStore
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.auth.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.repository.AuthRepository
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.repository.AuthRepository
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.LoginCredentialsValidationResult
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.SubmitLoginCredentialsUseCase
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.ValidateLoginCredentialsUseCase
|
||||
import ing.bikeshedengineer.debtpirate.domain.model.Token
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
enum class InvalidField {
|
||||
Username,
|
||||
Password
|
||||
}
|
||||
|
||||
sealed class FormState {
|
||||
class Pristine : FormState()
|
||||
class Valid : FormState()
|
||||
class Invalid(reason: InvalidReason) : FormState()
|
||||
}
|
||||
|
||||
enum class InvalidReason {
|
||||
MissingUsernameValue,
|
||||
MissingPasswordValue,
|
||||
PasswordTooShort
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
class AuthScreenViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
private val prefsStore: DataStore<PrefsDataStore>
|
||||
private val prefsStore: DataStore<PrefsDataStore>,
|
||||
private val submitLoginCredentials: SubmitLoginCredentialsUseCase,
|
||||
private val validateLoginCredentials: ValidateLoginCredentialsUseCase,
|
||||
) : ViewModel() {
|
||||
private val tag: String
|
||||
get() {
|
||||
return javaClass.simpleName
|
||||
}
|
||||
|
||||
// private val storeLoginData = StoreLoginDataUseCase(dataStore)
|
||||
|
||||
private val _username = MutableStateFlow("")
|
||||
|
@ -41,16 +58,21 @@ class AuthScreenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun submitLoginRequest() {
|
||||
val credentials = AuthLoginRequest(this._username.value, this._password.value)
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val response = authRepository.submitLoginRequest(credentials)
|
||||
Log.i(tag, "Login successful! $response")
|
||||
} catch (err: Throwable) {
|
||||
when (validateLoginCredentials(username.value, password.value)) {
|
||||
is LoginCredentialsValidationResult.ValidCredentials -> {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val result = submitLoginCredentials(username.value, password.value)
|
||||
} catch (err: Throwable) {
|
||||
// TODO...
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// TODO...
|
||||
Log.e(tag, err.message!!)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun storeAuthData(userId: Int, sessionToken: Token, authToken: Token) {
|
|
@ -1,3 +1,3 @@
|
|||
package ing.bikeshedengineer.debtpirate.data.remote.model
|
||||
package ing.bikeshedengineer.debtpirate.data.remote
|
||||
|
||||
data class ApiResponse<T>(val data: T?, val error: String?)
|
|
@ -1,4 +0,0 @@
|
|||
package ing.bikeshedengineer.debtpirate.data.remote.client
|
||||
|
||||
class AuthEndpointClient {
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package ing.bikeshedengineer.debtpirate.data.remote.repository
|
||||
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.auth.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.model.auth.AuthLoginResponse
|
||||
|
||||
interface AuthRepository {
|
||||
suspend fun submitLoginRequest(credentials: AuthLoginRequest): AuthLoginResponse
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package ing.bikeshedengineer.debtpirate.di.modules
|
||||
package ing.bikeshedengineer.debtpirate.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
|
@ -1,4 +1,4 @@
|
|||
package ing.bikeshedengineer.debtpirate.di.modules
|
||||
package ing.bikeshedengineer.debtpirate.di
|
||||
|
||||
import android.app.Application
|
||||
import androidx.datastore.core.DataStore
|
|
@ -1,21 +0,0 @@
|
|||
package ing.bikeshedengineer.debtpirate.di.modules
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.repository.AuthRepository
|
||||
import ing.bikeshedengineer.debtpirate.domain.repository.AuthRepositoryImpl
|
||||
import retrofit2.Retrofit
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object AuthRepositoryModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAuthRepository(httpClient: Retrofit): AuthRepository {
|
||||
return AuthRepositoryImpl(httpClient)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package ing.bikeshedengineer.debtpirate.presentation.theme
|
||||
package ing.bikeshedengineer.debtpirate.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package ing.bikeshedengineer.debtpirate.presentation.theme
|
||||
package ing.bikeshedengineer.debtpirate.theme
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
@ -1,4 +1,4 @@
|
|||
package ing.bikeshedengineer.debtpirate.presentation.theme
|
||||
package ing.bikeshedengineer.debtpirate.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
Loading…
Add table
Reference in a new issue