Skip to content

Commit

Permalink
Merge pull request #34 from wisemuji/feature/#33
Browse files Browse the repository at this point in the history
  • Loading branch information
wisemuji authored Jul 12, 2023
2 parents 6ec0d9c + 4bd1331 commit f0850d6
Show file tree
Hide file tree
Showing 17 changed files with 221 additions and 20 deletions.
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<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=".DroidKnightsApplication"
android:allowBackup="true"
Expand All @@ -16,4 +18,4 @@

</application>

</manifest>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.droidknights.app2023

import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies

internal fun Project.configureCoroutineAndroid() {
val libs = extensions.libs
configureCoroutineKotlin()
dependencies {
"implementation"(libs.findLibrary("coroutines.android").get())
}
}

internal fun Project.configureCoroutineKotlin() {
val libs = extensions.libs
dependencies {
"implementation"(libs.findLibrary("coroutines.core").get())
"testImplementation"(libs.findLibrary("coroutines.test").get())
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import com.droidknights.app2023.configureCoroutineAndroid
import com.droidknights.app2023.configureKotest
import com.droidknights.app2023.configureKotlinAndroid

Expand All @@ -8,3 +9,4 @@ plugins {

configureKotlinAndroid()
configureKotest()
configureCoroutineAndroid()
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.droidknights.app2023.core.data.di

import com.droidknights.app2023.core.data.api.GithubApi
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import dagger.Module
import dagger.Provides
Expand All @@ -8,30 +9,39 @@ import dagger.hilt.components.SingletonComponent
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import retrofit2.Converter
import retrofit2.Retrofit
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
internal object ApiModule {
private const val BASE_URL = "https://raw.githubusercontent.com/"



@Provides
@Singleton
fun provideOkhttpClient(): OkHttpClient = OkHttpClient.Builder().build()

@Provides
@Singleton
fun provideRetrofit(
okHttpClient: OkHttpClient,
fun provideConverterFactory(
json: Json,
): Retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.client(okHttpClient)
.build()

): Converter.Factory {
return json.asConverterFactory("application/json".toMediaType())
}

@Provides
@Singleton
fun provideGithubApi(
okHttpClient: OkHttpClient,
converterFactory: Converter.Factory,
): GithubApi {
return Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(converterFactory)
.client(okHttpClient).build()
.create(GithubApi::class.java)
}

@Provides
@Singleton
fun provideJson(): Json = Json {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.droidknights.app2023.core.data.di

import com.droidknights.app2023.core.data.repository.ContributorRepository
import com.droidknights.app2023.core.data.repository.DefaultContributorRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@InstallIn(SingletonComponent::class)
@Module
internal abstract class DataModule {

@Binds
abstract fun bindsContributorRepository(
repository: DefaultContributorRepository,
): ContributorRepository
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@ import io.kotest.matchers.shouldBe

internal class DefaultContributorRepositoryTest : BehaviorSpec() {

private lateinit var repository: DefaultContributorRepository
private val repository: DefaultContributorRepository = DefaultContributorRepository(
githubApi = FakeGithubApi(contributors)
)

init {
beforeEach {
repository = DefaultContributorRepository(
githubApi = FakeGithubApi(contributors)
)
}
Given("기여자가 존재한다") {
val expected = contributors

Expand Down
8 changes: 7 additions & 1 deletion core/domain/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
plugins {
id("droidknights.kotlin.library")
id("droidknights.android.library")
}

android {
namespace = "com.droidknights.app2023.core.domain"
}

dependencies {
implementation(project(":core:data"))

implementation(libs.inject)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.droidknights.app2023.core.domain.mapper

import com.droidknights.app2023.core.data.model.ContributorEntity
import com.droidknights.app2023.core.domain.model.Contributor

internal fun ContributorEntity.toDomain(): Contributor =
Contributor(
name = this.name,
imageUrl = this.imageUrl
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.droidknights.app2023.core.domain.model

data class Contributor(
val name: String,
val imageUrl: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.droidknights.app2023.core.domain.usecase

import com.droidknights.app2023.core.data.model.ContributorEntity
import com.droidknights.app2023.core.data.repository.ContributorRepository
import com.droidknights.app2023.core.domain.mapper.toDomain
import com.droidknights.app2023.core.domain.model.Contributor
import javax.inject.Inject

class GetContributorsUseCase @Inject constructor(
private val repository: ContributorRepository,
) {
suspend operator fun invoke(): List<Contributor> {
return repository.getContributors(
owner = OWNER,
name = NAME,
).map(ContributorEntity::toDomain)
}

companion object {
private const val OWNER = "droidknights"
// TODO: DroidKnights2023_App로 변경 필요
private const val NAME = "DroidKnights2021_App"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.droidknights.app2023.core.domain.usecase

import com.droidknights.app2023.core.data.model.ContributorEntity
import com.droidknights.app2023.core.data.repository.ContributorRepository

internal class FakeContributorRepository(
private val contributors: List<ContributorEntity>,
) : ContributorRepository {
override suspend fun getContributors(owner: String, name: String): List<ContributorEntity> {
return contributors
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.droidknights.app2023.core.domain.usecase

import com.droidknights.app2023.core.data.model.ContributorEntity
import com.droidknights.app2023.core.domain.model.Contributor
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe

internal class GetContributorsUseCaseTest : BehaviorSpec() {

private val useCase: GetContributorsUseCase = GetContributorsUseCase(
repository = FakeContributorRepository(contributors)
)

init {
Given("드로이드나이츠 컨트리뷰터가 존재한다") {
val expected = contributors

When("드로이드나이츠 컨트리뷰터를 조회한다") {
val contributors: List<Contributor> = useCase.invoke()

Then("드로이드나이츠 컨트리뷰터를 반환한다") {
contributors.size shouldBe 1
contributors.all {
it.name == expected[0].name
}
}
}
}
}

companion object {
private val contributors = listOf(
ContributorEntity(
name = "test name",
imageUrl = "test image url"
)
)
}
}
8 changes: 8 additions & 0 deletions feature/contributor/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ plugins {
android {
namespace = "com.droidknights.app2023.feature.contributor"
}

dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.runtimeCompose)
implementation(libs.androidx.lifecycle.viewModelCompose)
implementation(libs.hilt.navigation.compose)
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.droidknights.app2023.feature.contributor

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.droidknights.app2023.core.domain.usecase.GetContributorsUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject

@HiltViewModel
class ContributorViewModel @Inject constructor(
getContributorsUseCase: GetContributorsUseCase,
) : ViewModel() {

val uiState: StateFlow<ContributorsUiState> =
flow { emit(getContributorsUseCase()) }.map(
ContributorsUiState::Contributors,
).stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = ContributorsUiState.Loading,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.droidknights.app2023.feature.contributor

import com.droidknights.app2023.core.domain.model.Contributor

sealed interface ContributorsUiState {
object Loading : ContributorsUiState

data class Contributors(
val contributors: List<Contributor>,
) : ContributorsUiState
}
9 changes: 9 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ androidxComposeNavigation = "2.6.0"
androidxComposeMaterial3 = "1.1.0"
androidxActivity = "1.7.2"
hilt = "2.46.1"
hiltNavigationCompose = "1.0.0"

okhttp = "4.11.0"
retrofit = "2.9.0"
Expand All @@ -24,6 +25,8 @@ kotest = "5.6.2"
# https://github.com/detekt/detekt
detekt = "1.23.0"

coroutine = "1.7.0"

[libraries]
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "androidDesugarJdkLibs" }
Expand Down Expand Up @@ -51,6 +54,8 @@ 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-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }

hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose" }

okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
retrofit-core = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-kotlin-serialization = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofitKotlinxSerializationJson" }
Expand All @@ -63,6 +68,10 @@ inject = "javax.inject:javax.inject:1"
kotest-runner = { group = "io.kotest", name = "kotest-runner-junit5", version.ref = "kotest" }
kotest-assertions = { group = "io.kotest", name = "kotest-assertions-core", version.ref = "kotest" }

coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutine" }
coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutine" }
coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutine" }

# verify
verify-detektFormatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }

Expand Down

0 comments on commit f0850d6

Please sign in to comment.