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.BAKLAVA
|
||||||
import com.android.sdklib.AndroidVersion.ApiBaseExtension.VANILLA_ICE_CREAM
|
import com.android.sdklib.AndroidVersion.ApiBaseExtension.VANILLA_ICE_CREAM
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
import java.util.Properties
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.kotlin.compose)
|
alias(libs.plugins.kotlin.compose)
|
||||||
|
alias(libs.plugins.kotlin.serialization)
|
||||||
alias(libs.plugins.hilt.android)
|
alias(libs.plugins.hilt.android)
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +24,8 @@ android {
|
||||||
versionName = "1.0"
|
versionName = "1.0"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
buildConfigField("String", "API_BASE_URL", "\"${getSecret("API_BASE_URL")}\"")
|
||||||
|
buildConfigField("String", "ACCESS_TOKEN", "\"${getSecret("ACCESS_TOKEN")}\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -45,6 +49,7 @@ android {
|
||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
compose = true
|
compose = true
|
||||||
|
buildConfig = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +66,10 @@ dependencies {
|
||||||
implementation(libs.hilt.android)
|
implementation(libs.hilt.android)
|
||||||
implementation(libs.androidx.navigation.compose)
|
implementation(libs.androidx.navigation.compose)
|
||||||
implementation(libs.androidx.core.splashscreen)
|
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)
|
ksp(libs.hilt.android.compiler)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
|
@ -69,4 +78,23 @@ dependencies {
|
||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
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"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".CSGOApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
@ -11,7 +14,6 @@
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.CSGOMatches"
|
android:theme="@style/Theme.CSGOMatches"
|
||||||
android:name=".CSGOApplication"
|
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
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.android.application) apply false
|
||||||
alias(libs.plugins.kotlin.android) apply false
|
alias(libs.plugins.kotlin.android) apply false
|
||||||
alias(libs.plugins.kotlin.compose) 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.hilt.android) apply false
|
||||||
alias(libs.plugins.ksp) apply false
|
alias(libs.plugins.ksp) apply false
|
||||||
}
|
}
|
|
@ -12,6 +12,10 @@ hilt = "2.56.2"
|
||||||
ksp = "2.2.0-2.0.2"
|
ksp = "2.2.0-2.0.2"
|
||||||
navigation = "2.9.2"
|
navigation = "2.9.2"
|
||||||
splashScreen = "1.0.1"
|
splashScreen = "1.0.1"
|
||||||
|
retrofit = "1.0.0"
|
||||||
|
retrofit2 = "2.11.0"
|
||||||
|
kotlinxSerializationJson = "1.8.1"
|
||||||
|
okhttp = "4.12.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
|
@ -28,10 +32,14 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
|
||||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
hilt-android = { group = "com.google.dagger", name="hilt-android", version.ref = "hilt" }
|
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
|
||||||
hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
|
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-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" }
|
||||||
androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "splashScreen" }
|
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]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
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" }
|
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
|
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
|
||||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
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