From c939c8d7bce97db8bb63fa7ed32166c09b228ba5 Mon Sep 17 00:00:00 2001 From: OYJ Date: Sat, 7 Sep 2024 16:36:08 +0900 Subject: [PATCH 01/13] =?UTF-8?q?Refactor=20:=20MainScreen=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20stateful,=20stateless=20=EC=98=A4?= =?UTF-8?q?=EB=B2=84=EB=A1=9C=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. MainActivity에 있는 상태값들 stateful한 MainScreen 컴포넌트로 이동. --- .../main/java/nextstep/github/MainActivity.kt | 10 +--- .../github/ui/screen/github/MainScreen.kt | 51 ++++++++++++++----- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/nextstep/github/MainActivity.kt b/app/src/main/java/nextstep/github/MainActivity.kt index 497f8f1..bb4aff8 100644 --- a/app/src/main/java/nextstep/github/MainActivity.kt +++ b/app/src/main/java/nextstep/github/MainActivity.kt @@ -6,12 +6,8 @@ import androidx.activity.compose.setContent import androidx.activity.viewModels import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.lifecycle.compose.collectAsStateWithLifecycle import nextstep.github.ui.screen.github.MainScreen import nextstep.github.ui.theme.GithubTheme @@ -28,12 +24,8 @@ class MainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val snackbarHostState = remember { SnackbarHostState() } MainScreen( - uiState = uiState, - snackbarHostState = snackbarHostState, - onClickSnackBar = { viewModel.getRepositories("next-step") } + viewModel = viewModel ) } } diff --git a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt index 71fae95..c6cbbc6 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt @@ -2,29 +2,52 @@ package nextstep.github.ui.screen.github import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import nextstep.github.GithubViewModel import nextstep.github.R import nextstep.github.core.data.GithubRepositoryInfo import nextstep.github.ui.screen.github.component.MainTopBar import nextstep.github.ui.screen.github.list.GithubRepositoryUiState -import nextstep.github.ui.screen.github.list.component.ErrorSnackbar import nextstep.github.ui.screen.github.list.component.GithubRepositoryEmpty import nextstep.github.ui.screen.github.list.component.GithubRepositoryList import nextstep.github.ui.screen.github.list.component.LoadingProgress +@Composable +fun MainScreen( + viewModel: GithubViewModel = viewModel(), +) { + // stateful + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + MainScreen( + uiState = uiState, + snackbarHostState = snackbarHostState, + onClickSnackBar = { viewModel.getRepositories("next-step") } + ) +} + @Composable fun MainScreen( uiState: GithubRepositoryUiState = GithubRepositoryUiState.Loading, snackbarHostState: SnackbarHostState, onClickSnackBar: () -> Unit = {} ) { + // stateless Scaffold( - topBar = { MainTopBar() } + topBar = { MainTopBar() }, + snackbarHost = { SnackbarHost(hostState = snackbarHostState) } ) { paddingValues -> when (uiState) { @@ -37,18 +60,19 @@ fun MainScreen( is GithubRepositoryUiState.Error -> { // 에러 화면 - LoadingProgress( - modifier = Modifier.padding(paddingValues), - snackBar = { - ErrorSnackbar( - errorMessage = stringResource(id = R.string.text_snackbar_network_error), - actionString = stringResource(id = R.string.text_snackbar_action_retry), - snackbarHostState = snackbarHostState, - modifier = Modifier.padding(paddingValues), - onClickAction = { onClickSnackBar() } - ) + val errorMsg = stringResource(id = R.string.text_snackbar_network_error) + val actionLabel = stringResource(id = R.string.text_snackbar_action_retry) + + LaunchedEffect(snackbarHostState) { + val snackbarResult = snackbarHostState.showSnackbar( + message = errorMsg, + actionLabel = actionLabel, + ) + + if (snackbarResult == SnackbarResult.ActionPerformed) { + onClickSnackBar() } - ) + } } is GithubRepositoryUiState.Empty -> { @@ -69,6 +93,7 @@ fun MainScreen( } } + @Preview @Composable private fun LoadingMainScreenPreview() { From 19178dff354598fb0b25380e2a1ac7f919068ed3 Mon Sep 17 00:00:00 2001 From: OYJ Date: Sat, 7 Sep 2024 16:41:32 +0900 Subject: [PATCH 02/13] =?UTF-8?q?Refactor=20:=20Github=20Client=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. RepositoryEntity, GithubRepositoryInfo에 stars프로퍼티 추가. 2. 관련 코드 수정 --- app/src/main/java/nextstep/github/GithubViewModel.kt | 3 ++- .../github/core/data/GithubRepositoryInfo.kt | 1 + .../nextstep/github/core/model/RepositoryEntity.kt | 4 +++- .../nextstep/github/ui/screen/github/MainScreen.kt | 12 ++++++++---- .../github/list/component/GithubRepositoryList.kt | 12 ++++++++---- .../screen/github/list/component/RepositoryColumn.kt | 3 ++- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/nextstep/github/GithubViewModel.kt b/app/src/main/java/nextstep/github/GithubViewModel.kt index 01ade41..f8c0c08 100644 --- a/app/src/main/java/nextstep/github/GithubViewModel.kt +++ b/app/src/main/java/nextstep/github/GithubViewModel.kt @@ -34,7 +34,8 @@ class GithubViewModel( val githubRepositories = result.value.map { GithubRepositoryInfo( fullName = it.fullName ?: "", - description = it.description ?: "" + description = it.description ?: "", + stars = it.stars ?: 0 ) } if (githubRepositories.isEmpty()) { diff --git a/app/src/main/java/nextstep/github/core/data/GithubRepositoryInfo.kt b/app/src/main/java/nextstep/github/core/data/GithubRepositoryInfo.kt index c413ce7..ae8d73a 100644 --- a/app/src/main/java/nextstep/github/core/data/GithubRepositoryInfo.kt +++ b/app/src/main/java/nextstep/github/core/data/GithubRepositoryInfo.kt @@ -3,4 +3,5 @@ package nextstep.github.core.data data class GithubRepositoryInfo( val fullName: String, val description: String, + val stars: Int ) diff --git a/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt b/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt index 99462e9..0f679e1 100644 --- a/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt +++ b/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt @@ -8,9 +8,11 @@ import nextstep.github.core.data.GithubRepositoryInfo data class RepositoryEntity( @SerialName("full_name") val fullName: String?, @SerialName("description") val description: String?, + @SerialName("stargazers_count") val stars: Int?, ) { fun RepositoryEntity.toRepositoryInfo() = GithubRepositoryInfo( fullName = fullName ?: "", - description = description ?: "" + description = description ?: "", + stars = stars ?: 0 ) } diff --git a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt index c6cbbc6..497abf0 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt @@ -118,19 +118,23 @@ private fun SuccessMainScreenPreview() { val githubRepositoryList = listOf( GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 2 ), GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 20 ), GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 2 ), GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 3 ) ) diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/component/GithubRepositoryList.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/GithubRepositoryList.kt index b9383fc..64c6f55 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/component/GithubRepositoryList.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/GithubRepositoryList.kt @@ -30,19 +30,23 @@ private fun GithubRepositoryListPreview() { val githubRepositoryList = listOf( GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 3 ), GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 2 ), GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 20 ), GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 2 ) ) diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt index 757d502..90c248b 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt @@ -46,7 +46,8 @@ private fun RepositoryColumnPreview() { RepositoryColumn( repositoryInfo = GithubRepositoryInfo( fullName = "next-step/nextstep-study", - description = "코드숨과 함께하는 NextStep" + description = "코드숨과 함께하는 NextStep", + stars = 3 ) ) } From c2eb2e0afc82a0867d9df892344f40d8a047b827 Mon Sep 17 00:00:00 2001 From: OYJ Date: Sat, 7 Sep 2024 16:47:23 +0900 Subject: [PATCH 03/13] =?UTF-8?q?Chore=20:=20README.md=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Step3 완료 체크 2. Step4 프로그래밍 요구사항 및 기능 요구사항 작성 --- README.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 46bbfe5..942b1ff 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,17 @@ - 로딩 UI를 노출할 때 CircularProgressIndicator를 활용한다. ## 기능 요구사항 -- [] 목록이 로딩되기 전에는 로딩 UI를 노출한다. -- [] 목록이 빈 경우에는 빈 화면 UI를 노출한다. -- [] 오류가 발생한 경우 재시도 가능한 스낵바를 노출한다. +- [O] 목록이 로딩되기 전에는 로딩 UI를 노출한다. +- [O] 목록이 빈 경우에는 빈 화면 UI를 노출한다. +- [O] 오류가 발생한 경우 재시도 가능한 스낵바를 노출한다. + +# Step 4 - GitHub(인기 저장소) + +## 프로그래밍 요구사항 + - domain 패키지를 만들어 비즈니스 로직을 캡슐화한다. + - 저장소의 Star 개수가 50개 이상인지 판단하는 로직도 도메인 레이어에 포함될지 스스로 판단한다. + +## 기능 요구사항 +- [] 저장소의 Star 개수를 노출한다 +- [] 저장소의 Star 개수가 50개 이상이면 HOT 텍스트를 노출한다. + From 350adaae8b76b04f35e60221d9d8cbc14731441e Mon Sep 17 00:00:00 2001 From: OYJ Date: Sat, 7 Sep 2024 17:44:31 +0900 Subject: [PATCH 04/13] =?UTF-8?q?Feat=20:=20=EA=B9=83=ED=97=88=EB=B8=8C=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=EC=86=8C=20star=20=ED=91=9C=EC=8B=9C=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 저장소 칼럼 헤더에 Star 개수 노출 2. Star 개수 50개 이상일 시 HOT 문구 노출 --- .../github/list/component/RepositoryColumn.kt | 10 +++ .../list/component/RopositoryColoumnHeader.kt | 62 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 + 3 files changed, 74 insertions(+) create mode 100644 app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt index 90c248b..77b126c 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt @@ -2,15 +2,23 @@ package nextstep.github.ui.screen.github.list.component import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Star import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import nextstep.github.R import nextstep.github.core.data.GithubRepositoryInfo @Composable @@ -20,6 +28,8 @@ fun RepositoryColumn(repositoryInfo: GithubRepositoryInfo, modifier: Modifier = .padding(vertical = 16.dp) .fillMaxWidth() ) { + RepositoryColumnHeader(repositoryInfo = repositoryInfo) + Text( text = repositoryInfo.fullName, style = MaterialTheme.typography.titleLarge, diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt new file mode 100644 index 0000000..7619f77 --- /dev/null +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt @@ -0,0 +1,62 @@ +package nextstep.github.ui.screen.github.list.component + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Star +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import nextstep.github.R +import nextstep.github.core.data.GithubRepositoryInfo + +@Composable +fun RepositoryColumnHeader( + repositoryInfo: GithubRepositoryInfo, + modifier: Modifier = Modifier +) { + Row( + modifier = Modifier + .padding(horizontal = 16.dp) + ) { + if(repositoryInfo.stars > 50) { + Text( + modifier = Modifier.align(Alignment.CenterVertically), + text = stringResource(id = R.string.text_hot), + style = MaterialTheme.typography.labelLarge, + ) + } + + Spacer(modifier = Modifier.weight(1f)) + + Icon( + imageVector = Icons.Filled.Star, + contentDescription = stringResource(id = R.string.text_description_repository_star_icon) + ) + + Text( + modifier = Modifier.align(Alignment.CenterVertically), + text = "${repositoryInfo.stars}", + style = MaterialTheme.typography.labelLarge, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun RepositoryColumnHeaderPreview() { + RepositoryColumnHeader( + repositoryInfo = GithubRepositoryInfo( + fullName = "next-step/nextstep-study", + description = "코드숨과 함께하는 NextStep", + stars = 32 + ) + ) +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c35dba8..1067507 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,4 +4,6 @@ 목록이 비었습니다. 예상치 못한 오류가 발생했습니다 재시도 + HOT + NEW From 00f675960ae0f56499106e2b4e9e9ba72a7baeeb Mon Sep 17 00:00:00 2001 From: OYJ Date: Sat, 7 Sep 2024 17:47:43 +0900 Subject: [PATCH 05/13] =?UTF-8?q?Chore=20:=20README.md=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 저장소 Star 개수 노출 2. 저장소 Star 개수 50개 이상 시 HOT 텍스트 노출 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 942b1ff..acd8612 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,6 @@ - 저장소의 Star 개수가 50개 이상인지 판단하는 로직도 도메인 레이어에 포함될지 스스로 판단한다. ## 기능 요구사항 -- [] 저장소의 Star 개수를 노출한다 -- [] 저장소의 Star 개수가 50개 이상이면 HOT 텍스트를 노출한다. +- [O] 저장소의 Star 개수를 노출한다 +- [O] 저장소의 Star 개수가 50개 이상이면 HOT 텍스트를 노출한다. From d37ccdc303b7e3faf7ec378e211af2ad0becd70e Mon Sep 17 00:00:00 2001 From: OYJ Date: Mon, 9 Sep 2024 11:20:29 +0900 Subject: [PATCH 06/13] =?UTF-8?q?Refactor=20:=20=EB=B9=84=EC=A6=88?= =?UTF-8?q?=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. domain 패키지 생성 2. GithubViewModel 파리미터 변경 (저장소 -> 유즈케이스) 3. GetGithubRepoUseCase 구현 --- .../java/nextstep/github/GithubViewModel.kt | 22 ++++++---------- .../github/core/data/GithubRepository.kt | 4 +-- .../github/core/data/GithubRepositoryImpl.kt | 12 +++------ .../github/core/model/RepositoryEntity.kt | 8 +----- .../domain/usecase/GetGithubRepoUseCase.kt | 26 +++++++++++++++++++ 5 files changed, 40 insertions(+), 32 deletions(-) create mode 100644 app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt diff --git a/app/src/main/java/nextstep/github/GithubViewModel.kt b/app/src/main/java/nextstep/github/GithubViewModel.kt index f8c0c08..116bcf2 100644 --- a/app/src/main/java/nextstep/github/GithubViewModel.kt +++ b/app/src/main/java/nextstep/github/GithubViewModel.kt @@ -11,13 +11,12 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import nextstep.github.core.data.GithubRepository -import nextstep.github.core.data.GithubRepositoryInfo import nextstep.github.core.network.ApiResult +import nextstep.github.domain.usecase.GetGithubRepoUseCase import nextstep.github.ui.screen.github.list.GithubRepositoryUiState class GithubViewModel( - private val githubRepository: GithubRepository + private val getGithubRepoUseCase: GetGithubRepoUseCase ) : ViewModel() { private val _uiState = @@ -29,21 +28,14 @@ class GithubViewModel( viewModelScope.launch(Dispatchers.IO) { try { - when (val result = githubRepository.getRepositories(organization)) { + when (val result = getGithubRepoUseCase(organization)) { is ApiResult.Success -> { - val githubRepositories = result.value.map { - GithubRepositoryInfo( - fullName = it.fullName ?: "", - description = it.description ?: "", - stars = it.stars ?: 0 - ) - } - if (githubRepositories.isEmpty()) { + if (result.value.isEmpty()) { _uiState.value = GithubRepositoryUiState.Empty } else { _uiState.value = GithubRepositoryUiState.Success( - githubRepositories = githubRepositories + githubRepositories = result.value ) } } @@ -68,7 +60,9 @@ class GithubViewModel( .appContainer .githubRepository - GithubViewModel(githubRepository) + val getGithubRepoUseCase = GetGithubRepoUseCase(githubRepository) + + GithubViewModel(getGithubRepoUseCase) } } } diff --git a/app/src/main/java/nextstep/github/core/data/GithubRepository.kt b/app/src/main/java/nextstep/github/core/data/GithubRepository.kt index 106f6fe..262577a 100644 --- a/app/src/main/java/nextstep/github/core/data/GithubRepository.kt +++ b/app/src/main/java/nextstep/github/core/data/GithubRepository.kt @@ -1,9 +1,9 @@ package nextstep.github.core.data import nextstep.github.core.model.RepositoryEntity -import nextstep.github.core.network.ApiResult +import retrofit2.Response interface GithubRepository { - suspend fun getRepositories(organization: String): ApiResult> + suspend fun getRepositories(organization: String): Response> } diff --git a/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt b/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt index d06b4b8..bbe05b8 100644 --- a/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt +++ b/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt @@ -1,20 +1,14 @@ package nextstep.github.core.data import nextstep.github.core.model.RepositoryEntity -import nextstep.github.core.network.ApiResult import nextstep.github.core.network.GithubService +import retrofit2.Response class GithubRepositoryImpl( private val githubService: GithubService ) : GithubRepository { - override suspend fun getRepositories(organization: String): ApiResult> { - val response = githubService.getRepositories(organization) - - return if (response.isSuccessful && response.body() != null) { - ApiResult.Success(response.body()!!) - } else { - ApiResult.Error(response.code(), Throwable(response.message())) - } + override suspend fun getRepositories(organization: String): Response> { + return githubService.getRepositories(organization) } } diff --git a/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt b/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt index 0f679e1..0b47923 100644 --- a/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt +++ b/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt @@ -9,10 +9,4 @@ data class RepositoryEntity( @SerialName("full_name") val fullName: String?, @SerialName("description") val description: String?, @SerialName("stargazers_count") val stars: Int?, -) { - fun RepositoryEntity.toRepositoryInfo() = GithubRepositoryInfo( - fullName = fullName ?: "", - description = description ?: "", - stars = stars ?: 0 - ) -} +) diff --git a/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt b/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt new file mode 100644 index 0000000..748515a --- /dev/null +++ b/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt @@ -0,0 +1,26 @@ +package nextstep.github.domain.usecase + +import nextstep.github.core.data.GithubRepository +import nextstep.github.core.data.GithubRepositoryInfo +import nextstep.github.core.network.ApiResult + +class GetGithubRepoUseCase( + private val githubRepository: GithubRepository +) { + suspend operator fun invoke(organization: String): ApiResult> { + val response = githubRepository.getRepositories(organization) + + return if (response.isSuccessful && response.body() != null) { + val githubRepositoryInfoList = response.body()!!.map { + GithubRepositoryInfo( + fullName = it.fullName ?: "", + description = it.description ?: "", + stars = it.stars ?: 0 + ) + } + ApiResult.Success(githubRepositoryInfoList) + } else { + ApiResult.Error(response.code(), Throwable(response.message())) + } + } +} From e582fb8db55046a59ebcfbe7ca695af1b028d52c Mon Sep 17 00:00:00 2001 From: OYJ Date: Mon, 9 Sep 2024 11:26:47 +0900 Subject: [PATCH 07/13] =?UTF-8?q?Rename=20:=20data=20=EB=B0=8F=20domain=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=EC=9D=98=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. RepositoryEntity -> GithubRepositoryData (data 패키지) 2. GithubRepositoryInfo -> RepositoryEntity (domain 패키지) --- .../github/core/data/GithubRepository.kt | 4 ++-- .../github/core/data/GithubRepositoryImpl.kt | 4 ++-- ...sitoryEntity.kt => GithubRepositoryData.kt} | 3 +-- .../github/core/network/GithubService.kt | 4 ++-- .../entity/RepositoryEntity.kt} | 4 ++-- .../domain/usecase/GetGithubRepoUseCase.kt | 10 +++++----- .../github/ui/screen/github/MainScreen.kt | 12 ++++++------ .../github/list/GithubRepositoryUiState.kt | 4 ++-- .../list/component/GithubRepositoryList.kt | 18 +++++++++--------- .../github/list/component/RepositoryColumn.kt | 14 +++----------- .../list/component/RopositoryColoumnHeader.kt | 6 +++--- 11 files changed, 37 insertions(+), 46 deletions(-) rename app/src/main/java/nextstep/github/core/model/{RepositoryEntity.kt => GithubRepositoryData.kt} (78%) rename app/src/main/java/nextstep/github/{core/data/GithubRepositoryInfo.kt => domain/entity/RepositoryEntity.kt} (53%) diff --git a/app/src/main/java/nextstep/github/core/data/GithubRepository.kt b/app/src/main/java/nextstep/github/core/data/GithubRepository.kt index 262577a..ea12dc1 100644 --- a/app/src/main/java/nextstep/github/core/data/GithubRepository.kt +++ b/app/src/main/java/nextstep/github/core/data/GithubRepository.kt @@ -1,9 +1,9 @@ package nextstep.github.core.data -import nextstep.github.core.model.RepositoryEntity +import nextstep.github.core.model.GithubRepositoryData import retrofit2.Response interface GithubRepository { - suspend fun getRepositories(organization: String): Response> + suspend fun getRepositories(organization: String): Response> } diff --git a/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt b/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt index bbe05b8..ddfcc63 100644 --- a/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt +++ b/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt @@ -1,6 +1,6 @@ package nextstep.github.core.data -import nextstep.github.core.model.RepositoryEntity +import nextstep.github.core.model.GithubRepositoryData import nextstep.github.core.network.GithubService import retrofit2.Response @@ -8,7 +8,7 @@ class GithubRepositoryImpl( private val githubService: GithubService ) : GithubRepository { - override suspend fun getRepositories(organization: String): Response> { + override suspend fun getRepositories(organization: String): Response> { return githubService.getRepositories(organization) } } diff --git a/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt b/app/src/main/java/nextstep/github/core/model/GithubRepositoryData.kt similarity index 78% rename from app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt rename to app/src/main/java/nextstep/github/core/model/GithubRepositoryData.kt index 0b47923..84bed10 100644 --- a/app/src/main/java/nextstep/github/core/model/RepositoryEntity.kt +++ b/app/src/main/java/nextstep/github/core/model/GithubRepositoryData.kt @@ -2,10 +2,9 @@ package nextstep.github.core.model import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import nextstep.github.core.data.GithubRepositoryInfo @Serializable -data class RepositoryEntity( +data class GithubRepositoryData( @SerialName("full_name") val fullName: String?, @SerialName("description") val description: String?, @SerialName("stargazers_count") val stars: Int?, diff --git a/app/src/main/java/nextstep/github/core/network/GithubService.kt b/app/src/main/java/nextstep/github/core/network/GithubService.kt index 9177785..e76fd64 100644 --- a/app/src/main/java/nextstep/github/core/network/GithubService.kt +++ b/app/src/main/java/nextstep/github/core/network/GithubService.kt @@ -1,6 +1,6 @@ package nextstep.github.core.network -import nextstep.github.core.model.RepositoryEntity +import nextstep.github.core.model.GithubRepositoryData import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path @@ -8,5 +8,5 @@ import retrofit2.http.Path interface GithubService { @GET("orgs/{organization}/repos") - suspend fun getRepositories(@Path("organization") organization: String): Response> + suspend fun getRepositories(@Path("organization") organization: String): Response> } diff --git a/app/src/main/java/nextstep/github/core/data/GithubRepositoryInfo.kt b/app/src/main/java/nextstep/github/domain/entity/RepositoryEntity.kt similarity index 53% rename from app/src/main/java/nextstep/github/core/data/GithubRepositoryInfo.kt rename to app/src/main/java/nextstep/github/domain/entity/RepositoryEntity.kt index ae8d73a..de6637e 100644 --- a/app/src/main/java/nextstep/github/core/data/GithubRepositoryInfo.kt +++ b/app/src/main/java/nextstep/github/domain/entity/RepositoryEntity.kt @@ -1,6 +1,6 @@ -package nextstep.github.core.data +package nextstep.github.domain.entity -data class GithubRepositoryInfo( +data class RepositoryEntity( val fullName: String, val description: String, val stars: Int diff --git a/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt b/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt index 748515a..8d5a1fd 100644 --- a/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt +++ b/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt @@ -1,24 +1,24 @@ package nextstep.github.domain.usecase import nextstep.github.core.data.GithubRepository -import nextstep.github.core.data.GithubRepositoryInfo +import nextstep.github.domain.entity.RepositoryEntity import nextstep.github.core.network.ApiResult class GetGithubRepoUseCase( private val githubRepository: GithubRepository ) { - suspend operator fun invoke(organization: String): ApiResult> { + suspend operator fun invoke(organization: String): ApiResult> { val response = githubRepository.getRepositories(organization) return if (response.isSuccessful && response.body() != null) { - val githubRepositoryInfoList = response.body()!!.map { - GithubRepositoryInfo( + val repositoryEntityList = response.body()!!.map { + RepositoryEntity( fullName = it.fullName ?: "", description = it.description ?: "", stars = it.stars ?: 0 ) } - ApiResult.Success(githubRepositoryInfoList) + ApiResult.Success(repositoryEntityList) } else { ApiResult.Error(response.code(), Throwable(response.message())) } diff --git a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt index 497abf0..55437ec 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt @@ -16,7 +16,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import nextstep.github.GithubViewModel import nextstep.github.R -import nextstep.github.core.data.GithubRepositoryInfo +import nextstep.github.domain.entity.RepositoryEntity import nextstep.github.ui.screen.github.component.MainTopBar import nextstep.github.ui.screen.github.list.GithubRepositoryUiState import nextstep.github.ui.screen.github.list.component.GithubRepositoryEmpty @@ -83,7 +83,7 @@ fun MainScreen( is GithubRepositoryUiState.Success -> { GithubRepositoryList( - githubRepositoryInfoList = uiState.githubRepositories, + repositoryEntityList = uiState.githubRepositories, modifier = Modifier.padding(paddingValues) ) } @@ -116,22 +116,22 @@ private fun EmptyMainScreenPreview() { @Composable private fun SuccessMainScreenPreview() { val githubRepositoryList = listOf( - GithubRepositoryInfo( + RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 2 ), - GithubRepositoryInfo( + RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 20 ), - GithubRepositoryInfo( + RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 2 ), - GithubRepositoryInfo( + RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 3 diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/GithubRepositoryUiState.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/GithubRepositoryUiState.kt index fec92ba..ba3fd03 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/GithubRepositoryUiState.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/GithubRepositoryUiState.kt @@ -1,6 +1,6 @@ package nextstep.github.ui.screen.github.list -import nextstep.github.core.data.GithubRepositoryInfo +import nextstep.github.domain.entity.RepositoryEntity sealed class GithubRepositoryUiState { @@ -10,6 +10,6 @@ sealed class GithubRepositoryUiState { data object Empty : GithubRepositoryUiState() - data class Success(val githubRepositories: List) : + data class Success(val githubRepositories: List) : GithubRepositoryUiState() } diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/component/GithubRepositoryList.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/GithubRepositoryList.kt index 64c6f55..f37b7d3 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/component/GithubRepositoryList.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/GithubRepositoryList.kt @@ -5,19 +5,19 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import nextstep.github.core.data.GithubRepositoryInfo +import nextstep.github.domain.entity.RepositoryEntity @Composable fun GithubRepositoryList( - githubRepositoryInfoList: List, + repositoryEntityList: List, modifier: Modifier = Modifier ) { LazyColumn( modifier = modifier.fillMaxWidth() ) { - items(githubRepositoryInfoList.size) { + items(repositoryEntityList.size) { RepositoryColumn( - repositoryInfo = githubRepositoryInfoList[it], + repositoryInfo = repositoryEntityList[it], modifier = Modifier ) } @@ -28,22 +28,22 @@ fun GithubRepositoryList( @Composable private fun GithubRepositoryListPreview() { val githubRepositoryList = listOf( - GithubRepositoryInfo( + RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 3 ), - GithubRepositoryInfo( + RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 2 ), - GithubRepositoryInfo( + RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 20 ), - GithubRepositoryInfo( + RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 2 @@ -51,7 +51,7 @@ private fun GithubRepositoryListPreview() { ) GithubRepositoryList( - githubRepositoryInfoList = githubRepositoryList, + repositoryEntityList = githubRepositoryList, modifier = Modifier ) } diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt index 77b126c..0afe8ec 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RepositoryColumn.kt @@ -2,27 +2,19 @@ package nextstep.github.ui.screen.github.list.component import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Star import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import nextstep.github.R -import nextstep.github.core.data.GithubRepositoryInfo +import nextstep.github.domain.entity.RepositoryEntity @Composable -fun RepositoryColumn(repositoryInfo: GithubRepositoryInfo, modifier: Modifier = Modifier) { +fun RepositoryColumn(repositoryInfo: RepositoryEntity, modifier: Modifier = Modifier) { Column( modifier = modifier .padding(vertical = 16.dp) @@ -54,7 +46,7 @@ fun RepositoryColumn(repositoryInfo: GithubRepositoryInfo, modifier: Modifier = @Composable private fun RepositoryColumnPreview() { RepositoryColumn( - repositoryInfo = GithubRepositoryInfo( + repositoryInfo = RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 3 diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt index 7619f77..08e3701 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt @@ -15,11 +15,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import nextstep.github.R -import nextstep.github.core.data.GithubRepositoryInfo +import nextstep.github.domain.entity.RepositoryEntity @Composable fun RepositoryColumnHeader( - repositoryInfo: GithubRepositoryInfo, + repositoryInfo: RepositoryEntity, modifier: Modifier = Modifier ) { Row( @@ -53,7 +53,7 @@ fun RepositoryColumnHeader( @Composable private fun RepositoryColumnHeaderPreview() { RepositoryColumnHeader( - repositoryInfo = GithubRepositoryInfo( + repositoryInfo = RepositoryEntity( fullName = "next-step/nextstep-study", description = "코드숨과 함께하는 NextStep", stars = 32 From 5ebe4fd29ae4368f8ac6b42fbc6e9677228c6bfc Mon Sep 17 00:00:00 2001 From: OYJ Date: Mon, 9 Sep 2024 11:34:39 +0900 Subject: [PATCH 08/13] =?UTF-8?q?Rename=20:=20data=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. core 패키지를 data패키지, di패키지로 분리 --- app/src/main/AndroidManifest.xml | 2 +- app/src/main/java/nextstep/github/MainActivity.kt | 1 + .../github/{core => data}/model/GithubRepositoryData.kt | 2 +- .../nextstep/github/{core => data}/network/ApiResult.kt | 2 +- .../github/{core => data}/network/GithubService.kt | 4 ++-- .../{core/data => data/repository}/GithubRepository.kt | 4 ++-- .../data => data/repository}/GithubRepositoryImpl.kt | 6 +++--- .../java/nextstep/github/{core => }/di/AppContainer.kt | 8 ++++---- .../main/java/nextstep/github/{ => di}/MainApplication.kt | 3 +-- .../github/domain/usecase/GetGithubRepoUseCase.kt | 4 ++-- .../github/{ => ui/screen/github}/GithubViewModel.kt | 5 +++-- .../java/nextstep/github/ui/screen/github/MainScreen.kt | 1 - 12 files changed, 21 insertions(+), 21 deletions(-) rename app/src/main/java/nextstep/github/{core => data}/model/GithubRepositoryData.kt (89%) rename app/src/main/java/nextstep/github/{core => data}/network/ApiResult.kt (84%) rename app/src/main/java/nextstep/github/{core => data}/network/GithubService.kt (74%) rename app/src/main/java/nextstep/github/{core/data => data/repository}/GithubRepository.kt (61%) rename app/src/main/java/nextstep/github/{core/data => data/repository}/GithubRepositoryImpl.kt (67%) rename app/src/main/java/nextstep/github/{core => }/di/AppContainer.kt (87%) rename app/src/main/java/nextstep/github/{ => di}/MainApplication.kt (62%) rename app/src/main/java/nextstep/github/{ => ui/screen/github}/GithubViewModel.kt (95%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 43ee14d..3e3c532 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Github" - android:name="MainApplication" + android:name=".di.MainApplication" tools:targetApi="31"> { data class Success(val value: T) : ApiResult() diff --git a/app/src/main/java/nextstep/github/core/network/GithubService.kt b/app/src/main/java/nextstep/github/data/network/GithubService.kt similarity index 74% rename from app/src/main/java/nextstep/github/core/network/GithubService.kt rename to app/src/main/java/nextstep/github/data/network/GithubService.kt index e76fd64..10dd131 100644 --- a/app/src/main/java/nextstep/github/core/network/GithubService.kt +++ b/app/src/main/java/nextstep/github/data/network/GithubService.kt @@ -1,6 +1,6 @@ -package nextstep.github.core.network +package nextstep.github.data.network -import nextstep.github.core.model.GithubRepositoryData +import nextstep.github.data.model.GithubRepositoryData import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path diff --git a/app/src/main/java/nextstep/github/core/data/GithubRepository.kt b/app/src/main/java/nextstep/github/data/repository/GithubRepository.kt similarity index 61% rename from app/src/main/java/nextstep/github/core/data/GithubRepository.kt rename to app/src/main/java/nextstep/github/data/repository/GithubRepository.kt index ea12dc1..b570fbb 100644 --- a/app/src/main/java/nextstep/github/core/data/GithubRepository.kt +++ b/app/src/main/java/nextstep/github/data/repository/GithubRepository.kt @@ -1,6 +1,6 @@ -package nextstep.github.core.data +package nextstep.github.data.repository -import nextstep.github.core.model.GithubRepositoryData +import nextstep.github.data.model.GithubRepositoryData import retrofit2.Response diff --git a/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt b/app/src/main/java/nextstep/github/data/repository/GithubRepositoryImpl.kt similarity index 67% rename from app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt rename to app/src/main/java/nextstep/github/data/repository/GithubRepositoryImpl.kt index ddfcc63..e1379f4 100644 --- a/app/src/main/java/nextstep/github/core/data/GithubRepositoryImpl.kt +++ b/app/src/main/java/nextstep/github/data/repository/GithubRepositoryImpl.kt @@ -1,7 +1,7 @@ -package nextstep.github.core.data +package nextstep.github.data.repository -import nextstep.github.core.model.GithubRepositoryData -import nextstep.github.core.network.GithubService +import nextstep.github.data.model.GithubRepositoryData +import nextstep.github.data.network.GithubService import retrofit2.Response class GithubRepositoryImpl( diff --git a/app/src/main/java/nextstep/github/core/di/AppContainer.kt b/app/src/main/java/nextstep/github/di/AppContainer.kt similarity index 87% rename from app/src/main/java/nextstep/github/core/di/AppContainer.kt rename to app/src/main/java/nextstep/github/di/AppContainer.kt index e0b2975..530a090 100644 --- a/app/src/main/java/nextstep/github/core/di/AppContainer.kt +++ b/app/src/main/java/nextstep/github/di/AppContainer.kt @@ -1,10 +1,10 @@ -package nextstep.github.core.di +package nextstep.github.di import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import kotlinx.serialization.json.Json -import nextstep.github.core.data.GithubRepository -import nextstep.github.core.data.GithubRepositoryImpl -import nextstep.github.core.network.GithubService +import nextstep.github.data.repository.GithubRepository +import nextstep.github.data.repository.GithubRepositoryImpl +import nextstep.github.data.network.GithubService import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor diff --git a/app/src/main/java/nextstep/github/MainApplication.kt b/app/src/main/java/nextstep/github/di/MainApplication.kt similarity index 62% rename from app/src/main/java/nextstep/github/MainApplication.kt rename to app/src/main/java/nextstep/github/di/MainApplication.kt index 0cce1f9..91156bd 100644 --- a/app/src/main/java/nextstep/github/MainApplication.kt +++ b/app/src/main/java/nextstep/github/di/MainApplication.kt @@ -1,7 +1,6 @@ -package nextstep.github +package nextstep.github.di import android.app.Application -import nextstep.github.core.di.AppContainer class MainApplication : Application() { diff --git a/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt b/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt index 8d5a1fd..fb40eae 100644 --- a/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt +++ b/app/src/main/java/nextstep/github/domain/usecase/GetGithubRepoUseCase.kt @@ -1,8 +1,8 @@ package nextstep.github.domain.usecase -import nextstep.github.core.data.GithubRepository +import nextstep.github.data.repository.GithubRepository import nextstep.github.domain.entity.RepositoryEntity -import nextstep.github.core.network.ApiResult +import nextstep.github.data.network.ApiResult class GetGithubRepoUseCase( private val githubRepository: GithubRepository diff --git a/app/src/main/java/nextstep/github/GithubViewModel.kt b/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt similarity index 95% rename from app/src/main/java/nextstep/github/GithubViewModel.kt rename to app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt index 116bcf2..24ae3a1 100644 --- a/app/src/main/java/nextstep/github/GithubViewModel.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt @@ -1,4 +1,4 @@ -package nextstep.github +package nextstep.github.ui.screen.github import android.util.Log import androidx.lifecycle.ViewModel @@ -11,7 +11,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import nextstep.github.core.network.ApiResult +import nextstep.github.di.MainApplication +import nextstep.github.data.network.ApiResult import nextstep.github.domain.usecase.GetGithubRepoUseCase import nextstep.github.ui.screen.github.list.GithubRepositoryUiState diff --git a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt index 55437ec..647453b 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt @@ -14,7 +14,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import nextstep.github.GithubViewModel import nextstep.github.R import nextstep.github.domain.entity.RepositoryEntity import nextstep.github.ui.screen.github.component.MainTopBar From ccf05ddca072fec23a025faf9f5a07b60eca75f8 Mon Sep 17 00:00:00 2001 From: OYJ Date: Mon, 9 Sep 2024 14:16:45 +0900 Subject: [PATCH 09/13] =?UTF-8?q?Rename=20:=20MainTopBar=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. github.component -> gihub.list.component --- .../main/java/nextstep/github/ui/screen/github/MainScreen.kt | 2 +- .../github/ui/screen/github/{ => list}/component/MainTopBar.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/src/main/java/nextstep/github/ui/screen/github/{ => list}/component/MainTopBar.kt (93%) diff --git a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt index 647453b..0df314e 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt @@ -16,7 +16,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import nextstep.github.R import nextstep.github.domain.entity.RepositoryEntity -import nextstep.github.ui.screen.github.component.MainTopBar +import nextstep.github.ui.screen.github.list.component.MainTopBar import nextstep.github.ui.screen.github.list.GithubRepositoryUiState import nextstep.github.ui.screen.github.list.component.GithubRepositoryEmpty import nextstep.github.ui.screen.github.list.component.GithubRepositoryList diff --git a/app/src/main/java/nextstep/github/ui/screen/github/component/MainTopBar.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/MainTopBar.kt similarity index 93% rename from app/src/main/java/nextstep/github/ui/screen/github/component/MainTopBar.kt rename to app/src/main/java/nextstep/github/ui/screen/github/list/component/MainTopBar.kt index e272285..c023e15 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/component/MainTopBar.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/MainTopBar.kt @@ -1,4 +1,4 @@ -package nextstep.github.ui.screen.github.component +package nextstep.github.ui.screen.github.list.component import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.ExperimentalMaterial3Api From 76bc4846e9b2905daace18154348489fb90fef86 Mon Sep 17 00:00:00 2001 From: OYJ Date: Wed, 11 Sep 2024 11:30:49 +0900 Subject: [PATCH 10/13] =?UTF-8?q?Refactor=20:=20=EC=8A=A4=EB=82=B5?= =?UTF-8?q?=EB=B0=94=20=ED=81=B4=EB=A6=AD=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 사용자 행동 -> 로직의 동작에 초점을 맞춤 2. onClickSnackBar -> onRetry --- .../java/nextstep/github/ui/screen/github/MainScreen.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt index 0df314e..1a2326f 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt @@ -33,7 +33,7 @@ fun MainScreen( MainScreen( uiState = uiState, snackbarHostState = snackbarHostState, - onClickSnackBar = { viewModel.getRepositories("next-step") } + onRetry = { viewModel.getRepositories("next-step") } ) } @@ -41,7 +41,7 @@ fun MainScreen( fun MainScreen( uiState: GithubRepositoryUiState = GithubRepositoryUiState.Loading, snackbarHostState: SnackbarHostState, - onClickSnackBar: () -> Unit = {} + onRetry: () -> Unit = {} ) { // stateless Scaffold( @@ -69,7 +69,7 @@ fun MainScreen( ) if (snackbarResult == SnackbarResult.ActionPerformed) { - onClickSnackBar() + onRetry() } } } From a385f58bbcba5f358481651fa24ccf680d1bd2fe Mon Sep 17 00:00:00 2001 From: OYJ Date: Wed, 11 Sep 2024 12:08:04 +0900 Subject: [PATCH 11/13] =?UTF-8?q?Refactor=20:=20HOT=20=EB=AC=B8=EA=B5=AC?= =?UTF-8?q?=20=EB=85=B8=EC=B6=9C=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. view에서 data로 로직 이동 2. 멤버변수 isHot을 사용하여 노출 여부 판단 --- .../nextstep/github/domain/entity/RepositoryEntity.kt | 8 +++++++- .../github/list/component/RopositoryColoumnHeader.kt | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nextstep/github/domain/entity/RepositoryEntity.kt b/app/src/main/java/nextstep/github/domain/entity/RepositoryEntity.kt index de6637e..100ebbd 100644 --- a/app/src/main/java/nextstep/github/domain/entity/RepositoryEntity.kt +++ b/app/src/main/java/nextstep/github/domain/entity/RepositoryEntity.kt @@ -4,4 +4,10 @@ data class RepositoryEntity( val fullName: String, val description: String, val stars: Int -) +) { + val isHot: Boolean by lazy { stars > HOT_COUNT } + + companion object { + private const val HOT_COUNT = 50 + } +} diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt index 08e3701..3cf8e9c 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/component/RopositoryColoumnHeader.kt @@ -26,7 +26,7 @@ fun RepositoryColumnHeader( modifier = Modifier .padding(horizontal = 16.dp) ) { - if(repositoryInfo.stars > 50) { + if(repositoryInfo.isHot) { Text( modifier = Modifier.align(Alignment.CenterVertically), text = stringResource(id = R.string.text_hot), From d7c7023eb130c67a197df0b83181926f4a449eb2 Mon Sep 17 00:00:00 2001 From: OYJ Date: Thu, 12 Sep 2024 00:22:35 +0900 Subject: [PATCH 12/13] =?UTF-8?q?Fix=20:=20=EC=9E=AC=EC=8B=9C=EB=8F=84=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=EC=97=90=20=EB=94=B0=EB=A5=B8=20uiState=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. delay를 추가하여 상태변경을 놓치는 경우를 방지함. --- .../nextstep/github/ui/screen/github/GithubViewModel.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt b/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt index 24ae3a1..5aa842b 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt @@ -8,11 +8,12 @@ import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import nextstep.github.di.MainApplication import nextstep.github.data.network.ApiResult +import nextstep.github.di.MainApplication import nextstep.github.domain.usecase.GetGithubRepoUseCase import nextstep.github.ui.screen.github.list.GithubRepositoryUiState @@ -25,10 +26,11 @@ class GithubViewModel( val uiState: StateFlow = _uiState fun getRepositories(organization: String) { - _uiState.value = GithubRepositoryUiState.Loading viewModelScope.launch(Dispatchers.IO) { try { + _uiState.value = GithubRepositoryUiState.Loading + delay(300) when (val result = getGithubRepoUseCase(organization)) { is ApiResult.Success -> { if (result.value.isEmpty()) { @@ -53,6 +55,9 @@ class GithubViewModel( } } + fun setLoadingUiState() { + _uiState.value = GithubRepositoryUiState.Loading + } companion object { val Factory: ViewModelProvider.Factory = viewModelFactory { From 74cf5ade3e700114e5a555e867e1ff56a38279ff Mon Sep 17 00:00:00 2001 From: OYJ Date: Thu, 12 Sep 2024 00:40:44 +0900 Subject: [PATCH 13/13] =?UTF-8?q?Refactor=20:=20GithubRepositoryUiState=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Loading과 Ready로 구분 2. Ready안에 항목 없음과 에러 여부를 판단하는 boolean값 추가 3. 관련 코드 수정 --- .../ui/screen/github/GithubViewModel.kt | 32 ++++------ .../github/ui/screen/github/MainScreen.kt | 64 ++++++++++--------- .../github/list/GithubRepositoryUiState.kt | 15 ++--- 3 files changed, 53 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt b/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt index 5aa842b..faff55f 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/GithubViewModel.kt @@ -20,9 +20,7 @@ import nextstep.github.ui.screen.github.list.GithubRepositoryUiState class GithubViewModel( private val getGithubRepoUseCase: GetGithubRepoUseCase ) : ViewModel() { - - private val _uiState = - MutableStateFlow(GithubRepositoryUiState.Loading) + private val _uiState = MutableStateFlow(GithubRepositoryUiState.Loading) val uiState: StateFlow = _uiState fun getRepositories(organization: String) { @@ -33,32 +31,28 @@ class GithubViewModel( delay(300) when (val result = getGithubRepoUseCase(organization)) { is ApiResult.Success -> { - if (result.value.isEmpty()) { - _uiState.value = GithubRepositoryUiState.Empty - } else { - _uiState.value = - GithubRepositoryUiState.Success( - githubRepositories = result.value - ) - } + _uiState.value = GithubRepositoryUiState.Ready( + githubRepositories = result.value, + isError = false + ) } is ApiResult.Error -> { - _uiState.value = GithubRepositoryUiState.Error - Log.e("GithubViewModel", "Error: ${result.code} ${result.exception}") + _uiState.value = GithubRepositoryUiState.Ready( + githubRepositories = emptyList(), + isError = true + ) } } } catch (e: Exception) { - _uiState.value = GithubRepositoryUiState.Error - Log.e("GithubViewModel", "Error: ${e.message}") + _uiState.value = GithubRepositoryUiState.Ready( + githubRepositories = emptyList(), + isError = true + ) } } } - fun setLoadingUiState() { - _uiState.value = GithubRepositoryUiState.Loading - } - companion object { val Factory: ViewModelProvider.Factory = viewModelFactory { initializer { diff --git a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt index 1a2326f..f57d9c0 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/MainScreen.kt @@ -16,11 +16,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import nextstep.github.R import nextstep.github.domain.entity.RepositoryEntity -import nextstep.github.ui.screen.github.list.component.MainTopBar import nextstep.github.ui.screen.github.list.GithubRepositoryUiState import nextstep.github.ui.screen.github.list.component.GithubRepositoryEmpty import nextstep.github.ui.screen.github.list.component.GithubRepositoryList import nextstep.github.ui.screen.github.list.component.LoadingProgress +import nextstep.github.ui.screen.github.list.component.MainTopBar @Composable fun MainScreen( @@ -39,8 +39,9 @@ fun MainScreen( @Composable fun MainScreen( - uiState: GithubRepositoryUiState = GithubRepositoryUiState.Loading, + uiState: GithubRepositoryUiState, snackbarHostState: SnackbarHostState, + modifier: Modifier = Modifier, onRetry: () -> Unit = {} ) { // stateless @@ -51,48 +52,43 @@ fun MainScreen( { paddingValues -> when (uiState) { is GithubRepositoryUiState.Loading -> { - // 로딩 화면 LoadingProgress( modifier = Modifier.padding(paddingValues) ) } - is GithubRepositoryUiState.Error -> { - // 에러 화면 - val errorMsg = stringResource(id = R.string.text_snackbar_network_error) - val actionLabel = stringResource(id = R.string.text_snackbar_action_retry) + is GithubRepositoryUiState.Ready -> { + if (uiState.isError) { + val errorMsg = stringResource(id = R.string.text_snackbar_network_error) + val actionLabel = stringResource(id = R.string.text_snackbar_action_retry) - LaunchedEffect(snackbarHostState) { - val snackbarResult = snackbarHostState.showSnackbar( - message = errorMsg, - actionLabel = actionLabel, - ) + LaunchedEffect(snackbarHostState) { + val snackbarResult = snackbarHostState.showSnackbar( + message = errorMsg, + actionLabel = actionLabel, + ) - if (snackbarResult == SnackbarResult.ActionPerformed) { - onRetry() + if (snackbarResult == SnackbarResult.ActionPerformed) { + onRetry() + } } } - } - is GithubRepositoryUiState.Empty -> { - GithubRepositoryEmpty( - modifier = Modifier.padding(paddingValues) - ) - } - - is GithubRepositoryUiState.Success -> { - GithubRepositoryList( - repositoryEntityList = uiState.githubRepositories, - modifier = Modifier.padding(paddingValues) - ) + if (uiState.isEmpty) { + GithubRepositoryEmpty( + modifier = Modifier.padding(paddingValues) + ) + } else { + GithubRepositoryList( + repositoryEntityList = uiState.githubRepositories, + modifier = Modifier.padding(paddingValues) + ) + } } - - } } } - @Preview @Composable private fun LoadingMainScreenPreview() { @@ -106,7 +102,10 @@ private fun LoadingMainScreenPreview() { @Composable private fun EmptyMainScreenPreview() { MainScreen( - uiState = GithubRepositoryUiState.Empty, + uiState = GithubRepositoryUiState.Ready( + githubRepositories = emptyList(), + isError = true + ), snackbarHostState = remember { SnackbarHostState() } ) } @@ -138,7 +137,10 @@ private fun SuccessMainScreenPreview() { ) MainScreen( - uiState = GithubRepositoryUiState.Success(githubRepositoryList), + uiState = GithubRepositoryUiState.Ready( + githubRepositories = githubRepositoryList, + isError = false + ), snackbarHostState = remember { SnackbarHostState() } ) } diff --git a/app/src/main/java/nextstep/github/ui/screen/github/list/GithubRepositoryUiState.kt b/app/src/main/java/nextstep/github/ui/screen/github/list/GithubRepositoryUiState.kt index ba3fd03..ecd5a32 100644 --- a/app/src/main/java/nextstep/github/ui/screen/github/list/GithubRepositoryUiState.kt +++ b/app/src/main/java/nextstep/github/ui/screen/github/list/GithubRepositoryUiState.kt @@ -3,13 +3,12 @@ package nextstep.github.ui.screen.github.list import nextstep.github.domain.entity.RepositoryEntity sealed class GithubRepositoryUiState { - - data object Error : GithubRepositoryUiState() - data object Loading : GithubRepositoryUiState() - - data object Empty : GithubRepositoryUiState() - - data class Success(val githubRepositories: List) : - GithubRepositoryUiState() + data class Ready( + val githubRepositories: List, + val isError: Boolean = false + ) : GithubRepositoryUiState() { + val isEmpty: Boolean + get() = githubRepositories.isEmpty() + } }