Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
# android-github-compose
# android-github-compose

### 1단계

- [x] κΆŒν•œ μ„€μ •, μ˜μ‘΄μ„± μΆ”κ°€
- [x] data νŒ¨ν‚€μ§€μ— μ €μž₯μ†Œ λͺ©λ‘μ„ κ°€μ Έμ˜€λŠ” μ½”λ“œ κ΅¬ν˜„
- [x] μˆ˜λ™ DI κ΅¬ν˜„
- [x] μ €μž₯μ†Œ λͺ©λ‘κ³Ό κ΄€λ ¨λœ ViewModel 생성
- [x] Activityμ—μ„œ λ‘œλ“œν•œ μ €μž₯μ†Œ λͺ©λ‘ Log둜 좜λ ₯ν•˜κΈ°
21 changes: 17 additions & 4 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlinSerialization)
}

android {
namespace = "nextstep.github"
compileSdk = 35
compileSdk = 36

defaultConfig {
applicationId = "nextstep.github"
minSdk = 26
targetSdk = 35
targetSdk = 36
versionCode = 1
versionName = "1.0"

Expand All @@ -34,8 +37,10 @@ android {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_17
}
}
buildFeatures {
compose = true
Expand All @@ -59,11 +64,19 @@ dependencies {
implementation(libs.androidx.material3)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.lifecycle.runtime.compose)

implementation(libs.kotlinx.serialization.json)
implementation(libs.retrofit2.kotlinx.serialization.converter)

implementation(libs.retrofit)
implementation(libs.okhttp3)

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)

debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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=".GithubApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand All @@ -15,7 +18,6 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Github">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/java/nextstep/github/GithubApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package nextstep.github

import android.app.Application
import nextstep.github.di.AppContainer

class GithubApplication: Application() {

val appContainer = AppContainer()
}
41 changes: 40 additions & 1 deletion app/src/main/java/nextstep/github/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nextstep.github

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
Expand All @@ -10,11 +11,35 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import nextstep.github.ui.theme.GithubTheme
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
import nextstep.github.di.AppContainer
import nextstep.github.di.RepositoryListContainer
import nextstep.github.presentation.repositorylist.RepositoryListViewModel
import nextstep.github.presentation.theme.GithubTheme

class MainActivity : ComponentActivity() {

private lateinit var viewModel: RepositoryListViewModel
private lateinit var appContainer: AppContainer

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setDi()

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.response.collect {
Log.d("Response", "$it")
}
}
}

viewModel.getRepositories()

setContent {
GithubTheme {
// A surface container using the 'background' color from the theme
Expand All @@ -27,6 +52,20 @@ class MainActivity : ComponentActivity() {
}
}
}

private fun setDi() {
appContainer = (application as GithubApplication).appContainer

appContainer.repositoryListContainer = RepositoryListContainer(appContainer.githubRepository)

viewModel = appContainer.repositoryListContainer!!.repositoryListViewModelFactory.create()
}

override fun onDestroy() {
appContainer.repositoryListContainer = null

super.onDestroy()
}
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package nextstep.github.data.datasource

import nextstep.github.data.model.RepositoryEntity

