-
Notifications
You must be signed in to change notification settings - Fork 0
[INIT/#1] 프로젝트 기초 세팅 #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6969a21
34e8061
3797ea4
ae20ee0
266fcdd
367370b
5ace7f0
da22a30
008177f
4994c0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,20 +1,39 @@ | ||||||||||||||||||||
| import java.util.Properties | ||||||||||||||||||||
|
|
||||||||||||||||||||
| plugins { | ||||||||||||||||||||
| alias(libs.plugins.android.application) | ||||||||||||||||||||
| alias(libs.plugins.kotlin.android) | ||||||||||||||||||||
| alias(libs.plugins.kotlin.compose) | ||||||||||||||||||||
| alias(libs.plugins.kotlin.serialization) | ||||||||||||||||||||
| alias(libs.plugins.hilt) | ||||||||||||||||||||
| alias(libs.plugins.ksp) | ||||||||||||||||||||
| alias(libs.plugins.kotlin.parcelize) | ||||||||||||||||||||
| alias(libs.plugins.ktlint) | ||||||||||||||||||||
| } | ||||||||||||||||||||
| val properties = | ||||||||||||||||||||
| Properties().apply { | ||||||||||||||||||||
| load(project.rootProject.file("local.properties").inputStream()) | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| android { | ||||||||||||||||||||
| namespace = "com.android.heartz" | ||||||||||||||||||||
| compileSdk = 35 | ||||||||||||||||||||
| namespace = "com.heartz.app" | ||||||||||||||||||||
| compileSdk = libs.versions.compileSdk.get().toInt() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| defaultConfig { | ||||||||||||||||||||
| applicationId = "com.android.heartz" | ||||||||||||||||||||
| minSdk = 28 | ||||||||||||||||||||
| targetSdk = 35 | ||||||||||||||||||||
| versionCode = 1 | ||||||||||||||||||||
| versionName = "1.0" | ||||||||||||||||||||
| applicationId = "com.heartz.app" | ||||||||||||||||||||
| minSdk = libs.versions.minSdk.get().toInt() | ||||||||||||||||||||
| targetSdk = libs.versions.targetSdk.get().toInt() | ||||||||||||||||||||
| versionCode = libs.versions.versionCode.get().toInt() | ||||||||||||||||||||
| versionName = libs.versions.versionName.get() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| buildConfigField("String", "BASE_URL", properties["base.url"].toString()) | ||||||||||||||||||||
| buildConfigField( | ||||||||||||||||||||
| "String", | ||||||||||||||||||||
| "KAKAO_NATIVE_APP_KEY", | ||||||||||||||||||||
| properties["kakao.native.app.key"].toString() | ||||||||||||||||||||
| ) | ||||||||||||||||||||
|
Comment on lines
+31
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BuildConfig에서 민감한 정보 노출을 방지하세요.
더 안전한 방법들을 고려해보세요:
- buildConfigField("String", "BASE_URL", properties["base.url"].toString())
- buildConfigField(
- "String",
- "KAKAO_NATIVE_APP_KEY",
- properties["kakao.native.app.key"].toString()
- )
+ // 리소스 파일을 통한 방법 고려
+ resValue("string", "base_url", properties["base.url"]?.toString() ?: "\"\"")
+ manifestPlaceholders["kakaoAppKey"] = properties["kakao.native.app.key"]?.toString() ?: ""📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| buildTypes { | ||||||||||||||||||||
|
|
@@ -27,20 +46,66 @@ android { | |||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| compileOptions { | ||||||||||||||||||||
| sourceCompatibility = JavaVersion.VERSION_11 | ||||||||||||||||||||
| targetCompatibility = JavaVersion.VERSION_11 | ||||||||||||||||||||
| sourceCompatibility = JavaVersion.VERSION_17 | ||||||||||||||||||||
| targetCompatibility = JavaVersion.VERSION_17 | ||||||||||||||||||||
| } | ||||||||||||||||||||
| kotlinOptions { | ||||||||||||||||||||
| jvmTarget = "11" | ||||||||||||||||||||
| jvmTarget = "17" | ||||||||||||||||||||
| } | ||||||||||||||||||||
| buildFeatures { | ||||||||||||||||||||
| compose = true | ||||||||||||||||||||
| buildConfig = true | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| dependencies { | ||||||||||||||||||||
|
|
||||||||||||||||||||
| implementation(libs.androidx.core.ktx) | ||||||||||||||||||||
| implementation(libs.androidx.appcompat) | ||||||||||||||||||||
| implementation(libs.material) | ||||||||||||||||||||
| // Test | ||||||||||||||||||||
| testImplementation(libs.junit) | ||||||||||||||||||||
| androidTestImplementation(libs.androidx.junit) | ||||||||||||||||||||
| androidTestImplementation(libs.androidx.espresso.core) | ||||||||||||||||||||
| } | ||||||||||||||||||||
| androidTestImplementation(platform(libs.androidx.compose.bom)) | ||||||||||||||||||||
| androidTestImplementation(libs.bundles.test) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Debug | ||||||||||||||||||||
| debugImplementation(libs.bundles.debug) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // AndroidX | ||||||||||||||||||||
| implementation(libs.bundles.androidx) | ||||||||||||||||||||
| implementation(platform(libs.androidx.compose.bom)) | ||||||||||||||||||||
| implementation(libs.kotlinx.collections.immutable) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| implementation(platform(libs.google.firebase.bom)) | ||||||||||||||||||||
| implementation(libs.google.firebase.crashlytics) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Network | ||||||||||||||||||||
| implementation(platform(libs.okhttp.bom)) | ||||||||||||||||||||
| implementation(libs.bundles.okhttp) | ||||||||||||||||||||
| implementation(libs.bundles.retrofit) | ||||||||||||||||||||
| implementation(libs.kotlinx.serialization.json) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Hilt | ||||||||||||||||||||
| implementation(libs.bundles.hilt) | ||||||||||||||||||||
| ksp(libs.hilt.compiler) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Coil | ||||||||||||||||||||
| implementation(libs.coil.compose) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Timber | ||||||||||||||||||||
| implementation(libs.timber) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Kakao Login | ||||||||||||||||||||
| implementation(libs.bundles.kakao) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Ui | ||||||||||||||||||||
| implementation(libs.androidx.ui) | ||||||||||||||||||||
| implementation(libs.androidx.ui.graphics) | ||||||||||||||||||||
| debugImplementation(libs.androidx.ui.tooling) | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ktlint { | ||||||||||||||||||||
| android = true | ||||||||||||||||||||
| debug = true | ||||||||||||||||||||
| coloredOutput = true | ||||||||||||||||||||
| verbose = true | ||||||||||||||||||||
| outputToConsole = true | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,16 @@ | ||
| package com.android.heartz | ||
|
|
||
| import androidx.test.platform.app.InstrumentationRegistry | ||
| import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
|
|
||
| import androidx.test.platform.app.InstrumentationRegistry | ||
| import org.junit.Assert.assertEquals | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
|
|
||
| import org.junit.Assert.* | ||
|
|
||
| /** | ||
| * Instrumented test, which will execute on an Android device. | ||
| * | ||
| * See [testing documentation](http://d.android.com/tools/testing). | ||
| */ | ||
| @RunWith(AndroidJUnit4::class) | ||
| class ExampleInstrumentedTest { | ||
| @Test | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p3: 얘도 테스트코드인건가요?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이부분은 안드로이드 Instrumented 테스트 코드입니다! 저도 unit test만 해보고 요런 테스트에 대해서는 처음 공부해봤는데 이 차이점은 나중에 같이 공부해보면 좋을 것 같아요! 여기서 수정이 일어난 이유는 ktlint에서
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오오 Instrumented 테스트 코드 이 부분 저도 한 번 미리 공부해보겠습니다~~ |
||
| fun useAppContext() { | ||
| // Context of the app under test. | ||
| val appContext = InstrumentationRegistry.getInstrumentation().targetContext | ||
| assertEquals("com.android.heartz", appContext.packageName) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.heartz.app | ||
|
|
||
| import android.app.Application | ||
| import androidx.appcompat.app.AppCompatDelegate | ||
| import dagger.hilt.android.HiltAndroidApp | ||
| import timber.log.Timber | ||
|
|
||
| @HiltAndroidApp | ||
| class Heartz : Application() { | ||
| override fun onCreate() { | ||
| super.onCreate() | ||
|
|
||
| initTimber() | ||
| setDayMode() | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p3: 다크 모드 확장하는 거 물어봐주는거 까먹지 말기~~
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sohee6989 앱잼 기간 동안에는 일단 안하는걸루! |
||
| } | ||
|
|
||
| private fun initTimber() { | ||
| if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree()) | ||
| } | ||
|
|
||
| private fun setDayMode() { | ||
| AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,13 @@ | ||||||||||||||||||||||||||||||||
| package com.heartz.app.core.designsystem.ui.theme | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import androidx.compose.material3.darkColorScheme | ||||||||||||||||||||||||||||||||
| import androidx.compose.ui.graphics.Color | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| val Red80 = Color(0xFFFF5656) | ||||||||||||||||||||||||||||||||
| val Pink80 = Color(0xFFFFB0B0) | ||||||||||||||||||||||||||||||||
|
Comment on lines
+6
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 색상 네이밍이 실제 색상값과 불일치합니다.
-val Red80 = Color(0xFFFF5656)
-val Pink80 = Color(0xFFFFB0B0)
+val Red40 = Color(0xFFFF5656) // 더 밝은 색상이므로 40번대가 적절
+val Pink40 = Color(0xFFFFB0B0)또는 Material 3 색상 팔레트 가이드라인에 따라 색상을 재정의하는 것을 고려해보세요. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| val HeartzColorScheme = | ||||||||||||||||||||||||||||||||
| darkColorScheme( | ||||||||||||||||||||||||||||||||
| primary = Red80, | ||||||||||||||||||||||||||||||||
| secondary = Pink80 | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
|
Comment on lines
+9
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 라이트 테마 지원을 위한 추가 구현이 필요합니다. 현재 다크 컬러 스키마만 정의되어 있어 라이트 테마를 지원하지 않습니다. 사용자 경험 향상을 위해 라이트 컬러 스키마도 추가하는 것을 권장합니다. +val HeartzLightColorScheme = lightColorScheme(
+ primary = Red40,
+ secondary = Pink40
+)
+
val HeartzColorScheme =
darkColorScheme(
- primary = Red80,
- secondary = Pink80
+ primary = Red80,
+ secondary = Pink80
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package com.heartz.app.core.designsystem.ui.theme | ||
|
|
||
| import androidx.compose.material3.MaterialTheme | ||
| import androidx.compose.runtime.Composable | ||
|
|
||
| @Composable | ||
| fun HeartzTheme(content: @Composable () -> Unit) { | ||
| MaterialTheme( | ||
| colorScheme = HeartzColorScheme, | ||
| typography = Typography, | ||
| content = content | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package com.heartz.app.core.designsystem.ui.theme | ||
|
|
||
| import androidx.compose.material3.Typography | ||
| import androidx.compose.ui.text.TextStyle | ||
| import androidx.compose.ui.text.font.FontFamily | ||
| import androidx.compose.ui.text.font.FontWeight | ||
| import androidx.compose.ui.unit.sp | ||
|
|
||
| val Typography = | ||
| Typography( | ||
| bodyLarge = | ||
| TextStyle( | ||
| fontFamily = FontFamily.Default, | ||
| fontWeight = FontWeight.SemiBold, | ||
| fontSize = 16.sp, | ||
| lineHeight = 24.sp | ||
| ) | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| package com.heartz.app.core.navigation | ||
|
|
||
| interface MainTabRoute : Route |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| package com.heartz.app.core.navigation | ||
|
|
||
| interface Route |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.heartz.app.core.state | ||
|
|
||
| sealed interface UiState<out T> { | ||
| data object Empty : UiState<Nothing> | ||
|
|
||
| data object Loading : UiState<Nothing> | ||
|
|
||
| data class Success<T>( | ||
| val data: T | ||
| ) : UiState<T> | ||
|
|
||
| data class Failure( | ||
| val msg: String | ||
| ) : UiState<Nothing> | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.heartz.app.core.util | ||
|
|
||
| import androidx.compose.foundation.clickable | ||
| import androidx.compose.foundation.interaction.MutableInteractionSource | ||
| import androidx.compose.runtime.remember | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.composed | ||
|
|
||
| inline fun Modifier.noRippleClickable(crossinline onClick: () -> Unit = {}): Modifier = | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p3
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inline함수를 쓰면서 정말 많이 나오는 부분 같아요! 앱잼하면서 런캐칭으로 오류처리 할 때
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 이거 저도 공부해보겠습니다~~신기하네요 |
||
| composed { | ||
| this.clickable( | ||
| indication = null, | ||
| interactionSource = remember { MutableInteractionSource() } | ||
| ) { | ||
| onClick() | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.heartz.app.data.datasource.local | ||
|
|
||
| import kotlinx.coroutines.flow.Flow | ||
|
|
||
| // TODO: 임시 | ||
| interface DummyLocalDataSource { | ||
| val isLogin: Flow<Boolean> | ||
|
|
||
| suspend fun setIsLogin(value: Boolean) | ||
|
|
||
| suspend fun clear() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.heartz.app.data.datasource.remote | ||
|
|
||
| import com.heartz.app.data.dto.base.DummyBaseResponse | ||
| import com.heartz.app.data.dto.request.RequestDummyDto | ||
| import com.heartz.app.data.dto.response.ResponseDummyDto | ||
|
|
||
| interface DummyRemoteDataSource { | ||
| suspend fun getDummies(request: RequestDummyDto): DummyBaseResponse<ResponseDummyDto> | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package com.heartz.app.data.datasourceimpl.local | ||
|
|
||
| import android.content.Context | ||
| import androidx.datastore.preferences.core.booleanPreferencesKey | ||
| import androidx.datastore.preferences.core.edit | ||
| import androidx.datastore.preferences.preferencesDataStore | ||
| import com.heartz.app.data.datasource.local.DummyLocalDataSource | ||
| import dagger.hilt.android.qualifiers.ApplicationContext | ||
| import javax.inject.Inject | ||
| import kotlinx.coroutines.flow.Flow | ||
| import kotlinx.coroutines.flow.map | ||
|
|
||
| private const val FILE_NAME = "heartz_datastore" | ||
|
|
||
| private val Context.dataStore by preferencesDataStore(name = FILE_NAME) | ||
|
|
||
| class DummyLocalDataSourceImpl @Inject constructor( | ||
| @ApplicationContext private val context: Context | ||
| ) : DummyLocalDataSource { | ||
| companion object { | ||
| val IS_LOGIN = booleanPreferencesKey("is_login") | ||
| } | ||
|
|
||
| override val isLogin: Flow<Boolean> = | ||
| context.dataStore.data.map { preferences -> | ||
| preferences[IS_LOGIN] ?: false | ||
| } | ||
|
|
||
| override suspend fun setIsLogin(value: Boolean) { | ||
| context.dataStore.edit { it[IS_LOGIN] = value } | ||
| } | ||
|
|
||
| override suspend fun clear() { | ||
| context.dataStore.edit { it.clear() } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package com.heartz.app.data.datasourceimpl.remote | ||
|
|
||
| import com.heartz.app.data.datasource.remote.DummyRemoteDataSource | ||
| import com.heartz.app.data.dto.base.DummyBaseResponse | ||
| import com.heartz.app.data.dto.request.RequestDummyDto | ||
| import com.heartz.app.data.dto.response.ResponseDummyDto | ||
| import com.heartz.app.data.service.DummyService | ||
| import javax.inject.Inject | ||
|
|
||
| class DummyRemoteDataSourceImpl | ||
| @Inject | ||
| constructor( | ||
| private val dummyService: DummyService | ||
| ) : DummyRemoteDataSource { | ||
| override suspend fun getDummies( | ||
| request: RequestDummyDto | ||
| ): DummyBaseResponse<ResponseDummyDto> = | ||
| dummyService.getDummies(request) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
local.properties 파일 누락 시 에러 처리를 추가하세요.
현재
local.properties파일이 존재하지 않을 경우 빌드가 실패할 수 있습니다.val properties = Properties().apply { - load(project.rootProject.file("local.properties").inputStream()) + val localPropertiesFile = project.rootProject.file("local.properties") + if (localPropertiesFile.exists()) { + load(localPropertiesFile.inputStream()) + } }🤖 Prompt for AI Agents