Created
March 10, 2025 13:19
-
-
Save sajjadyousefnia/ad9ddf09ff14b1588ba14c748089fa8a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.divadventure.divadventure.domain | |
import com.divadventure.divadventure.SignupResultWrapper | |
import com.divadventure.divadventure.data.AuthRepository | |
import com.divadventure.divadventure.data.Model.SignUpResponse | |
import com.divadventure.divadventure.data.Model.SignupRequest | |
import kotlinx.coroutines.CoroutineScope | |
import kotlinx.coroutines.Dispatchers | |
import kotlinx.coroutines.flow.Flow | |
import kotlinx.coroutines.flow.flow | |
import kotlinx.coroutines.launch | |
import timber.log.Timber | |
import javax.inject.Inject | |
class AuthUseCases @Inject constructor( | |
// val signInUseCase: SignInUseCase, | |
val signUpUseCase: SignUpUseCase, | |
// val forgotPasswordUseCase: ForgotPasswordUseCase, | |
// val isLoggedInUseCase: IsLoggedInUseCase, | |
// val verifyEmailUseCase: VerifyEmailUseCase, | |
// val getCurrentUserUseCase: GetCurrentUserUseCase, | |
// val logoutUseCase: LogoutUseCase | |
) | |
/* | |
class SignInUseCase @Inject constructor(private val authRepository: AuthRepository) { | |
suspend operator fun invoke(email: String, password: String): ResultWrapper<User> { | |
// Validate email and password if needed | |
if (!isValidEmail(email)) { | |
return Result.Error(Exception("Invalid email format")) | |
} | |
if (password.length < 6) { | |
return Result.Error(Exception("Password must be at least 6 characters long")) | |
} | |
return try { | |
authRepository.signIn(email, password) | |
} catch (e: Exception) { | |
Result.Error(e) | |
} | |
} | |
private fun isValidEmail(email: String): Boolean { | |
// You can add a better email validation logic if needed | |
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches() | |
} | |
} | |
*/ | |
class SignUpUseCase @Inject constructor(private val authRepository: AuthRepository) { | |
suspend operator fun invoke(signupRequest: SignupRequest): Flow<SignupResultWrapper<SignUpResponse>> = | |
flow { | |
// Validate email and password if needed | |
emit(SignupResultWrapper.Loading) | |
if (!isValidEmail(signupRequest.email)) { | |
Timber.d("Invalid email format") | |
SignupResultWrapper.Error("Invalid email format") | |
return@flow | |
} | |
if (signupRequest.password.length < 8) { | |
Timber.d("Password must be at least 6 characters long") | |
emit(SignupResultWrapper.Error("Password must be at least 6 characters long")) | |
return@flow | |
} | |
if (signupRequest.password != signupRequest.password_confirmation) { | |
Timber.d("Passwords do not match") | |
emit(SignupResultWrapper.Error(("Passwords do not match"))) | |
return@flow | |
} | |
try { | |
CoroutineScope( | |
Dispatchers.IO | |
).launch { | |
CoroutineScope(Dispatchers.Main).launch { | |
val result: SignupResultWrapper<SignUpResponse> = | |
authRepository.signup(signupRequest) | |
when (result) { | |
is SignupResultWrapper.Error -> { | |
emit( | |
SignupResultWrapper.Error( | |
result.message | |
) | |
) | |
} | |
SignupResultWrapper.Loading -> { | |
emit( | |
SignupResultWrapper.Loading | |
) | |
} | |
is SignupResultWrapper.Success<*> -> { | |
emit( | |
SignupResultWrapper.Success( | |
result.data as SignUpResponse | |
) | |
) | |
} | |
} | |
} | |
} | |
// Emit Success state | |
// emit(ResultWrapper.Success(signupRequest)) | |
} catch (e: Exception) { | |
SignupResultWrapper.Error("failed to sign up") | |
} | |
} | |
private fun isValidEmail(email: String): Boolean { | |
// You can add a better email validation logic if needed | |
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches() | |
} | |
} | |
/* | |
class ForgotPasswordUseCase @Inject constructor(private val authRepository: AuthRepository) { | |
suspend operator fun invoke(email: String): Result<Unit> { | |
// Validate email if needed | |
if (!isValidEmail(email)) { | |
return Result.Error(Exception("Invalid email format")) | |
} | |
return try { | |
authRepository.forgotPassword(email) | |
Result.Success(Unit) | |
} catch (e: Exception) { | |
Result.Error(e) | |
} | |
} | |
private fun isValidEmail(email: String): Boolean { | |
// You can add a better email validation logic if needed | |
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches() | |
} | |
} | |
*/ | |
/* | |
class IsLoggedInUseCase @Inject constructor(private val authRepository: AuthRepository) { | |
suspend operator fun invoke(): Boolean { | |
// Check if the user is logged in | |
return authRepository.isLoggedIn() | |
} | |
}*/ | |
/*class VerifyEmailUseCase @Inject constructor(private val authRepository: AuthRepository) { | |
suspend operator fun invoke(): Result<Unit> { | |
// Verify the user email | |
return try { | |
authRepository.verifyEmail() | |
Result.Success(Unit) | |
} catch (e: Exception) { | |
Result.Error(e) | |
} | |
} | |
}*/ | |
/* | |
class GetCurrentUserUseCase @Inject constructor(private val authRepository: AuthRepository) { | |
suspend operator fun invoke(): Result<User?> { | |
// Get the user | |
return try { | |
val user = authRepository.getCurrentUser() | |
Result.Success(user) | |
} catch (e:*/ | |
// another file | |
package com.divadventure.divadventure.ViewModel | |
import androidx.lifecycle.viewModelScope | |
import com.divadventure.divadventure.BaseViewModel | |
import com.divadventure.divadventure.Intent.AuthIntent | |
import com.divadventure.divadventure.SignupResultWrapper | |
import com.divadventure.divadventure.State.AuthState | |
import com.divadventure.divadventure.data.AuthRepository | |
import com.divadventure.divadventure.data.Model.SignupRequest | |
import com.divadventure.divadventure.domain.AuthUseCases | |
import dagger.hilt.android.lifecycle.HiltViewModel | |
import kotlinx.coroutines.flow.collectLatest | |
import kotlinx.coroutines.launch | |
import timber.log.Timber | |
import javax.inject.Inject | |
@HiltViewModel | |
class AuthViewModel @Inject constructor( | |
private val authUseCases: AuthUseCases, private val authRepository: AuthRepository | |
) : BaseViewModel<AuthIntent, AuthState>(AuthState()) { | |
override suspend fun handleIntent(intent: AuthIntent) { | |
when (intent) { | |
is AuthIntent.SignUp -> { | |
updateState(state.value.copy(isLoadingSignUp = true)) | |
authUseCases.signUpUseCase( | |
SignupRequest( | |
email = intent.email, | |
password = intent.password, | |
password_confirmation = intent.password | |
) | |
).collectLatest { result -> | |
when (result) { | |
is SignupResultWrapper.Success -> { | |
viewModelScope.launch { | |
updateState( | |
state.value.copy( | |
isLoadingSignUp = false, | |
signupError = "", | |
isLogged = true | |
) | |
) | |
Timber.d("Signup successful: ${result.data}") | |
} | |
} | |
is SignupResultWrapper.Error -> { | |
viewModelScope.launch { | |
Timber.d("Error: ${result.message}") | |
updateState( | |
state.value.copy( | |
isLoadingSignUp = false, | |
isLogged = false, | |
signupError = result.message, | |
) | |
) | |
} | |
} | |
SignupResultWrapper.Loading -> { | |
viewModelScope.launch { | |
Timber.d("Loading...") | |
} | |
} | |
} | |
} | |
} | |
AuthIntent.CheckIfLoggedIn -> {} | |
AuthIntent.ClearError -> {} | |
AuthIntent.ClearNavigation -> {} | |
is AuthIntent.ForgotPassword -> {} | |
AuthIntent.GoToForgotPassword -> {} | |
AuthIntent.GoToLanding -> {} | |
AuthIntent.GoToSignIn -> {} | |
AuthIntent.GoToSignUp -> {} | |
AuthIntent.NavigateToEmailVerification -> {} | |
AuthIntent.NavigateToForgotPassword -> {} | |
AuthIntent.NavigateToLandingPage -> {} | |
AuthIntent.NavigateToMain -> {} | |
AuthIntent.NavigateToSignIn -> {} | |
AuthIntent.NavigateToSignUp -> {} | |
is AuthIntent.SignIn -> {} | |
AuthIntent.SignUpWithGoogle -> { | |
updateState( | |
state.value.copy( | |
isLogged = true | |
) | |
) | |
Timber.d("Signing up with Google...") | |
} | |
is AuthIntent.OnEmailChanged -> { | |
updateState( | |
state.value.copy( | |
email = intent.email | |
) | |
) | |
checkSignupCardColor() | |
} | |
is AuthIntent.OnPasswordChanged -> { | |
updateState( | |
state.value.copy( | |
password = intent.password | |
) | |
) | |
checkSignupCardColor() | |
} | |
is AuthIntent.OnPasswordConfirmationChanged -> { | |
updateState( | |
state.value.copy( | |
passwordConfirmation = intent.passwordConfirmation | |
) | |
) | |
checkSignupCardColor() | |
} | |
} | |
} | |
private fun checkSignupCardColor() { | |
val email = state.value.email | |
val password = state.value.password | |
val passwordConfirmation = state.value.passwordConfirmation | |
val isEmailNotEmpty = email.isNotEmpty() | |
val isPasswordNotEmpty = password.isNotEmpty() | |
val isEmailValid = isEmailValid(email) | |
val isPasswordAtLeast8Chars = isAtleast8Characters(password) | |
val doPasswordsMatch = | |
passwordsMatch(password = password, passwordConfirmation = passwordConfirmation) | |
val isValid = | |
isEmailNotEmpty && isPasswordNotEmpty && isEmailValid && isPasswordAtLeast8Chars && doPasswordsMatch | |
val issue = when { | |
!isEmailNotEmpty -> "Email can't be empty" | |
!isEmailValid -> "Email is not valid" | |
!isPasswordNotEmpty -> "Password can't be empty" | |
!isPasswordAtLeast8Chars -> "Password must have at least 8 characters" | |
!doPasswordsMatch -> "Passwords does not match" | |
else -> null | |
} | |
updateState( | |
state.value.copy( | |
rawDataAccepted = isValid, | |
formError = issue ?: "" | |
) | |
) | |
} | |
private fun passwordsMatch(password: String, passwordConfirmation: String): Boolean { | |
return password == passwordConfirmation | |
} | |
private fun isAtleast8Characters(password: String): Boolean { | |
return password.length >= 8 | |
} | |
private fun isEmailValid(email: String): Boolean { | |
val emailRegex = """^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$""".toRegex() | |
return emailRegex.matches(email) | |
} | |
} | |
// another file | |
package com.divadventure.divadventure.data | |
import com.divadventure.divadventure.SignupResultWrapper | |
import com.divadventure.divadventure.data.Model.SignUpResponse | |
import com.divadventure.divadventure.data.Model.SignupRequest | |
import com.google.gson.Gson | |
import com.google.gson.JsonParseException | |
import okio.IOException | |
import retrofit2.HttpException | |
import timber.log.Timber | |
import javax.inject.Inject | |
class AuthRepository @Inject constructor( | |
private val authService: AuthService | |
) { | |
suspend fun signup(request: SignupRequest): SignupResultWrapper<SignUpResponse> { | |
Timber.d("Starting signup request: $request") | |
return try { | |
val response = authService.signup(request).execute() | |
Timber.d("Signup response: $response") | |
if (response.isSuccessful) { | |
val authResponse = response.body() as SignUpResponse? | |
// Extract the authResponse from response.body() | |
Timber.d("Signup successful: $authResponse") | |
if (authResponse != null) { | |
SignupResultWrapper.Success(authResponse) | |
} else { | |
Timber.w("Response body is null") | |
SignupResultWrapper.Error("Response body is null") | |
} | |
} else { | |
val errorBody = response.errorBody()?.string() | |
val message = if (errorBody != null) { | |
try { | |
val errorJson = Gson().fromJson(errorBody, Map::class.java) | |
Timber.w("Signup failed with error body: $errorJson") | |
errorJson["message"].toString() // Extract the message field | |
} catch (e: JsonParseException) { | |
Timber.e(e, "Invalid error response") | |
"Invalid error response: ${e.message}" | |
} | |
} else { | |
Timber.w("Signup failed with code: ${response.code()}") | |
"Signup failed with code: ${response.code()}" | |
} | |
SignupResultWrapper.Error(message) | |
} | |
} catch (httpException: HttpException) { | |
Timber.e(httpException, "HTTP exception occurred") | |
// Handle HTTP exceptions (4xx or 5xx status codes) | |
val message = httpException.message() ?: "HTTP Error" | |
SignupResultWrapper.Error("HTTP error: $message") | |
} catch (ioException: IOException) { | |
Timber.e(ioException, "Network exception occurred") | |
// Handle network issues (e.g., no internet connection) | |
SignupResultWrapper.Error("Network error: ${ioException.message}") | |
} catch (jsonParseException: JsonParseException) { | |
Timber.e(jsonParseException, "JSON parsing exception occurred") | |
// Handle JSON parsing issues | |
SignupResultWrapper.Error("JSON parsing error: ${jsonParseException.message}") | |
} catch (e: Exception) { | |
Timber.e(e, "An unexpected exception occurred") | |
// Handle other unexpected exceptions | |
SignupResultWrapper.Error("An unexpected error occurred: ${e.message}") | |
} | |
} | |
// Add other repository methods here... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment