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 @@ -17,9 +17,6 @@ import kotlin.time.Instant
import kotlin.uuid.Uuid

interface ProjectionService {
@GET("projections/{id}")
suspend fun getProjection(@Path("id") id: Uuid): Response<Projection>

@GET("projections/date/{startDate}/{endDate}/cinema/{cinemaId}")
suspend fun getByProjectionDateBetweenInCinema(
@Path(value = "startDate") startDate: Instant,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ interface ReservationService {
@POST("reservations/{reservationId}/payment")
suspend fun payReservation(@Path("reservationId") reservationId: Uuid): Response<Unit>

// @GET("reservations/projection/{projectionId}")
@GET("reservations/projections/{projectionId}")
suspend fun getUserReservationForProjection(
@Path("projectionId") projectionId: Uuid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import kotlin.time.Instant
import kotlin.uuid.Uuid

interface RoomService {
@GET("rooms/{id}")
suspend fun getRoom(@Path("id") id: Uuid): Response<Room>

@GET("rooms/cinema/{cinemaId}")
suspend fun getCinemaRooms(@Path("cinemaId") cinemaId: Uuid): Response<List<Room>>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ import kotlin.uuid.Uuid

interface SeatService {
@GET("rooms/{projectionId}/seats/info")
suspend fun getSeatsInfo(@Path("projectionId") projectionId: Uuid): Response<List<SeatInfoResponse>>
suspend fun getSeatsInfo(
@Path("projectionId") projectionId: Uuid
): Response<List<SeatInfoResponse>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class ChatRepository @Inject constructor(

suspend fun getOrCreateConversation(
participants: ConversationParticipants,
): Result<Conversation> {
): Result<Conversation> = runCatching {
val queryRemote = suspend {
getConversationFromRemote { conversationService.getOrCreateConversation(participants) }
}
Expand All @@ -147,7 +147,7 @@ class ChatRepository @Inject constructor(
} ?: queryRemote()
}

suspend fun getConversation(conversationId: Uuid): Result<Conversation> {
suspend fun getConversation(conversationId: Uuid): Result<Conversation> = runCatching {
val queryRemote = suspend {
getConversationFromRemote { conversationService.getConversation(conversationId) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,15 @@ class MovieRepository @Inject constructor(

suspend fun getMovieById(id: Uuid): Result<Movie?> = runCatching {
val cached = movieDao.getMovieById(id)
return Result.success(if (cached != null) {
cached
} else {
withContext(Dispatchers.IO) {
fetchAndSaveMovie(id)
}
movieDao.getMovieById(id)
})
return Result.success(
if (cached != null) {
cached
} else {
withContext(Dispatchers.IO) {
fetchAndSaveMovie(id)
}
movieDao.getMovieById(id)
})
}

suspend fun fetchAndSaveMoviesProjectedInCinemaInTimeFrame(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class ReservationRepository @Inject constructor(
}
}

suspend fun createReservation(projectionId: Uuid): Result<ReservationModel> {
suspend fun createReservation(projectionId: Uuid): Result<ReservationModel> = runCatching {
val response = reservationService.createReservation(projectionId)
return if (response.isSuccessful) {
Result.success(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ class SeatRepository @Inject constructor(
) {
private val tag = this::class.simpleName


suspend fun getSeatsInfo(projectionId: Uuid): List<SeatModel> {
with(seatService.getSeatsInfo(projectionId)) {
if (isSuccessful) {
return body()!!.map { it.toSeatModel() }
} else {
Log.e(tag, "request to fetch user failed with ${code()}: ${errorBody()?.string()}")
try {
with(seatService.getSeatsInfo(projectionId)) {
if (isSuccessful) {
return body()!!.map { it.toSeatModel() }
} else {
Log.e(
tag,
"request to fetch user failed with ${code()}: ${errorBody()?.string()}"
)
}
}
} catch (e: Exception) {
Log.e(tag, "Could not get seat info", e)
}
return listOf()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.bytestrick.vertex.repository.paging

import android.util.Log
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
Expand All @@ -9,7 +10,6 @@ import com.github.bytestrick.vertex.data.AppDatabase
import com.github.bytestrick.vertex.data.entity.RemoteKey
import retrofit2.HttpException
import retrofit2.Response
import java.io.IOException
import kotlin.uuid.Uuid

/**
Expand Down Expand Up @@ -49,11 +49,8 @@ class PageMediator<Key : Any, Dto : Any, Value : Any>(
onUpsert(slice.content.map { converter(it) })
}
MediatorResult.Success(endOfPaginationReached = slice.last)
} catch (e: IOException) {
MediatorResult.Error(e)
} catch (e: HttpException) {
MediatorResult.Error(e)
} catch (e: Exception) {
MediatorResult.Error(e)
} catch (t: Throwable) {
Log.e("PageMediator", "Error loading page", t)
MediatorResult.Error(t)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.github.bytestrick.vertex.repository.paging

import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.github.bytestrick.vertex.api.dto.Slice
import retrofit2.HttpException
import retrofit2.Response
import java.io.IOException

/**
* Parametrized [PagingSource]. Used mainly for search. Deduplicates the content of the pages
Expand Down Expand Up @@ -42,9 +42,8 @@ class PageSource<Value : Any>(
prevKey = if (position == 0) null else position - 1,
nextKey = if (page?.last == true) null else position + 1
)
} catch (e: IOException) {
LoadResult.Error(e)
} catch (e: HttpException) {
LoadResult.Error(e)
} catch (t: Throwable) {
Log.e("PageSource", "Error loading page", t)
LoadResult.Error(t)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.github.bytestrick.vertex.ui.common.validateEmail
import com.github.bytestrick.vertex.ui.common.validatedPasswordAndConfirm
import com.github.bytestrick.vertex.ui.navigation.ResetPassword
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
Expand Down Expand Up @@ -65,26 +66,32 @@ class ResetPasswordViewModel @Inject constructor(

fun onEmailChange(email: String) = _uiState.update { it.copy(email = email, emailError = null) }

fun onEmailNext() = viewModelScope.launch {
_uiState.update { it.copy(isEmailCheckInProgress = true) }
// If the user is an OAuth2 user, the reset password flow should just set a new password,
// and enable them to sign in with the Google email and the new password.
val emailError = validateEmail(_uiState.value.email) ?: if (userService.isEmailTaken(
Email(_uiState.value.email)
).code() != 200
) R.string.sign_in_incorrect_email else null
if (emailError == null) {
with(authService.forgotPassword(Email(_uiState.value.email.trim()))) {
if (isSuccessful) {
_uiState.update { it.copy(step = Step.Email(true)) }
} else {
Snackbar.show(R.string.rst_pw_send_verification_email_failure)
fun onEmailNext() = viewModelScope.launch(Dispatchers.IO) {
try {
_uiState.update { it.copy(isEmailCheckInProgress = true) }
// If the user is an OAuth2 user, the reset password flow should just set a new password,
// and enable them to sign in with the Google email and the new password.
val emailError = validateEmail(_uiState.value.email) ?: if (userService.isEmailTaken(
Email(_uiState.value.email)
).code() != 200
) R.string.sign_in_incorrect_email else null
if (emailError == null) {
with(authService.forgotPassword(Email(_uiState.value.email.trim()))) {
if (isSuccessful) {
_uiState.update { it.copy(step = Step.Email(true)) }
} else {
Snackbar.show(R.string.rst_pw_send_verification_email_failure)
}
}
} else {
_uiState.update { it.copy(emailError = emailError) }
}
} else {
_uiState.update { it.copy(emailError = emailError) }
} catch (e: Exception) {
Snackbar.show()
Log.e(tag, "Error in forgot password flow", e)
} finally {
_uiState.update { it.copy(isEmailCheckInProgress = false) }
}
_uiState.update { it.copy(isEmailCheckInProgress = false) }
}

fun onPasswordChange(password: String) {
Expand All @@ -105,7 +112,7 @@ class ResetPasswordViewModel @Inject constructor(

fun onBackToEmail() = viewModelScope.launch { _uiState.update { it.copy(step = Step.Email()) } }

fun onResetPassword() = viewModelScope.launch {
fun onResetPassword() = viewModelScope.launch(Dispatchers.IO) {
val (passwordError, confirmPasswordError) = validatedPasswordAndConfirm(
_uiState.value.password,
_uiState.value.confirmPassword
Expand Down Expand Up @@ -143,19 +150,24 @@ class ResetPasswordViewModel @Inject constructor(
_uiState.update { it.copy(isPasswordResetInProgress = false) }
}

fun onResendEmail() = viewModelScope.launch {
with(authService.resendMfaEmail(Email(_uiState.value.email))) {
if (isSuccessful) {
Snackbar.show(R.string.verify_email_resend_success)
} else when (code()) {
401 -> {
Snackbar.show(R.string.verify_email_no_pending_verification_email)
_uiState.update { it.copy(step = Step.Terminated) }
}
fun onResendEmail() = viewModelScope.launch(Dispatchers.IO) {
try {
with(authService.resendMfaEmail(Email(_uiState.value.email))) {
if (isSuccessful) {
Snackbar.show(R.string.verify_email_resend_success)
} else when (code()) {
401 -> {
Snackbar.show(R.string.verify_email_no_pending_verification_email)
_uiState.update { it.copy(step = Step.Terminated) }
}

404 -> Snackbar.show(R.string.verify_email_user_not_found)
else -> Snackbar.show(R.string.verify_email_resend_default_error)
404 -> Snackbar.show(R.string.verify_email_user_not_found)
else -> Snackbar.show(R.string.verify_email_resend_default_error)
}
}
} catch (e: Exception) {
Log.e(tag, "Could not resend email", e)
Snackbar.show()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.github.bytestrick.vertex.ui.common.validateBirthday
import com.github.bytestrick.vertex.ui.common.validateEmail
import com.github.bytestrick.vertex.ui.common.validatedPasswordAndConfirm
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
Expand Down Expand Up @@ -83,12 +84,18 @@ class SignUpViewModel @Inject constructor(private val userService: UserService)
_uiState.update { it.copy(birthday = birthday, birthdayError = null) }
}

fun onPersonalDetailsNext() = viewModelScope.launch {
_uiState.update { it.copy(isEmailCheckInProgress = true) }
if (arePersonalDetailsValid()) {
_uiState.update { it.copy(step = Step.Password) }
fun onPersonalDetailsNext() = viewModelScope.launch(Dispatchers.IO) {
try {
_uiState.update { it.copy(isEmailCheckInProgress = true) }
if (arePersonalDetailsValid()) {
_uiState.update { it.copy(step = Step.Password) }
}
} catch (e: Exception) {
Snackbar.show()
Log.e(tag, "Error while verifying email existence", e)
} finally {
_uiState.update { it.copy(isEmailCheckInProgress = false) }
}
_uiState.update { it.copy(isEmailCheckInProgress = false) }
}

fun onBackToPersonalDetails() = viewModelScope.launch {
Expand Down Expand Up @@ -148,9 +155,9 @@ class SignUpViewModel @Inject constructor(private val userService: UserService)
}
}

fun signUp() = viewModelScope.launch {
_uiState.update { it.copy(isSignUpInProgress = true) }
fun signUp() = viewModelScope.launch(Dispatchers.IO) {
try {
_uiState.update { it.copy(isSignUpInProgress = true) }
if (isPasswordValid()) {
val res = userService.createUser(
NewUser(
Expand All @@ -172,7 +179,8 @@ class SignUpViewModel @Inject constructor(private val userService: UserService)
} catch (e: Exception) {
Log.e(tag, "sign up failed", e)
Snackbar.show(R.string.sign_up_failed)
} finally {
_uiState.update { it.copy(isSignUpInProgress = false) }
}
_uiState.update { it.copy(isSignUpInProgress = false) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import com.github.bytestrick.vertex.ui.common.Snackbar
import com.github.bytestrick.vertex.ui.navigation.VerifyEmail
import dagger.hilt.android.lifecycle.HiltViewModel
import jakarta.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

Expand Down Expand Up @@ -62,14 +65,14 @@ class VerifyEmailViewModel @Inject constructor(
}

"verify-new-email" -> {
Snackbar.show(R.string.verify_new_email_deep_link_success)
userRepository.fetchAndSaveUser(userRepository.user.filterNotNull().first().id)
_uiState.update {
it.copy(
step = Step.Terminated,
reason = VerificationReason.EMAIL_UPDATED
)
}
userRepository.user.value?.id?.let { userRepository.fetchAndSaveUser(it) }
Snackbar.show(R.string.verify_new_email_deep_link_success)
}

else -> {
Expand All @@ -91,7 +94,7 @@ class VerifyEmailViewModel @Inject constructor(
}
}

fun onResendEmail() = viewModelScope.launch {
fun onResendEmail() = viewModelScope.launch(Dispatchers.IO) {
try {
val res = authService.resendMfaEmail(Email(_uiState.value.email!!))
if (res.isSuccessful) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ fun NavGraphBuilder.authentication(windowPadding: PaddingValues, navController:
composable<VerifyEmail>(
deepLinks = listOf(
navDeepLink {
uriPattern = "$redirectionBase/redirect?reason=verify-email&error={error}"
uriPattern = "$redirectionBase/redirect/index.html?reason=verify-email&error={error}"
action = Intent.ACTION_VIEW
},
navDeepLink {
uriPattern =
"$redirectionBase/redirect?reason=verify-new-email&error={error}"
"$redirectionBase/redirect/index.html?reason=verify-new-email&error={error}"
action = Intent.ACTION_VIEW
}
)
Expand Down
Loading