Fix exception handling
continuous-integration/drone/push Build is passing Details

pull/5/head
avalin 1 year ago
parent 71deba6f12
commit 4ce266860f

@ -4,7 +4,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import fr.iut.alldev.allin.data.api.interceptors.AllInAPIException
import fr.iut.alldev.allin.data.model.bet.BetFactory import fr.iut.alldev.allin.data.model.bet.BetFactory
import fr.iut.alldev.allin.data.model.bet.BetType import fr.iut.alldev.allin.data.model.bet.BetType
import fr.iut.alldev.allin.data.repository.BetRepository import fr.iut.alldev.allin.data.repository.BetRepository
@ -114,7 +113,7 @@ class BetCreationViewModel @Inject constructor(
betRepository.createBet(bet, keystoreManager.getTokenOrEmpty()) betRepository.createBet(bet, keystoreManager.getTokenOrEmpty())
onSuccess() onSuccess()
} ?: onError() } ?: onError()
} catch (e: AllInAPIException) { } catch (e: Exception) {
Timber.e(e) Timber.e(e)
onError() onError()
} }

@ -46,7 +46,7 @@ import fr.iut.alldev.allin.ui.core.AllInTextField
fun LoginScreen( fun LoginScreen(
navigateToDashboard: () -> Unit, navigateToDashboard: () -> Unit,
navigateToRegister: () -> Unit, navigateToRegister: () -> Unit,
loginViewModel: LoginViewModel = hiltViewModel(), loginViewModel: LoginViewModel = hiltViewModel()
) { ) {
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
@ -170,7 +170,9 @@ fun LoginScreen(
} }
} }
} }
AllInLoading(visible = loading) AllInLoading(visible = loading)
AllInAlertDialog( AllInAlertDialog(
enabled = hasLoginError, enabled = hasLoginError,
title = stringResource(id = R.string.Login_Error_Title), title = stringResource(id = R.string.Login_Error_Title),

@ -4,12 +4,13 @@ import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import fr.iut.alldev.allin.data.api.interceptors.AllInAPIException
import fr.iut.alldev.allin.data.repository.UserRepository import fr.iut.alldev.allin.data.repository.UserRepository
import fr.iut.alldev.allin.keystore.AllInKeystoreManager import fr.iut.alldev.allin.keystore.AllInKeystoreManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import retrofit2.HttpException
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -23,9 +24,7 @@ class LoginViewModel @Inject constructor(
val username = mutableStateOf("") val username = mutableStateOf("")
val password = mutableStateOf("") val password = mutableStateOf("")
fun onLogin( fun onLogin(navigateToDashboard: () -> Unit) {
navigateToDashboard: () -> Unit
) {
viewModelScope.launch { viewModelScope.launch {
loading.value = true loading.value = true
@ -34,12 +33,14 @@ class LoginViewModel @Inject constructor(
userRepository userRepository
.login(username.value, password.value) .login(username.value, password.value)
?.let { token -> keystoreManager.putToken(token) } ?.let { token -> keystoreManager.putToken(token) }
} catch (e: AllInAPIException) { navigateToDashboard()
} catch (e: Exception) {
hasError.value = true hasError.value = true
if (e !is HttpException || e.code() != 404) {
Timber.e(e)
} }
} }
if (!hasError.value) {
navigateToDashboard()
} }
loading.value = false loading.value = false
} }

@ -56,6 +56,7 @@ private val topLevelDestinations = listOf(
TopLevelDestination.BetCreation, TopLevelDestination.BetCreation,
TopLevelDestination.BetHistory, TopLevelDestination.BetHistory,
TopLevelDestination.Friends, TopLevelDestination.Friends,
TopLevelDestination.Ranking,
TopLevelDestination.CurrentBets TopLevelDestination.CurrentBets
) )

@ -44,6 +44,7 @@ object Routes {
const val BET_HISTORY = "BET_HISTORY" const val BET_HISTORY = "BET_HISTORY"
const val BET_CURRENT = "BET_CURRENT" const val BET_CURRENT = "BET_CURRENT"
const val FRIENDS = "FRIENDS" const val FRIENDS = "FRIENDS"
const val RANKING = "RANKING"
} }
private val fadingRoutes private val fadingRoutes
@ -66,7 +67,7 @@ internal fun NavHostController.popUpTo(route: String, baseRoute: String) {
fun AllInNavHost( fun AllInNavHost(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(), navController: NavHostController = rememberNavController(),
startDestination: String = Routes.SPLASH, startDestination: String = Routes.SPLASH
) { ) {
NavHost( NavHost(
navController = navController, navController = navController,
@ -141,7 +142,7 @@ internal fun AllInDrawerNavHost(
} }
composable( composable(
route = Routes.FRIENDS route = Routes.RANKING
) { ) {
backHandlers() backHandlers()
RankingScreen() RankingScreen()

@ -42,4 +42,11 @@ sealed class TopLevelDestination(
subtitle = R.string.current_bets_subtitle, subtitle = R.string.current_bets_subtitle,
emoji = R.drawable.money_with_wings emoji = R.drawable.money_with_wings
) )
data object Ranking : TopLevelDestination(
route = Routes.RANKING,
title = R.string.ranking,
subtitle = R.string.ranking_subtitle,
emoji = R.drawable.ranking
)
} }

@ -1,31 +1,17 @@
package fr.iut.alldev.allin.ui.register package fr.iut.alldev.allin.ui.register
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.Text import androidx.compose.runtime.Composable
import androidx.compose.runtime.* import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.focus.FocusDirection import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import fr.iut.alldev.allin.R import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.ui.core.AllInAlertDialog
import fr.iut.alldev.allin.ui.core.AllInGradientButton
import fr.iut.alldev.allin.ui.core.AllInLoading
import fr.iut.alldev.allin.ui.core.AllInPasswordField
import fr.iut.alldev.allin.ui.core.AllInTextField
import fr.iut.alldev.allin.ui.register.components.RegisterScreenContent import fr.iut.alldev.allin.ui.register.components.RegisterScreenContent
@Composable @Composable
@ -39,6 +25,7 @@ fun RegisterScreen(
val loading by remember { registerViewModel.loading } val loading by remember { registerViewModel.loading }
var hasNetworkError by remember { mutableStateOf(false) }
val usernameError by remember { registerViewModel.usernameError } val usernameError by remember { registerViewModel.usernameError }
val emailError by remember { registerViewModel.emailError } val emailError by remember { registerViewModel.emailError }
val passwordError by remember { registerViewModel.passwordError } val passwordError by remember { registerViewModel.passwordError }
@ -58,10 +45,11 @@ fun RegisterScreen(
onDone = { onDone = {
focusManager.clearFocus() focusManager.clearFocus()
registerViewModel.onRegister( registerViewModel.onRegister(
usernameFieldName, usernameFieldName = usernameFieldName,
emailFieldName, emailFieldName = emailFieldName,
passwordFieldName, passwordFieldName = passwordFieldName,
navigateToDashboard navigateToDashboard = navigateToDashboard,
displayNetworkErrorAlert = { hasNetworkError = false }
) )
}, },
onNext = { onNext = {
@ -74,10 +62,11 @@ fun RegisterScreen(
navigateToLogin = navigateToLogin, navigateToLogin = navigateToLogin,
onRegister = { onRegister = {
registerViewModel.onRegister( registerViewModel.onRegister(
usernameFieldName, usernameFieldName = usernameFieldName,
emailFieldName, emailFieldName = emailFieldName,
passwordFieldName, passwordFieldName = passwordFieldName,
navigateToDashboard navigateToDashboard = navigateToDashboard,
displayNetworkErrorAlert = { hasNetworkError = false }
) )
}, },
keyboardActions = keyboardActions, keyboardActions = keyboardActions,
@ -99,4 +88,11 @@ fun RegisterScreen(
setPasswordValidation = setPasswordValidation setPasswordValidation = setPasswordValidation
) )
AllInAlertDialog(
enabled = hasNetworkError,
title = stringResource(id = R.string.network_error),
text = stringResource(id = R.string.network_error_text),
onDismiss = { hasNetworkError = false }
)
} }

@ -4,7 +4,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import fr.iut.alldev.allin.data.api.interceptors.AllInAPIException
import fr.iut.alldev.allin.data.repository.UserRepository import fr.iut.alldev.allin.data.repository.UserRepository
import fr.iut.alldev.allin.ext.ALLOWED_SYMBOLS import fr.iut.alldev.allin.ext.ALLOWED_SYMBOLS
import fr.iut.alldev.allin.ext.FieldErrorState import fr.iut.alldev.allin.ext.FieldErrorState
@ -14,6 +13,8 @@ import fr.iut.alldev.allin.keystore.AllInKeystoreManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import retrofit2.HttpException
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private const val MIN_PASSWORD_SIZE = 8 private const val MIN_PASSWORD_SIZE = 8
@ -83,7 +84,8 @@ class RegisterViewModel @Inject constructor(
usernameFieldName: String, usernameFieldName: String,
emailFieldName: String, emailFieldName: String,
passwordFieldName: String, passwordFieldName: String,
navigateToDashboard: () -> Unit navigateToDashboard: () -> Unit,
displayNetworkErrorAlert: () -> Unit
) { ) {
viewModelScope.launch { viewModelScope.launch {
loading.value = true loading.value = true
@ -104,11 +106,20 @@ class RegisterViewModel @Inject constructor(
password.value password.value
) )
?.let { token -> keystoreManager.putToken(token) } ?.let { token -> keystoreManager.putToken(token) }
} catch (e: AllInAPIException) { } catch (e: Exception) {
when {
e is HttpException && e.code() == 409 -> {
usernameError.value = FieldErrorState.AlreadyUsed(username.value) usernameError.value = FieldErrorState.AlreadyUsed(username.value)
emailError.value = FieldErrorState.AlreadyUsed(email.value) emailError.value = FieldErrorState.AlreadyUsed(email.value)
hasError.value = true hasError.value = true
} }
else -> {
Timber.e(e)
displayNetworkErrorAlert()
}
}
}
} }
} }
if (!hasError.value) { if (!hasError.value) {

@ -28,6 +28,8 @@
<string name="Stake">Mise</string> <string name="Stake">Mise</string>
<string name="Possible_winnings">Gains possibles</string> <string name="Possible_winnings">Gains possibles</string>
<string name="generic_error">Erreur</string> <string name="generic_error">Erreur</string>
<string name="network_error">Une erreur est survenue</string>
<string name="network_error_text">Assurez-vous d\'être bien connecté au réseau puis réessayez.</string>
<!--Drawer--> <!--Drawer-->
<string name="bets">Bets</string> <string name="bets">Bets</string>
@ -42,6 +44,8 @@
<string name="friends_subtitle">Défiez vos porches en les ajoutant en amis.</string> <string name="friends_subtitle">Défiez vos porches en les ajoutant en amis.</string>
<string name="current_bets">Bets en cours</string> <string name="current_bets">Bets en cours</string>
<string name="current_bets_subtitle">Gérez vos bets et récompensez les gagnants.</string> <string name="current_bets_subtitle">Gérez vos bets et récompensez les gagnants.</string>
<string name="ranking">Classement</string>
<string name="ranking_subtitle">Consultez votre classement parmi vos amis.</string>
<!--Welcome Page--> <!--Welcome Page-->
<string name="welcome_title">Bienvenue sur</string> <string name="welcome_title">Bienvenue sur</string>
<string name="welcome_subtitle">Récupère tes Allcoins et viens parier avec tes amis pour prouver qui est le meilleur.</string> <string name="welcome_subtitle">Récupère tes Allcoins et viens parier avec tes amis pour prouver qui est le meilleur.</string>

@ -30,6 +30,8 @@
<string name="Stake">Stake</string> <string name="Stake">Stake</string>
<string name="Possible_winnings">Possible winnings</string> <string name="Possible_winnings">Possible winnings</string>
<string name="generic_error">Error</string> <string name="generic_error">Error</string>
<string name="network_error">An error occurred</string>
<string name="network_error_text">Make sure to be properly connected to the network then try again.</string>
<!--Drawer--> <!--Drawer-->
<string name="bets">Bets</string> <string name="bets">Bets</string>
@ -44,6 +46,8 @@
<string name="friends_subtitle">Challenge your folks by adding them as friends.</string> <string name="friends_subtitle">Challenge your folks by adding them as friends.</string>
<string name="current_bets">Current bets</string> <string name="current_bets">Current bets</string>
<string name="current_bets_subtitle">Manage your bets and reward the winners.</string> <string name="current_bets_subtitle">Manage your bets and reward the winners.</string>
<string name="ranking">Ranking</string>
<string name="ranking_subtitle">Browse your ranking with your friends.</string>
<!--Welcome Page--> <!--Welcome Page-->
<string name="welcome_title">Welcome to</string> <string name="welcome_title">Welcome to</string>
<string name="welcome_appname" translatable="false">Allin.</string> <string name="welcome_appname" translatable="false">Allin.</string>

@ -4,7 +4,6 @@ import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import fr.iut.alldev.allin.data.api.interceptors.ErrorInterceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import javax.inject.Singleton import javax.inject.Singleton
@ -22,6 +21,5 @@ internal object DebugNetworkModule {
level = HttpLoggingInterceptor.Level.BODY level = HttpLoggingInterceptor.Level.BODY
} }
) )
.addInterceptor(ErrorInterceptor())
.build() .build()
} }