interface GithubRemoteDataSource {

suspend fun getRepositories(organization: String): List<RepositoryEntity>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package nextstep.github.data.datasource

import nextstep.github.data.model.RepositoryEntity
import nextstep.github.data.service.GithubService

class GithubRemoteDataSourceImpl(
private val service: GithubService,
): GithubRemoteDataSource {

override suspend fun getRepositories(organization: String): List<RepositoryEntity> {
return service.getRepositories(organization)
}
}
10 changes: 10 additions & 0 deletions app/src/main/java/nextstep/github/data/model/RepositoryEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package nextstep.github.data.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class RepositoryEntity(
@SerialName("full_name") val fullName: String?,
@SerialName("description") val description: String?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package nextstep.github.data.repository

import nextstep.github.data.model.RepositoryEntity

interface GithubRepository {

suspend fun getRepositories(organization: String): List<RepositoryEntity>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package nextstep.github.data.repository

import nextstep.github.data.datasource.GithubRemoteDataSource
import nextstep.github.data.model.RepositoryEntity

class GithubRepositoryImpl(
private val remoteDataSource: GithubRemoteDataSource,
): GithubRepository {

override suspend fun getRepositories(organization: String): List<RepositoryEntity> {
return remoteDataSource.getRepositories(organization)
}
}
11 changes: 11 additions & 0 deletions app/src/main/java/nextstep/github/data/service/GithubService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package nextstep.github.data.service

import nextstep.github.data.model.RepositoryEntity
import retrofit2.http.GET
import retrofit2.http.Path

interface GithubService {

@GET("orgs/{organization}/repos")
suspend fun getRepositories(@Path("organization") organization: String): List<RepositoryEntity>
}
33 changes: 33 additions & 0 deletions app/src/main/java/nextstep/github/di/AppContainer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package nextstep.github.di

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import nextstep.github.data.datasource.GithubRemoteDataSourceImpl
import nextstep.github.data.repository.GithubRepository
import nextstep.github.data.repository.GithubRepositoryImpl
import nextstep.github.data.service.GithubService
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import retrofit2.Retrofit

class AppContainer {

var repositoryListContainer: RepositoryListContainer? = null

private val serialization = Json { ignoreUnknownKeys = true }
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(OkHttpClient.Builder().build())
.addConverterFactory(serialization.asConverterFactory(CONTENT_TYPE.toMediaType()))
.build()

private val githubService = retrofit.create(GithubService::class.java)
private val githubRemoteDataSource = GithubRemoteDataSourceImpl(githubService)

val githubRepository: GithubRepository = GithubRepositoryImpl(githubRemoteDataSource)

companion object {
private const val CONTENT_TYPE = "application/json"
private const val BASE_URL = "https://api.github.com"
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/nextstep/github/di/Factory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package nextstep.github.di

import nextstep.github.data.repository.GithubRepository
import nextstep.github.presentation.repositorylist.RepositoryListViewModel

interface Factory<T> {
fun create(): T
}

class RepositoryListViewModelFactory(private val githubRepository: GithubRepository): Factory<RepositoryListViewModel> {

override fun create(): RepositoryListViewModel {
return RepositoryListViewModel(githubRepository)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package nextstep.github.di

import nextstep.github.data.repository.GithubRepository

class RepositoryListContainer(githubRepository: GithubRepository) {

val repositoryListViewModelFactory = RepositoryListViewModelFactory(githubRepository)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package nextstep.github.presentation.mapper

import nextstep.github.data.model.RepositoryEntity
import nextstep.github.presentation.repositorylist.Repository

fun RepositoryEntity.toUi(): Repository {
return Repository(
fullName = fullName ?: "",
description = description ?: "",
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package nextstep.github.presentation.repositorylist

data class Repository(
val fullName: String,
val description: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package nextstep.github.presentation.repositorylist

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import nextstep.github.data.repository.GithubRepository
import nextstep.github.presentation.mapper.toUi

class RepositoryListViewModel(
private val githubRepository: GithubRepository,
) : ViewModel() {

private val _response = MutableStateFlow<List<Repository>>(emptyList())
val response = _response.asStateFlow()

fun getRepositories() {
viewModelScope.launch {
val repositories = githubRepository.getRepositories(REPO_NAME).map {
it.toUi()
}
_response.update {
repositories
}
}
}

companion object {
private const val REPO_NAME = "next-step"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package nextstep.github.ui.theme
package nextstep.github.presentation.theme

import androidx.compose.ui.graphics.Color

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package nextstep.github.ui.theme
package nextstep.github.presentation.theme

import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package nextstep.github.ui.theme
package nextstep.github.presentation.theme

import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false
alias(libs.plugins.kotlinSerialization) apply false
}
Loading