diff --git a/Prezel/app/build.gradle.kts b/Prezel/app/build.gradle.kts index 8b216b84..ef75ab70 100644 --- a/Prezel/app/build.gradle.kts +++ b/Prezel/app/build.gradle.kts @@ -1,14 +1,21 @@ plugins { - alias(libs.plugins.prezel.android.application) alias(libs.plugins.prezel.android.application.compose) + alias(libs.plugins.prezel.hilt) } android { namespace = "com.team.prezel" + + buildFeatures { + buildConfig = true + } } dependencies { + implementation(projects.core.data) + implementation(libs.androidx.activity.ktx) implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.timber) } diff --git a/Prezel/app/src/main/AndroidManifest.xml b/Prezel/app/src/main/AndroidManifest.xml index 7162ca24..639a9130 100644 --- a/Prezel/app/src/main/AndroidManifest.xml +++ b/Prezel/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ diff --git a/Prezel/app/src/main/java/com/team/prezel/PrezelApplication.kt b/Prezel/app/src/main/java/com/team/prezel/PrezelApplication.kt new file mode 100644 index 00000000..f05bcfd2 --- /dev/null +++ b/Prezel/app/src/main/java/com/team/prezel/PrezelApplication.kt @@ -0,0 +1,15 @@ +package com.team.prezel + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp +import timber.log.Timber + +@HiltAndroidApp +class PrezelApplication : Application() { + override fun onCreate() { + super.onCreate() + if (BuildConfig.DEBUG) { + Timber.plant(Timber.DebugTree()) + } + } +} diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/external/LocalPropertiesExt.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/external/LocalPropertiesExt.kt new file mode 100644 index 00000000..440e8866 --- /dev/null +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/external/LocalPropertiesExt.kt @@ -0,0 +1,28 @@ +package com.team.prezel.buildlogic.convention.external + +import org.gradle.api.Project +import org.gradle.api.provider.Provider +import java.io.StringReader +import java.util.Properties + +fun Project.localProperty(key: String): Provider { + val localPropertiesFile = isolated.rootProject.projectDirectory.file("local.properties") + + return providers.provider { + val file = localPropertiesFile.asFile + if (!file.exists()) { + logger.warn("local.properties not found") + return@provider null + } + + val properties = Properties() + properties.load(StringReader(file.readText())) + val value = properties.getProperty(key) + + if (value == null) { + logger.warn("Key '$key' not found in local.properties") + } + + value + } +} diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/AndroidCompose.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/AndroidCompose.kt similarity index 93% rename from Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/AndroidCompose.kt rename to Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/AndroidCompose.kt index 0a57e87e..4f30fd7a 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/AndroidCompose.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/AndroidCompose.kt @@ -1,4 +1,4 @@ -package com.team.prezel.buildlogic.convention +package com.team.prezel.buildlogic.convention.internal import com.android.build.api.dsl.CommonExtension import org.gradle.api.Project diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/KotlinAndroid.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/KotlinAndroid.kt similarity index 97% rename from Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/KotlinAndroid.kt rename to Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/KotlinAndroid.kt index 661b4caa..7add3d06 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/KotlinAndroid.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/KotlinAndroid.kt @@ -1,4 +1,4 @@ -package com.team.prezel.buildlogic.convention +package com.team.prezel.buildlogic.convention.internal import com.android.build.api.dsl.CommonExtension import org.gradle.api.JavaVersion diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/ProjectExtensions.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/ProjectExtensions.kt similarity index 76% rename from Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/ProjectExtensions.kt rename to Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/ProjectExtensions.kt index e2343036..a36e5ce0 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/ProjectExtensions.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/internal/ProjectExtensions.kt @@ -1,9 +1,9 @@ -package com.team.prezel.buildlogic.convention +package com.team.prezel.buildlogic.convention.internal import org.gradle.api.Project import org.gradle.api.artifacts.VersionCatalog import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.kotlin.dsl.getByType -val Project.libs +internal val Project.libs get(): VersionCatalog = extensions.getByType().named("libs") diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidApplicationComposeConventionPlugin.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidApplicationComposeConventionPlugin.kt index 4c79a9b2..77fbb94f 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidApplicationComposeConventionPlugin.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidApplicationComposeConventionPlugin.kt @@ -1,7 +1,7 @@ package com.team.prezel.buildlogic.convention.plugin import com.android.build.api.dsl.ApplicationExtension -import com.team.prezel.buildlogic.convention.configureAndroidCompose +import com.team.prezel.buildlogic.convention.internal.configureAndroidCompose import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidApplicationConventionPlugin.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidApplicationConventionPlugin.kt index 2e796f0f..da33c831 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidApplicationConventionPlugin.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidApplicationConventionPlugin.kt @@ -1,7 +1,7 @@ package com.team.prezel.buildlogic.convention.plugin import com.android.build.api.dsl.ApplicationExtension -import com.team.prezel.buildlogic.convention.configureKotlinAndroid +import com.team.prezel.buildlogic.convention.internal.configureKotlinAndroid import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidFeatureImplConventionPlugin.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidFeatureImplConventionPlugin.kt index 1ee1a460..0f981deb 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidFeatureImplConventionPlugin.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidFeatureImplConventionPlugin.kt @@ -1,7 +1,7 @@ package com.team.prezel.buildlogic.convention.plugin import com.android.build.api.dsl.LibraryExtension -import com.team.prezel.buildlogic.convention.libs +import com.team.prezel.buildlogic.convention.internal.libs import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidLibraryComposeConventionPlugin.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidLibraryComposeConventionPlugin.kt index 6d10f810..9ebf8ce0 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidLibraryComposeConventionPlugin.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidLibraryComposeConventionPlugin.kt @@ -1,7 +1,7 @@ package com.team.prezel.buildlogic.convention.plugin import com.android.build.api.dsl.LibraryExtension -import com.team.prezel.buildlogic.convention.configureAndroidCompose +import com.team.prezel.buildlogic.convention.internal.configureAndroidCompose import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidLibraryConventionPlugin.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidLibraryConventionPlugin.kt index 963e6b69..d3d3a5cc 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidLibraryConventionPlugin.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/AndroidLibraryConventionPlugin.kt @@ -1,8 +1,8 @@ package com.team.prezel.buildlogic.convention.plugin import com.android.build.api.dsl.LibraryExtension -import com.team.prezel.buildlogic.convention.configureKotlinAndroid -import com.team.prezel.buildlogic.convention.libs +import com.team.prezel.buildlogic.convention.internal.configureKotlinAndroid +import com.team.prezel.buildlogic.convention.internal.libs import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/HiltConventionPlugin.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/HiltConventionPlugin.kt index 890d6092..bcf7de93 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/HiltConventionPlugin.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/HiltConventionPlugin.kt @@ -1,6 +1,6 @@ package com.team.prezel.buildlogic.convention.plugin -import com.team.prezel.buildlogic.convention.libs +import com.team.prezel.buildlogic.convention.internal.libs import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply @@ -19,6 +19,7 @@ class HiltConventionPlugin : Plugin { dependencies { "ksp"(libs.findLibrary("hilt.compiler").get()) + "ksp"(libs.findLibrary("kotlin.metadata.jvm").get()) } pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { diff --git a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/JvmLibraryConventionPlugin.kt b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/JvmLibraryConventionPlugin.kt index c31144c6..242d2532 100644 --- a/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/JvmLibraryConventionPlugin.kt +++ b/Prezel/build-logic/convention/src/main/java/com/team/prezel/buildlogic/convention/plugin/JvmLibraryConventionPlugin.kt @@ -1,7 +1,7 @@ package com.team.prezel.buildlogic.convention.plugin -import com.team.prezel.buildlogic.convention.configureKotlinJvm -import com.team.prezel.buildlogic.convention.libs +import com.team.prezel.buildlogic.convention.internal.configureKotlinJvm +import com.team.prezel.buildlogic.convention.internal.libs import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply diff --git a/Prezel/core/data/.gitignore b/Prezel/core/data/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/Prezel/core/data/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Prezel/core/data/build.gradle.kts b/Prezel/core/data/build.gradle.kts new file mode 100644 index 00000000..366eb6c7 --- /dev/null +++ b/Prezel/core/data/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + alias(libs.plugins.prezel.android.library) + alias(libs.plugins.prezel.hilt) +} + +android { + namespace = "com.team.prezel.core.data" + testOptions.unitTests.isIncludeAndroidResources = true +} + +dependencies { + implementation(projects.core.network) + implementation(libs.kotlinx.coroutines.core) +} diff --git a/Prezel/core/data/consumer-rules.pro b/Prezel/core/data/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/Prezel/core/data/proguard-rules.pro b/Prezel/core/data/proguard-rules.pro new file mode 100644 index 00000000..f1b42451 --- /dev/null +++ b/Prezel/core/data/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Prezel/core/data/src/androidTest/java/com/team/prezel/core/data/.gitkeep b/Prezel/core/data/src/androidTest/java/com/team/prezel/core/data/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Prezel/core/data/src/main/AndroidManifest.xml b/Prezel/core/data/src/main/AndroidManifest.xml new file mode 100644 index 00000000..e1000761 --- /dev/null +++ b/Prezel/core/data/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/Prezel/core/data/src/main/java/com/team/prezel/core/data/RepositoryModule.kt b/Prezel/core/data/src/main/java/com/team/prezel/core/data/RepositoryModule.kt new file mode 100644 index 00000000..bbf6a3f3 --- /dev/null +++ b/Prezel/core/data/src/main/java/com/team/prezel/core/data/RepositoryModule.kt @@ -0,0 +1,9 @@ +package com.team.prezel.core.data + +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +abstract class RepositoryModule diff --git a/Prezel/core/data/src/test/java/com/team/prezel/core/data/.gitkeep b/Prezel/core/data/src/test/java/com/team/prezel/core/data/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Prezel/core/network/.gitignore b/Prezel/core/network/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/Prezel/core/network/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Prezel/core/network/build.gradle.kts b/Prezel/core/network/build.gradle.kts new file mode 100644 index 00000000..d36c3be7 --- /dev/null +++ b/Prezel/core/network/build.gradle.kts @@ -0,0 +1,47 @@ +import com.android.build.api.variant.BuildConfigField +import com.team.prezel.buildlogic.convention.external.localProperty + +plugins { + alias(libs.plugins.prezel.android.library) + alias(libs.plugins.prezel.hilt) + alias(libs.plugins.kotlinx.serialization) +} + +android { + buildFeatures { + buildConfig = true + } + + namespace = "com.team.prezel.core.network" + testOptions.unitTests.isIncludeAndroidResources = true +} + +dependencies { + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.okhttp) + implementation(libs.ktor.client.content.negotiation) + implementation(libs.ktor.serialization.kotlinx.json) + implementation(libs.ktor.client.logging) + implementation(libs.kotlinx.serialization.json) + implementation(libs.timber) + + implementation(libs.ktorfit.lib) + ksp(libs.ktorfit.ksp) + + testImplementation(libs.kotlinx.coroutines.test) +} + +androidComponents { + onVariants { variant -> + val buildType = variant.buildType ?: return@onVariants + val buildConfigFields = variant.buildConfigFields ?: return@onVariants + val baseUrlKey = "${buildType.uppercase()}_BASE_URL" + + buildConfigFields.put( + "BASE_URL", + localProperty(baseUrlKey).map { value -> + BuildConfigField("String", "\"$value\"", null) + }, + ) + } +} diff --git a/Prezel/core/network/consumer-rules.pro b/Prezel/core/network/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/Prezel/core/network/proguard-rules.pro b/Prezel/core/network/proguard-rules.pro new file mode 100644 index 00000000..f1b42451 --- /dev/null +++ b/Prezel/core/network/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Prezel/core/network/src/androidTest/java/com/team/prezel/core/network/.gitkeep b/Prezel/core/network/src/androidTest/java/com/team/prezel/core/network/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Prezel/core/network/src/main/AndroidManifest.xml b/Prezel/core/network/src/main/AndroidManifest.xml new file mode 100644 index 00000000..5e7684f5 --- /dev/null +++ b/Prezel/core/network/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/Prezel/core/network/src/main/java/com/team/prezel/core/network/ApiResponseConverterFactory.kt b/Prezel/core/network/src/main/java/com/team/prezel/core/network/ApiResponseConverterFactory.kt new file mode 100644 index 00000000..5569c137 --- /dev/null +++ b/Prezel/core/network/src/main/java/com/team/prezel/core/network/ApiResponseConverterFactory.kt @@ -0,0 +1,70 @@ +package com.team.prezel.core.network + +import com.team.prezel.core.network.model.ApiResponse +import de.jensklingenberg.ktorfit.Ktorfit +import de.jensklingenberg.ktorfit.converter.Converter +import de.jensklingenberg.ktorfit.converter.KtorfitResult +import de.jensklingenberg.ktorfit.converter.TypeData +import io.ktor.client.call.body +import io.ktor.client.plugins.ResponseException +import io.ktor.client.statement.HttpResponse +import io.ktor.util.reflect.TypeInfo +import timber.log.Timber +import java.io.IOException +import kotlin.coroutines.cancellation.CancellationException + +class ApiResponseConverterFactory : Converter.Factory { + override fun suspendResponseConverter( + typeData: TypeData, + ktorfit: Ktorfit, + ): Converter.SuspendResponseConverter? { + if (typeData.typeInfo.type != ApiResponse::class) return null + val bodyTypeInfo = typeData.typeArgs.firstOrNull()?.typeInfo ?: return null + + return object : Converter.SuspendResponseConverter> { + override suspend fun convert(result: KtorfitResult): ApiResponse = + when (result) { + is KtorfitResult.Success -> parseSuccess(result.response, bodyTypeInfo) + is KtorfitResult.Failure -> mapFailure(result.throwable) + } + } + } + + private suspend fun parseSuccess( + response: HttpResponse, + bodyTypeInfo: TypeInfo, + ): ApiResponse = + try { + val body = response.body(bodyTypeInfo) + ApiResponse.Success(body) + } catch (t: Throwable) { + t.rethrowIfCancellation() + Timber.e(t, "Response parsing failed") + ApiResponse.Failure.NetworkError(t) + } + + private fun mapFailure(t: Throwable): ApiResponse { + t.rethrowIfCancellation() + + return when (t) { + is IOException -> { + Timber.e(t, "Network error") + ApiResponse.Failure.NetworkError(t) + } + + is ResponseException -> { + Timber.e(t, "HTTP error ${t.response.status.value}") + ApiResponse.Failure.HttpError(t) + } + + else -> { + Timber.e(t, "Unknown error") + ApiResponse.Failure.NetworkError(t) + } + } + } + + private fun Throwable.rethrowIfCancellation() { + if (this is CancellationException) throw this + } +} diff --git a/Prezel/core/network/src/main/java/com/team/prezel/core/network/di/NetworkModule.kt b/Prezel/core/network/src/main/java/com/team/prezel/core/network/di/NetworkModule.kt new file mode 100644 index 00000000..a77a1357 --- /dev/null +++ b/Prezel/core/network/src/main/java/com/team/prezel/core/network/di/NetworkModule.kt @@ -0,0 +1,70 @@ +package com.team.prezel.core.network.di + +import com.team.prezel.core.network.ApiResponseConverterFactory +import com.team.prezel.core.network.BuildConfig +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import de.jensklingenberg.ktorfit.Ktorfit +import io.ktor.client.HttpClient +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.http.ContentType +import io.ktor.http.contentType +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json +import timber.log.Timber +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object NetworkModule { + @Provides + @Singleton + fun provideJson(): Json = + Json { + ignoreUnknownKeys = true + coerceInputValues = true + encodeDefaults = true + prettyPrint = false + } + + @Provides + @Singleton + fun provideHttpClient(json: Json): HttpClient = + HttpClient(OkHttp) { + expectSuccess = true + + install(ContentNegotiation) { + json(json) + } + + install(Logging) { + logger = object : Logger { + override fun log(message: String) { + Timber.tag("KtorClient").d(message) + } + } + level = if (BuildConfig.DEBUG) LogLevel.BODY else LogLevel.NONE + } + + defaultRequest { + contentType(ContentType.Application.Json) + } + } + + @Provides + @Singleton + fun provideKtorfit(httpClient: HttpClient): Ktorfit = + Ktorfit + .Builder() + .baseUrl(BuildConfig.BASE_URL) + .httpClient(httpClient) + .converterFactories(ApiResponseConverterFactory()) + .build() +} diff --git a/Prezel/core/network/src/main/java/com/team/prezel/core/network/model/ApiResponse.kt b/Prezel/core/network/src/main/java/com/team/prezel/core/network/model/ApiResponse.kt new file mode 100644 index 00000000..83d44a66 --- /dev/null +++ b/Prezel/core/network/src/main/java/com/team/prezel/core/network/model/ApiResponse.kt @@ -0,0 +1,17 @@ +package com.team.prezel.core.network.model + +sealed interface ApiResponse { + data class Success( + val data: T, + ) : ApiResponse + + sealed interface Failure : ApiResponse { + data class HttpError( + val throwable: Throwable, + ) : Failure + + data class NetworkError( + val throwable: Throwable, + ) : Failure + } +} diff --git a/Prezel/core/network/src/test/java/com/team/prezel/core/network/.gitkeep b/Prezel/core/network/src/test/java/com/team/prezel/core/network/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Prezel/detekt-config.yml b/Prezel/detekt-config.yml index ea5bfde0..c631b0fc 100644 --- a/Prezel/detekt-config.yml +++ b/Prezel/detekt-config.yml @@ -51,3 +51,5 @@ potential-bugs: exceptions: active: true + TooGenericExceptionCaught: + active: false diff --git a/Prezel/gradle/libs.versions.toml b/Prezel/gradle/libs.versions.toml index 3fceabbc..d779789f 100644 --- a/Prezel/gradle/libs.versions.toml +++ b/Prezel/gradle/libs.versions.toml @@ -1,6 +1,8 @@ [versions] agp = "8.13.2" kotlin = "2.3.0" +kotlinMetadataJvm = "2.3.0" +kotlinxCoroutines = "1.10.2" coreKtx = "1.17.0" junit = "4.13.2" junitVersion = "1.3.0" @@ -14,6 +16,10 @@ ksp = "2.3.4" activityKtx = "1.12.2" hilt = "2.57.2" desugarJdk = "2.0.3" +ktor = "3.3.3" +ktorfit = "2.7.2" +kotlinx-serialization = "1.9.0" +timber = "5.0.1" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -37,7 +43,20 @@ hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" } hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" } hilt-core = { group = "com.google.dagger", name = "hilt-core", version.ref = "hilt" } +kotlin-metadata-jvm = { module = "org.jetbrains.kotlin:kotlin-metadata-jvm", version.ref = "kotlinMetadataJvm" } kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" } +kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } +kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } +kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } +ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } +ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } +ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } +ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } +ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } +ktorfit-lib = { module = "de.jensklingenberg.ktorfit:ktorfit-lib", version.ref = "ktorfit" } +ktorfit-ksp = { module = "de.jensklingenberg.ktorfit:ktorfit-ksp", version.ref = "ktorfit" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" } +timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } # Dependencies of the included build-logic android-gradleApiPlugin = { group = "com.android.tools.build", name = "gradle-api", version.ref = "agp" } @@ -56,6 +75,7 @@ detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } # Plugins defined by this project prezel-android-application = { id = "prezel.android.application" } diff --git a/Prezel/settings.gradle.kts b/Prezel/settings.gradle.kts index a8f98851..97683e5d 100644 --- a/Prezel/settings.gradle.kts +++ b/Prezel/settings.gradle.kts @@ -31,3 +31,5 @@ rootProject.name = "Prezel" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") include(":app") +include(":core:data") +include(":core:network")