@ -1,7 +1,5 @@
package fr.iut.alldev.allin.data.api package fr.iut.alldev.allin.data.api
import fr.iut.alldev.allin.data.api.interceptors.AllInAPIException
import fr.iut.alldev.allin.data.api.interceptors.AllInUnauthorizedException
import fr.iut.alldev.allin.data.api.model.CheckUser import fr.iut.alldev.allin.data.api.model.CheckUser
import fr.iut.alldev.allin.data.api.model.RequestBet import fr.iut.alldev.allin.data.api.model.RequestBet
import fr.iut.alldev.allin.data.api.model.RequestParticipation import fr.iut.alldev.allin.data.api.model.RequestParticipation
@ -25,6 +23,8 @@ import java.time.Duration
import java.time.ZonedDateTime import java.time.ZonedDateTime
import java.util.UUID import java.util.UUID
class MockAllInApiException(override val message: String?) : Exception()
class MockAllInApi : AllInApi { class MockAllInApi : AllInApi {
init { init {
@ -71,12 +71,12 @@ class MockAllInApi : AllInApi {
override suspend fun login(body: CheckUser): ResponseUser { override suspend fun login(body: CheckUser): ResponseUser {
return mockUsers.find { it.first.username == body.login && it.second == body.password }?.first return mockUsers.find { it.first.username == body.login && it.second == body.password }?.first
?: throw AllInAPIException("Invalid login/password.") ?: throw MockAllInApiException("Invalid login/password.")
} }
override suspend fun login(token: String): ResponseUser { override suspend fun login(token: String): ResponseUser {
return getUserFromToken(token)?.first return getUserFromToken(token)?.first
?: throw AllInAPIException("Invalid token") ?: throw MockAllInApiException("Invalid token")
} }
override suspend fun register(body: RequestUser): ResponseUser { override suspend fun register(body: RequestUser): ResponseUser {
@ -109,7 +109,7 @@ class MockAllInApi : AllInApi {
} }
override suspend fun dailyGift(token: String): Int { override suspend fun dailyGift(token: String): Int {
getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") getUserFromToken(token) ?: throw MockAllInApiException("Invalid login/password.")
if (mockGifts[token] == null) { if (mockGifts[token] == null) {
mockGifts[token] = ZonedDateTime.now().minusDays(1) mockGifts[token] = ZonedDateTime.now().minusDays(1)
} }
@ -130,16 +130,16 @@ class MockAllInApi : AllInApi {
} else it } else it
} }
return amount return amount
} else throw AllInUnauthorizedException("Gift already taken today") } else throw MockAllInApiException("Gift already taken today")
} }
override suspend fun getAllBets(token: String): List<ResponseBet> { override suspend fun getAllBets(token: String): List<ResponseBet> {
getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") getUserFromToken(token) ?: throw MockAllInApiException("Invalid login/password.")
return mockBets return mockBets
} }
override suspend fun getToConfirm(token: String): List<ResponseBetDetail> { override suspend fun getToConfirm(token: String): List<ResponseBetDetail> {
val user = getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") val user = getUserFromToken(token) ?: throw MockAllInApiException("Invalid login/password.")
return mockBets.filter { return mockBets.filter {
it.createdBy == user.first.username && it.status == BetStatus.CLOSING it.createdBy == user.first.username && it.status == BetStatus.CLOSING
}.map { bet -> }.map { bet ->
@ -156,8 +156,8 @@ class MockAllInApi : AllInApi {
} }
override suspend fun confirmBet(token: String, id: String, value: String) { override suspend fun confirmBet(token: String, id: String, value: String) {
getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") getUserFromToken(token) ?: throw MockAllInApiException("Invalid login/password.")
val bet = mockBets.find { it.id == id } ?: throw AllInAPIException("Unauthorized") val bet = mockBets.find { it.id == id } ?: throw MockAllInApiException("Unauthorized")
mockResults.add( mockResults.add(
ResponseBetResult( ResponseBetResult(
betId = id, betId = id,
@ -168,8 +168,8 @@ class MockAllInApi : AllInApi {
} }
override suspend fun getBet(token: String, id: String): ResponseBetDetail { override suspend fun getBet(token: String, id: String): ResponseBetDetail {
val bet = mockBets.find { it.id == id } ?: throw AllInAPIException("Bet not found") val bet = mockBets.find { it.id == id } ?: throw MockAllInApiException("Bet not found")
val user = getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") val user = getUserFromToken(token) ?: throw MockAllInApiException("Invalid login/password.")
val betParticipations = mockParticipations.filter { it.betId == bet.id } val betParticipations = mockParticipations.filter { it.betId == bet.id }
val userParticipation = betParticipations.find { it.username == user.first.username } val userParticipation = betParticipations.find { it.username == user.first.username }
val wonParticipation = if (bet.status == BetStatus.FINISHED) { val wonParticipation = if (bet.status == BetStatus.FINISHED) {
@ -187,7 +187,7 @@ class MockAllInApi : AllInApi {
} }
override suspend fun getBetCurrent(token: String): List<ResponseBetDetail> { override suspend fun getBetCurrent(token: String): List<ResponseBetDetail> {
val user = getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") val user = getUserFromToken(token) ?: throw MockAllInApiException("Invalid login/password.")
val betParticipations = mockParticipations.filter { it.username == user.first.username } val betParticipations = mockParticipations.filter { it.username == user.first.username }
return betParticipations.map { p -> return betParticipations.map { p ->
getBet(token, p.betId) getBet(token, p.betId)
@ -197,7 +197,7 @@ class MockAllInApi : AllInApi {
} }
override suspend fun getBetHistory(token: String): List<ResponseBetResultDetail> { override suspend fun getBetHistory(token: String): List<ResponseBetResultDetail> {
val user = getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") val user = getUserFromToken(token) ?: throw MockAllInApiException("Invalid login/password.")
val betParticipations = mockParticipations.filter { it.username == user.first.username } val betParticipations = mockParticipations.filter { it.username == user.first.username }
return betParticipations.map { p -> return betParticipations.map { p ->
getBet(token, p.betId) getBet(token, p.betId)
@ -252,7 +252,7 @@ class MockAllInApi : AllInApi {
) )
) )
} ?: throw AllInAPIException("Invalid token") } ?: throw MockAllInApiException("Invalid token")
} }
companion object { companion object {

@ -1,31 +0,0 @@
package fr.iut.alldev.allin.data.api.interceptors
import okhttp3.Interceptor
import okhttp3.Response
import okio.IOException
open class AllInAPIException(message: String) : IOException(message)
class AllInNotFoundException(message: String) : AllInAPIException(message)
class AllInUnauthorizedException(message: String) : AllInAPIException(message)
class AllInUnsuccessfulException(message: String) : AllInAPIException(message)
class ErrorInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)
if (!response.isSuccessful) {
when (response.code) {
404 -> throw AllInNotFoundException(response.message)
401 -> throw AllInUnauthorizedException(response.message)
else -> throw AllInUnsuccessfulException(response.message)
}
}
response.body?.contentType()?.subtype?.takeIf { it != "json" }?.let {
throw AllInAPIException(response.message)
}
return response
}
}

@ -1,3 +1,3 @@
package fr.iut.alldev.allin.data.ext package fr.iut.alldev.allin.data.ext
fun Float.toPercentageString(precision: Int = 0) = String.format("%.${precision}f", this*100) + "%" fun Float.toPercentageString(precision: Int = 0) = String.format("%.${precision}f", this * 100) + "%"

@ -4,7 +4,6 @@ import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import fr.iut.alldev.allin.data.api.interceptors.ErrorInterceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import javax.inject.Singleton import javax.inject.Singleton
@ -16,6 +15,5 @@ internal object ReleaseNetworkModule {
@Singleton @Singleton
fun provideOkHttpClient(): OkHttpClient = fun provideOkHttpClient(): OkHttpClient =
OkHttpClient.Builder() OkHttpClient.Builder()
.addInterceptor(ErrorInterceptor())
.build() .build()
} }
Loading…
Cancel
Save