feat: add network, dto, mapping and repository initial setup
This commit is contained in:
parent
7eb061fc9d
commit
3fd7e78090
24 changed files with 492 additions and 3 deletions
|
@ -1,11 +1,13 @@
|
|||
import com.android.sdklib.AndroidVersion.ApiBaseExtension.BAKLAVA
|
||||
import com.android.sdklib.AndroidVersion.ApiBaseExtension.VANILLA_ICE_CREAM
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
alias(libs.plugins.hilt.android)
|
||||
alias(libs.plugins.ksp)
|
||||
}
|
||||
|
@ -22,6 +24,8 @@ android {
|
|||
versionName = "1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
buildConfigField("String", "API_BASE_URL", "\"${getSecret("API_BASE_URL")}\"")
|
||||
buildConfigField("String", "ACCESS_TOKEN", "\"${getSecret("ACCESS_TOKEN")}\"")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
@ -45,6 +49,7 @@ android {
|
|||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
buildConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +66,10 @@ dependencies {
|
|||
implementation(libs.hilt.android)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
implementation(libs.androidx.core.splashscreen)
|
||||
implementation(libs.retrofit2)
|
||||
implementation(libs.retrofit.kotlinx.serialization.converter)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.okhttp)
|
||||
ksp(libs.hilt.android.compiler)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
|
@ -70,3 +79,22 @@ dependencies {
|
|||
debugImplementation(libs.androidx.ui.tooling)
|
||||
debugImplementation(libs.androidx.ui.test.manifest)
|
||||
}
|
||||
|
||||
fun getSecret(key: String): String {
|
||||
// 1. Check Gradle -P property (CI)
|
||||
project.findProperty(key)?.let { return it.toString() }
|
||||
|
||||
// 2. Check environment variable (CI)
|
||||
System.getenv(key)?.let { return it }
|
||||
|
||||
// 3. Fallback to local.properties (local dev)
|
||||
val localPropsFile = rootProject.file("local.properties")
|
||||
if (localPropsFile.exists()) {
|
||||
val props = Properties().apply {
|
||||
load(localPropsFile.inputStream())
|
||||
}
|
||||
return props.getProperty(key) ?: ""
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:name=".CSGOApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
|
@ -11,7 +14,6 @@
|
|||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.CSGOMatches"
|
||||
android:name=".CSGOApplication"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package xyz.leomurca.csgomatches.data.local
|
||||
|
||||
import xyz.leomurca.csgomatches.data.model.LeagueDto
|
||||
import xyz.leomurca.csgomatches.data.model.MatchDto
|
||||
import xyz.leomurca.csgomatches.data.model.OpponentDto
|
||||
import xyz.leomurca.csgomatches.data.model.OpponentRecord
|
||||
import xyz.leomurca.csgomatches.data.model.SerieDto
|
||||
import xyz.leomurca.csgomatches.data.source.MatchDataSource
|
||||
import xyz.leomurca.csgomatches.domain.model.Resource
|
||||
|
||||
class MatchLocalDataSource : MatchDataSource {
|
||||
override suspend fun upcomingMatches(): Resource<List<MatchDto>> {
|
||||
return Resource.Success(
|
||||
data = listOf(
|
||||
MatchDto(
|
||||
beginAt = "2025-07-27T10:30:00Z",
|
||||
opponents = emptyList(),
|
||||
league = LeagueDto(
|
||||
id = 5078,
|
||||
name = "United21",
|
||||
imageUrl = "https://cdn.pandascore.co/images/league/image/5078/800px-united21_allmode-png"
|
||||
),
|
||||
serie = SerieDto(
|
||||
id = 9519,
|
||||
fullName = "Season 35 2025"
|
||||
),
|
||||
status = "not_started"
|
||||
),
|
||||
MatchDto(
|
||||
beginAt = "2025-07-21T10:30:00Z",
|
||||
opponents = listOf(
|
||||
OpponentDto(
|
||||
type = "team",
|
||||
opponent = OpponentRecord(
|
||||
id = 128519,
|
||||
name = "GenOne",
|
||||
imageUrl = "https://cdn.pandascore.co/images/team/image/128519/genone_csgo.png"
|
||||
)
|
||||
),
|
||||
OpponentDto(
|
||||
type = "team",
|
||||
opponent = OpponentRecord(
|
||||
id = 134996,
|
||||
name = "VOLT",
|
||||
imageUrl = "https://cdn.pandascore.co/images/team/image/134996/127px_volt_2024_allmode.png"
|
||||
)
|
||||
)
|
||||
),
|
||||
league = LeagueDto(
|
||||
id = 5078,
|
||||
name = "United21",
|
||||
imageUrl = "https://cdn.pandascore.co/images/league/image/5078/800px-united21_allmode-png"
|
||||
),
|
||||
serie = SerieDto(
|
||||
id = 9519,
|
||||
fullName = "Season 35 2025"
|
||||
),
|
||||
status = "not_started"
|
||||
),
|
||||
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package xyz.leomurca.csgomatches.data.mapper
|
||||
|
||||
import xyz.leomurca.csgomatches.data.model.MatchDto
|
||||
import xyz.leomurca.csgomatches.domain.model.League
|
||||
import xyz.leomurca.csgomatches.domain.model.Match
|
||||
import xyz.leomurca.csgomatches.domain.model.Opponent
|
||||
import xyz.leomurca.csgomatches.domain.model.Serie
|
||||
|
||||
fun MatchDto.toDomain(): Match {
|
||||
return Match(
|
||||
beginAt = beginAt ?: "",
|
||||
opponents = opponents.map { op ->
|
||||
Opponent(
|
||||
id = op.opponent.id,
|
||||
name = op.opponent.name ?: "",
|
||||
imageUrl = op.opponent.imageUrl ?: ""
|
||||
)
|
||||
},
|
||||
league = League(
|
||||
id = league.id,
|
||||
name = league.name ?: "",
|
||||
imageUrl = league.imageUrl ?: ""
|
||||
),
|
||||
serie = Serie(
|
||||
id = serie.id,
|
||||
name = serie.fullName ?: ""
|
||||
),
|
||||
status = status ?: ""
|
||||
)
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package xyz.leomurca.csgomatches.data.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ErrorDto(
|
||||
@SerialName("error") val message: String
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
package xyz.leomurca.csgomatches.data.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class LeagueDto(
|
||||
val id: Long,
|
||||
val name: String?,
|
||||
@SerialName("image_url")
|
||||
val imageUrl: String?
|
||||
)
|
||||
|
||||
//"league": {
|
||||
// "id": 5078,
|
||||
// "name": "United21",
|
||||
// "url": null,
|
||||
// "slug": "cs-go-united21",
|
||||
// "modified_at": "2023-12-22T16:36:10Z",
|
||||
// "image_url": "https://cdn.pandascore.co/images/league/image/5078/800px-united21_allmode-png"
|
||||
//},
|
|
@ -0,0 +1,17 @@
|
|||
package xyz.leomurca.csgomatches.data.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class MatchDto(
|
||||
@SerialName("begin_at")
|
||||
val beginAt: String?,
|
||||
val opponents: List<OpponentDto>,
|
||||
val league: LeagueDto,
|
||||
val serie: SerieDto,
|
||||
val status: String?
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package xyz.leomurca.csgomatches.data.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class OpponentDto(
|
||||
val type: String?,
|
||||
val opponent: OpponentRecord
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class OpponentRecord(
|
||||
val id: Long,
|
||||
val name: String?,
|
||||
@SerialName("image_url")
|
||||
val imageUrl: String?
|
||||
)
|
||||
|
||||
//{
|
||||
// "type": "Team",
|
||||
// "opponent": {
|
||||
// "id": 126694,
|
||||
// "name": "BIG Academy",
|
||||
// "location": "DE",
|
||||
// "slug": "big-academy",
|
||||
// "modified_at": "2025-07-17T10:49:15Z",
|
||||
// "acronym": "BIG.A",
|
||||
// "image_url": "https://cdn.pandascore.co/images/team/image/126694/big.png"
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,26 @@
|
|||
package xyz.leomurca.csgomatches.data.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SerieDto(
|
||||
val id: Long,
|
||||
@SerialName("full_name")
|
||||
val fullName: String?
|
||||
)
|
||||
|
||||
//"serie": {
|
||||
// "id": 9519,
|
||||
// "name": "",
|
||||
// "year": 2025,
|
||||
// "begin_at": "2025-07-18T08:00:00Z",
|
||||
// "end_at": "2025-08-04T21:00:00Z",
|
||||
// "winner_id": null,
|
||||
// "winner_type": "Team",
|
||||
// "slug": "cs-go-united21-35-2025",
|
||||
// "modified_at": "2025-07-17T10:55:39Z",
|
||||
// "league_id": 5078,
|
||||
// "season": "35",
|
||||
// "full_name": "Season 35 2025"
|
||||
//},
|
|
@ -0,0 +1,15 @@
|
|||
package xyz.leomurca.csgomatches.data.remote
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
class AuthorizationInterceptor(
|
||||
private val token: String
|
||||
) : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request().newBuilder()
|
||||
.addHeader("Authorization", "Bearer $token")
|
||||
.build()
|
||||
return chain.proceed(request)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package xyz.leomurca.csgomatches.data.remote
|
||||
|
||||
import kotlinx.serialization.json.Json
|
||||
import xyz.leomurca.csgomatches.data.model.ErrorDto
|
||||
import xyz.leomurca.csgomatches.data.model.MatchDto
|
||||
import xyz.leomurca.csgomatches.data.source.MatchDataSource
|
||||
import xyz.leomurca.csgomatches.domain.model.Resource
|
||||
|
||||
class MatchRemoteDataSourceImpl(
|
||||
private val matchesApiService: MatchesApiService,
|
||||
private val json: Json
|
||||
) : MatchDataSource {
|
||||
override suspend fun upcomingMatches(): Resource<List<MatchDto>> {
|
||||
return try {
|
||||
val response = matchesApiService.upcomingMatches()
|
||||
|
||||
if (response.isSuccessful) {
|
||||
Resource.Success(response.body() ?: throw Exception("Empty response body"))
|
||||
} else {
|
||||
val errorBody = response.errorBody()?.string() ?: ""
|
||||
val networkError = json.decodeFromString<ErrorDto>(errorBody)
|
||||
Resource.Error(networkError.message)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Resource.Error(e.message.toString())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package xyz.leomurca.csgomatches.data.remote
|
||||
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.GET
|
||||
import xyz.leomurca.csgomatches.data.model.MatchDto
|
||||
|
||||
interface MatchesApiService {
|
||||
|
||||
@GET("matches")
|
||||
suspend fun upcomingMatches(): Response<List<MatchDto>>
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package xyz.leomurca.csgomatches.data.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import xyz.leomurca.csgomatches.data.mapper.toDomain
|
||||
import xyz.leomurca.csgomatches.data.source.MatchDataSource
|
||||
import xyz.leomurca.csgomatches.di.AppDispatchers
|
||||
import xyz.leomurca.csgomatches.di.Dispatcher
|
||||
import xyz.leomurca.csgomatches.domain.model.Match
|
||||
import xyz.leomurca.csgomatches.domain.model.Resource
|
||||
import xyz.leomurca.csgomatches.domain.repository.MatchRepository
|
||||
|
||||
class MatchRepositoryImpl(
|
||||
@Dispatcher(AppDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
|
||||
private val matchRemoteDataSource: MatchDataSource
|
||||
) : MatchRepository {
|
||||
override suspend fun upcomingMatches(): Resource<List<Match>> {
|
||||
return withContext(ioDispatcher) {
|
||||
when (val result = matchRemoteDataSource.upcomingMatches()) {
|
||||
is Resource.Success -> Resource.Success(result.data.map { it.toDomain() })
|
||||
is Resource.Error -> Resource.Error(result.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package xyz.leomurca.csgomatches.data.source
|
||||
|
||||
import xyz.leomurca.csgomatches.data.model.MatchDto
|
||||
import xyz.leomurca.csgomatches.domain.model.Resource
|
||||
|
||||
interface MatchDataSource {
|
||||
suspend fun upcomingMatches(): Resource<List<MatchDto>>
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package xyz.leomurca.csgomatches.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import jakarta.inject.Qualifier
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class Dispatcher(val appDispatcher: AppDispatchers)
|
||||
|
||||
enum class AppDispatchers {
|
||||
Default,
|
||||
IO,
|
||||
}
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object DispatchersModule {
|
||||
@Provides
|
||||
@Dispatcher(AppDispatchers.IO)
|
||||
fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO
|
||||
|
||||
@Provides
|
||||
@Dispatcher(AppDispatchers.Default)
|
||||
fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package xyz.leomurca.csgomatches.di
|
||||
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Interceptor
|
||||
import retrofit2.Retrofit
|
||||
import xyz.leomurca.csgomatches.data.remote.MatchesApiService
|
||||
import javax.inject.Singleton
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import xyz.leomurca.csgomatches.BuildConfig
|
||||
import xyz.leomurca.csgomatches.data.local.MatchLocalDataSource
|
||||
import xyz.leomurca.csgomatches.data.remote.AuthorizationInterceptor
|
||||
import xyz.leomurca.csgomatches.data.remote.MatchRemoteDataSourceImpl
|
||||
import xyz.leomurca.csgomatches.data.repository.MatchRepositoryImpl
|
||||
import xyz.leomurca.csgomatches.data.source.MatchDataSource
|
||||
import xyz.leomurca.csgomatches.domain.repository.MatchRepository
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object NetworkModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesNetworkJson(): Json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
isLenient = true
|
||||
explicitNulls = false
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAuthorizationInterceptor(): Interceptor {
|
||||
return AuthorizationInterceptor(BuildConfig.ACCESS_TOKEN)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(authInterceptor: Interceptor): OkHttpClient {
|
||||
return OkHttpClient.Builder()
|
||||
.addInterceptor(authInterceptor)
|
||||
.build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideRetrofit(json: Json, okHttpClient: OkHttpClient): Retrofit {
|
||||
val contentType = "application/json".toMediaType()
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(BuildConfig.API_BASE_URL)
|
||||
.client(okHttpClient)
|
||||
.addConverterFactory(json.asConverterFactory(contentType))
|
||||
.build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideMatchesApiService(retrofit: Retrofit): MatchesApiService {
|
||||
return retrofit.create(MatchesApiService::class.java)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideMatchRemoteDataSource(
|
||||
matchesApiService: MatchesApiService,
|
||||
json: Json
|
||||
): MatchDataSource {
|
||||
val useRemote = false
|
||||
return if (useRemote) {
|
||||
MatchRemoteDataSourceImpl(matchesApiService, json)
|
||||
} else {
|
||||
MatchLocalDataSource()
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesMatchRepository(
|
||||
@Dispatcher(AppDispatchers.IO) ioDispatcher: CoroutineDispatcher,
|
||||
matchRemoteDataSource: MatchDataSource
|
||||
): MatchRepository {
|
||||
return MatchRepositoryImpl(ioDispatcher, matchRemoteDataSource)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package xyz.leomurca.csgomatches.domain.model
|
||||
|
||||
data class League(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val imageUrl: String
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
package xyz.leomurca.csgomatches.domain.model
|
||||
|
||||
|
||||
data class Match(
|
||||
val beginAt: String,
|
||||
val opponents: List<Opponent>,
|
||||
val league: League,
|
||||
val serie: Serie,
|
||||
val status: String
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
package xyz.leomurca.csgomatches.domain.model
|
||||
|
||||
data class Opponent(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val imageUrl: String
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
package xyz.leomurca.csgomatches.domain.model
|
||||
|
||||
sealed class Resource<out T> {
|
||||
data class Success<T>(val data: T) : Resource<T>()
|
||||
data class Error(val message: String) : Resource<Nothing>()
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package xyz.leomurca.csgomatches.domain.model
|
||||
|
||||
data class Serie(
|
||||
val id: Long,
|
||||
val name: String
|
||||
)
|
|
@ -0,0 +1,9 @@
|
|||
package xyz.leomurca.csgomatches.domain.repository
|
||||
|
||||
import xyz.leomurca.csgomatches.domain.model.Match
|
||||
import xyz.leomurca.csgomatches.domain.model.Resource
|
||||
|
||||
interface MatchRepository {
|
||||
|
||||
suspend fun upcomingMatches(): Resource<List<Match>>
|
||||
}
|
|
@ -3,6 +3,7 @@ plugins {
|
|||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.kotlin.compose) apply false
|
||||
alias(libs.plugins.kotlin.serialization) apply false
|
||||
alias(libs.plugins.hilt.android) apply false
|
||||
alias(libs.plugins.ksp) apply false
|
||||
}
|
|
@ -12,6 +12,10 @@ hilt = "2.56.2"
|
|||
ksp = "2.2.0-2.0.2"
|
||||
navigation = "2.9.2"
|
||||
splashScreen = "1.0.1"
|
||||
retrofit = "1.0.0"
|
||||
retrofit2 = "2.11.0"
|
||||
kotlinxSerializationJson = "1.8.1"
|
||||
okhttp = "4.12.0"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
|
@ -32,6 +36,10 @@ hilt-android = { group = "com.google.dagger", name="hilt-android", version.ref =
|
|||
hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
|
||||
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" }
|
||||
androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "splashScreen" }
|
||||
retrofit2 = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit2" }
|
||||
retrofit-kotlinx-serialization-converter = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofit" }
|
||||
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
@ -39,5 +47,6 @@ kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
|||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
|
||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue