diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9cefda3..0e3ab1c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -12,7 +12,7 @@ android { defaultConfig { applicationId = "com.iqball.app" - minSdk = 21 + minSdk = 28 targetSdk = 34 versionCode = 1 versionName = "1.0" diff --git a/app/src/main/java/com/iqball/app/MainActivity.kt b/app/src/main/java/com/iqball/app/MainActivity.kt index 7d79766..964daee 100644 --- a/app/src/main/java/com/iqball/app/MainActivity.kt +++ b/app/src/main/java/com/iqball/app/MainActivity.kt @@ -9,6 +9,8 @@ import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.iqball.app.api.EitherBodyConverter import com.iqball.app.api.EitherCallAdapterFactory import com.iqball.app.api.service.IQBallService import com.iqball.app.page.RegisterPage @@ -28,18 +30,10 @@ class MainActivity : ComponentActivity() { val gson = Gson() val retrofit = Retrofit.Builder() + .addConverterFactory(EitherBodyConverter.create()) .addConverterFactory(GsonConverterFactory.create(gson)) .addCallAdapterFactory(EitherCallAdapterFactory.create(gson)) - .addConverterFactory(object : Converter.Factory() { - override fun responseBodyConverter( - type: Type, - annotations: Array, - retrofit: Retrofit - ): Converter? { - return super.responseBodyConverter(type, annotations, retrofit) - } - }) - .baseUrl("http://grospc:5254") + .baseUrl("https://iqball.maxou.dev/api/dotnet-master/") .client( OkHttpClient.Builder() .addInterceptor { it.proceed(it.request()) } diff --git a/app/src/main/java/com/iqball/app/api/EitherBodyConverter.kt b/app/src/main/java/com/iqball/app/api/EitherBodyConverter.kt new file mode 100644 index 0000000..27da66c --- /dev/null +++ b/app/src/main/java/com/iqball/app/api/EitherBodyConverter.kt @@ -0,0 +1,37 @@ +package com.iqball.app.api + +import arrow.core.Either +import okhttp3.ResponseBody +import retrofit2.Call +import retrofit2.Converter +import retrofit2.Retrofit +import java.lang.reflect.ParameterizedType +import java.lang.reflect.Type + +class EitherBodyConverter : Converter.Factory() { + override fun responseBodyConverter( + type: Type, + annotations: Array, + retrofit: Retrofit + ): Converter? { + + if (type !is ParameterizedType) { + return null + } + if (type.rawType != Call::class.java) { + return null + } + val eitherType = type.actualTypeArguments.first() + if (eitherType !is ParameterizedType || eitherType.rawType != Either::class.java) { + return null + } + + val eitherRightType = eitherType.actualTypeArguments[1] + return retrofit.nextResponseBodyConverter(this, eitherRightType, annotations) + } + + companion object { + fun create() = EitherBodyConverter() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/iqball/app/api/EitherCallAdapterFactory.kt b/app/src/main/java/com/iqball/app/api/EitherCallAdapterFactory.kt index 67e00f1..7d115b4 100644 --- a/app/src/main/java/com/iqball/app/api/EitherCallAdapterFactory.kt +++ b/app/src/main/java/com/iqball/app/api/EitherCallAdapterFactory.kt @@ -1,5 +1,8 @@ package com.iqball.app.api +import android.os.Build +import androidx.annotation.RequiresApi +import arrow.core.Either import com.google.gson.Gson import com.skydoves.retrofit.adapters.arrow.EitherCallAdapterFactory import retrofit2.Call @@ -13,13 +16,21 @@ class EitherCallAdapterFactory(private val gson: Gson) : CallAdapter.Factory() { returnType: Type, annotations: Array, retrofit: Retrofit - ): CallAdapter<*, *> { + ): CallAdapter<*, *>? { + if (returnType !is ParameterizedType) { + return null + } + if (returnType.rawType != Call::class.java) { + return null + } + val eitherType = returnType.actualTypeArguments.first() + if (eitherType !is ParameterizedType || eitherType.rawType != Either::class.java) { + return null + } return object : CallAdapter { override fun responseType(): Type = returnType override fun adapt(call: Call): EitherCall { - val callType = returnType as ParameterizedType - val eitherType = callType.actualTypeArguments.first() as ParameterizedType return EitherCall(gson, eitherType, call) } } diff --git a/app/src/main/java/com/iqball/app/api/service/AuthService.kt b/app/src/main/java/com/iqball/app/api/service/AuthService.kt index bef7e4f..5b88a09 100644 --- a/app/src/main/java/com/iqball/app/api/service/AuthService.kt +++ b/app/src/main/java/com/iqball/app/api/service/AuthService.kt @@ -3,26 +3,26 @@ package com.iqball.app.api.service import arrow.core.Either import kotlinx.datetime.LocalDateTime import kotlinx.serialization.Serializable -import retrofit2.Call -import retrofit2.HttpException import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header import retrofit2.http.POST interface AuthService { @Serializable - data class AuthResponse(val token: String, val expirationDate: LocalDateTime) + data class AuthResponse(val token: String, val expirationDate: String) @Serializable data class RegisterRequest(val username: String, val email: String, val password: String) - @POST("/auth/register") + @POST("auth/register") suspend fun register(@Body req: RegisterRequest): APIResult data class LoginRequest(val email: String, val password: String) - @POST("/auth/token") - suspend fun login(@Body req: LoginRequest): Call + @POST("auth/token") + suspend fun login(@Body req: LoginRequest): APIResult } \ No newline at end of file diff --git a/app/src/main/java/com/iqball/app/api/service/IQBallService.kt b/app/src/main/java/com/iqball/app/api/service/IQBallService.kt index 81c3f28..bd73875 100644 --- a/app/src/main/java/com/iqball/app/api/service/IQBallService.kt +++ b/app/src/main/java/com/iqball/app/api/service/IQBallService.kt @@ -6,4 +6,4 @@ import retrofit2.Call typealias ErrorResponseResult = Map> typealias APIResult = Either -interface IQBallService : AuthService \ No newline at end of file +interface IQBallService : AuthService, UserService \ No newline at end of file diff --git a/app/src/main/java/com/iqball/app/api/service/UserService.kt b/app/src/main/java/com/iqball/app/api/service/UserService.kt new file mode 100644 index 0000000..f82376d --- /dev/null +++ b/app/src/main/java/com/iqball/app/api/service/UserService.kt @@ -0,0 +1,11 @@ +package com.iqball.app.api.service + +import retrofit2.http.GET +import retrofit2.http.Header + +interface UserService { + data class UserDataResponse(val teams: List, val tactics: List) + + @GET("user-data") + suspend fun getUserData(@Header("Authorization") auth: String): APIResult +} \ No newline at end of file diff --git a/app/src/main/java/com/iqball/app/page/RegisterPage.kt b/app/src/main/java/com/iqball/app/page/RegisterPage.kt index 012d3c9..6bb14bc 100644 --- a/app/src/main/java/com/iqball/app/page/RegisterPage.kt +++ b/app/src/main/java/com/iqball/app/page/RegisterPage.kt @@ -8,8 +8,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import arrow.core.Either +import com.iqball.app.api.service.AuthService import com.iqball.app.api.service.AuthService.RegisterRequest import com.iqball.app.api.service.IQBallService +import com.iqball.app.session.Authentication +import com.iqball.app.session.MutableSession import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay @@ -22,26 +25,30 @@ fun RegisterPage(service: IQBallService) { var text by remember { mutableStateOf("No message !") } - runBlocking { - val result = service.register(RegisterRequest("abcdefg", "a@m.com", "123456")) + val result = service.login(AuthService.LoginRequest("maxime@mail.com", "123456")) when (result) { - is Either.Left -> println("Error : " + result.value) - is Either.Right -> println("Success : " + result.value) + is Either.Left -> { + println("Error : " + result.value) + text = result.toString() + } + is Either.Right -> { + val token = result.value.token + val userDataResponse = service.getUserData(token) + + when (userDataResponse) { + is Either.Left -> println("Error User Data : " + userDataResponse.value) + is Either.Right -> println("Success User Data : " + userDataResponse.value) + } + + text = userDataResponse.toString() + } } println(result) - text = result.toString() Log.i("%", result.toString()) } Text(text = text) } - -suspend fun updateTextIn5Sec(setText: (String) -> Unit) = coroutineScope { - launch(Dispatchers.IO) { - delay(5000) - setText("test") - } -} \ No newline at end of file diff --git a/app/src/main/java/com/iqball/app/session/Authentication.kt b/app/src/main/java/com/iqball/app/session/Authentication.kt new file mode 100644 index 0000000..1f9aed4 --- /dev/null +++ b/app/src/main/java/com/iqball/app/session/Authentication.kt @@ -0,0 +1,5 @@ +package com.iqball.app.session + +import kotlinx.datetime.LocalDateTime + +data class Authentication(val token: String, val expirationDate: LocalDateTime) diff --git a/app/src/main/java/com/iqball/app/session/MutableSession.kt b/app/src/main/java/com/iqball/app/session/MutableSession.kt new file mode 100644 index 0000000..37219bf --- /dev/null +++ b/app/src/main/java/com/iqball/app/session/MutableSession.kt @@ -0,0 +1,5 @@ +package com.iqball.app.session + +interface MutableSession : Session { + override var auth: Authentication +} \ No newline at end of file diff --git a/app/src/main/java/com/iqball/app/session/Session.kt b/app/src/main/java/com/iqball/app/session/Session.kt new file mode 100644 index 0000000..bb34b40 --- /dev/null +++ b/app/src/main/java/com/iqball/app/session/Session.kt @@ -0,0 +1,5 @@ +package com.iqball.app.session + +interface Session { + val auth: Authentication +} \ No newline at end of file