Skip to content

Commit 8938df2

Browse files
authored
Merge pull request #215 from YAPP-Github/release/2.2.1
[Release/2.2.1] (main)
2 parents ef3d21b + 32e7863 commit 8938df2

710 files changed

Lines changed: 3575 additions & 3783 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/.gitkeep

Whitespace-only changes.

.github/workflows/develop_branch.yml

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,9 @@ jobs:
1414
- name: check out repository
1515
uses: actions/checkout@v4
1616

17-
- name: Decode Keystore
17+
- name: Decode Keystore & Generate local.properties
1818
env:
1919
RELEASE_STORE_BASE_64: ${{ secrets.RELEASE_STORE_BASE_64 }}
20-
run: |
21-
echo $RELEASE_STORE_BASE_64 > encoded_keystore.txt
22-
base64 --decode encoded_keystore.txt > release.jks
23-
24-
- name: Generate local.properties
25-
env:
2620
KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
2721
KAKAO_REST_API_KEY: ${{ secrets.KAKAO_REST_API_KEY }}
2822
BITNAGIL_DEV_URL: ${{ secrets.BITNAGIL_DEV_URL }}
@@ -31,6 +25,11 @@ jobs:
3125
RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
3226
RELEASE_STORE_PASSWORD: ${{ secrets.RELEASE_STORE_PASSWORD }}
3327
run: |
28+
# Keystore Decoding
29+
echo $RELEASE_STORE_BASE_64 > encoded_keystore.txt
30+
base64 --decode encoded_keystore.txt > release.jks
31+
32+
# Generate local.properties
3433
echo "kakao.native.app.key=$KAKAO_NATIVE_APP_KEY" >> local.properties
3534
echo "kakao.rest.api.key=$KAKAO_REST_API_KEY" >> local.properties
3635
echo "bitnagil.dev.url=$BITNAGIL_DEV_URL" >> local.properties
@@ -45,13 +44,11 @@ jobs:
4544
with:
4645
java-version: '17'
4746
distribution: 'temurin'
48-
cache: gradle
4947

50-
- name: Run ktlint
51-
run: ./gradlew ktlintCheck
52-
53-
- name: Run unit tests
54-
run: ./gradlew testDebugUnitTest
48+
- name: Setup Gradle
49+
uses: gradle/actions/setup-gradle@v4
50+
with:
51+
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
5552

56-
- name: Build with Gradle
57-
run: ./gradlew assembleDebug
53+
- name: Build and Verify
54+
run: ./gradlew ktlintCheck testDebugUnitTest assembleDebug

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ gen-external-apklibs
4545
### Kotlin ###
4646
# Compiled class file
4747
*.class
48+
.kotlin/
49+
.kotlin
4850

4951
# Log file
5052

app/build.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ import java.util.Properties
33
plugins {
44
alias(libs.plugins.bitnagil.android.application)
55
alias(libs.plugins.bitnagil.android.hilt)
6-
alias(libs.plugins.kotlin.serialization)
6+
alias(libs.plugins.bitnagil.kotlin.serialization)
77
}
88

99
android {
10-
namespace = "com.threegap.bitnagil"
11-
1210
val properties =
1311
Properties().apply {
1412
val propFile = rootProject.file("local.properties")
@@ -74,7 +72,8 @@ android {
7472
?: System.getenv("BITNAGIL_PROD_URL")
7573
?: throw GradleException("bitnagil.prod.url 값이 없습니다.")
7674
buildConfigField("String", "BASE_URL", "\"$prodUrl\"")
77-
isMinifyEnabled = false
75+
isMinifyEnabled = true
76+
isShrinkResources = true
7877
proguardFiles(
7978
getDefaultProguardFile("proguard-android-optimize.txt"),
8079
"proguard-rules.pro",
@@ -102,4 +101,5 @@ dependencies {
102101
implementation(libs.bundles.retrofit)
103102
implementation(platform(libs.okhttp.bom))
104103
implementation(libs.bundles.okhttp)
104+
implementation(libs.bundles.coil)
105105
}

app/proguard-rules.pro

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,45 @@
1-
# Add project specific ProGuard rules here.
2-
# You can control the set of applied configuration files using the
3-
# proguardFiles setting in build.gradle.
4-
#
5-
# For more details, see
6-
# http://developer.android.com/guide/developing/tools/proguard.html
1+
-keepattributes SourceFile,LineNumberTable
2+
-renamesourcefileattribute SourceFile
73

8-
# If your project uses WebView with JS, uncomment the following
9-
# and specify the fully qualified class name to the JavaScript interface
10-
# class:
11-
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12-
# public *;
13-
#}
4+
# [Kakao SDK 버그 방어]
5+
# AccessTokenInterceptor에서 ClientErrorCause 상수를 리플렉션(getField)으로 찾기 때문에 난독화에서 제외함
6+
-keep enum com.kakao.sdk.common.model.ClientErrorCause {
7+
*;
8+
}
149

15-
# Uncomment this to preserve the line number information for
16-
# debugging stack traces.
17-
#-keepattributes SourceFile,LineNumberTable
10+
# [Kotlinx Serialization]
11+
# 모든 @Serializable 클래스의 직렬화 로직 및 serializer 메서드 유지
12+
-keepattributes Annotation, InnerClasses, Signature, Exceptions
13+
-keepclassmembers class * {
14+
@kotlinx.serialization.Serializable *;
15+
}
16+
-keepclassmembers class * {
17+
kotlinx.serialization.KSerializer serializer(...);
18+
}
1819

19-
# If you keep the line number information, uncomment this to
20-
# hide the original source file name.
21-
#-renamesourcefileattribute SourceFile
20+
# [Domain/Data Layer Enums]
21+
# API 응답 매핑 및 리플렉션 방어를 위해 Enum 상수 이름 유지
22+
-keepclassmembers enum com.threegap.bitnagil.domain.**.model.** {
23+
<fields>;
24+
}
25+
-keepclassmembers enum com.threegap.bitnagil.data.**.model.** {
26+
<fields>;
27+
}
28+
29+
# [Compose Navigation Type-Safe Arguments]
30+
# 네비게이션 인자 클래스 및 Route 객체 보존
31+
-keep class com.threegap.bitnagil.presentation.**.model.navarg.** { *; }
32+
-keep class com.threegap.bitnagil.Route** { *; }
33+
# HomeRoute는 navigation.home 패키지로 Route** 패턴 밖이므로 별도 보호
34+
# Compose Navigation이 내부적으로 serializer descriptor name을 route ID로 사용하므로
35+
# deep link 추가 시 repackaging으로 빌드마다 route string이 달라지는 문제 방어
36+
-keep class com.threegap.bitnagil.navigation.home.HomeRoute** { *; }
37+
38+
# [Kotlin Result - Retrofit 반환 타입]
39+
# suspend fun foo(): Result<T> 형태의 Retrofit 인터페이스에서
40+
# R8이 kotlin.Result의 제네릭 타입 인자를 지워 call adapter 탐색 실패 방어
41+
-keep class kotlin.Result { *; }
42+
43+
# [Network Libraries]
44+
# Retrofit 및 OkHttp 어노테이션 유지
45+
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
xmlns:tools="http://schemas.android.com/tools">
3+
xmlns:tools="http://schemas.android.com/tools"
4+
android:installLocation="internalOnly">
45

56
<uses-permission android:name="android.permission.INTERNET" />
67
<uses-permission android:name="android.permission.CAMERA" />

app/src/main/java/com/threegap/bitnagil/BitnagilApplication.kt

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,51 @@
11
package com.threegap.bitnagil
22

33
import android.app.Application
4+
import coil3.ImageLoader
5+
import coil3.PlatformContext
6+
import coil3.SingletonImageLoader
7+
import coil3.disk.DiskCache
8+
import coil3.memory.MemoryCache
9+
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
10+
import coil3.request.crossfade
11+
import coil3.util.DebugLogger
412
import com.kakao.sdk.common.KakaoSdk
13+
import com.threegap.bitnagil.di.core.CoilEntryPoint
14+
import dagger.hilt.EntryPoints
515
import dagger.hilt.android.HiltAndroidApp
16+
import okio.Path.Companion.toOkioPath
617

718
@HiltAndroidApp
8-
class BitnagilApplication : Application() {
19+
class BitnagilApplication : Application(), SingletonImageLoader.Factory {
20+
921
override fun onCreate() {
1022
super.onCreate()
1123
initKakaoSdk()
1224
}
1325

26+
override fun newImageLoader(context: PlatformContext): ImageLoader {
27+
val okHttpClient = EntryPoints
28+
.get(this, CoilEntryPoint::class.java)
29+
.noneAuthOkHttpClient()
30+
31+
return ImageLoader.Builder(context)
32+
.components { add(OkHttpNetworkFetcherFactory(callFactory = { okHttpClient })) }
33+
.memoryCache {
34+
MemoryCache.Builder()
35+
.maxSizePercent(context, percent = 0.25)
36+
.build()
37+
}
38+
.diskCache {
39+
DiskCache.Builder()
40+
.directory(cacheDir.resolve("image_cache").toOkioPath())
41+
.maxSizeBytes(50L * 1024 * 1024)
42+
.build()
43+
}
44+
.crossfade(true)
45+
.logger(if (BuildConfig.DEBUG) DebugLogger() else null)
46+
.build()
47+
}
48+
1449
private fun initKakaoSdk() {
1550
KakaoSdk.init(this, BuildConfig.KAKAO_NATIVE_APP_KEY)
1651
}

app/src/main/java/com/threegap/bitnagil/MainActivity.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import androidx.compose.ui.Modifier
1717
import androidx.compose.ui.unit.dp
1818
import com.threegap.bitnagil.designsystem.component.atom.BitnagilToastContainer
1919
import com.threegap.bitnagil.designsystem.component.atom.rememberBitnagilToast
20-
import com.threegap.bitnagil.presentation.common.toast.GlobalBitnagilToast
20+
import com.threegap.bitnagil.presentation.util.toast.GlobalBitnagilToast
2121
import dagger.hilt.android.AndroidEntryPoint
2222

2323
@AndroidEntryPoint
@@ -46,9 +46,7 @@ class MainActivity : ComponentActivity() {
4646
}
4747

4848
Box(modifier = Modifier.fillMaxSize()) {
49-
MainScreen(
50-
navigator = mainNavigator,
51-
)
49+
MainScreen(navigator = mainNavigator)
5250

5351
BitnagilToastContainer(
5452
state = globalToast,

app/src/main/java/com/threegap/bitnagil/MainNavHost.kt

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,31 @@ package com.threegap.bitnagil
22

33
import androidx.compose.runtime.Composable
44
import androidx.compose.ui.Modifier
5-
import androidx.hilt.navigation.compose.hiltViewModel
5+
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
66
import androidx.navigation.compose.NavHost
77
import androidx.navigation.compose.composable
88
import androidx.navigation.toRoute
99
import com.threegap.bitnagil.navigation.home.HomeNavHost
10-
import com.threegap.bitnagil.presentation.emotion.EmotionScreenContainer
11-
import com.threegap.bitnagil.presentation.guide.GuideScreenContainer
12-
import com.threegap.bitnagil.presentation.login.LoginScreenContainer
13-
import com.threegap.bitnagil.presentation.onboarding.OnBoardingScreenContainer
14-
import com.threegap.bitnagil.presentation.onboarding.OnBoardingViewModel
15-
import com.threegap.bitnagil.presentation.onboarding.model.navarg.OnBoardingScreenArg
16-
import com.threegap.bitnagil.presentation.report.ReportScreenContainer
17-
import com.threegap.bitnagil.presentation.reportdetail.ReportDetailScreenContainer
18-
import com.threegap.bitnagil.presentation.reportdetail.ReportDetailViewModel
19-
import com.threegap.bitnagil.presentation.reportdetail.model.navarg.ReportDetailScreenArg
20-
import com.threegap.bitnagil.presentation.reporthistory.ReportHistoryScreenContainer
21-
import com.threegap.bitnagil.presentation.routinelist.RoutineListScreenContainer
22-
import com.threegap.bitnagil.presentation.setting.SettingScreenContainer
23-
import com.threegap.bitnagil.presentation.splash.SplashScreenContainer
24-
import com.threegap.bitnagil.presentation.terms.TermsAgreementScreenContainer
25-
import com.threegap.bitnagil.presentation.webview.BitnagilWebViewScreen
26-
import com.threegap.bitnagil.presentation.withdrawal.WithdrawalScreenContainer
27-
import com.threegap.bitnagil.presentation.writeroutine.WriteRoutineScreenContainer
28-
import com.threegap.bitnagil.presentation.writeroutine.WriteRoutineViewModel
29-
import com.threegap.bitnagil.presentation.writeroutine.model.navarg.WriteRoutineScreenArg
10+
import com.threegap.bitnagil.presentation.screen.emotion.EmotionScreenContainer
11+
import com.threegap.bitnagil.presentation.screen.guide.GuideScreenContainer
12+
import com.threegap.bitnagil.presentation.screen.login.LoginScreenContainer
13+
import com.threegap.bitnagil.presentation.screen.onboarding.OnBoardingScreenContainer
14+
import com.threegap.bitnagil.presentation.screen.onboarding.OnBoardingViewModel
15+
import com.threegap.bitnagil.presentation.screen.onboarding.model.navarg.OnBoardingScreenArg
16+
import com.threegap.bitnagil.presentation.screen.reportdetail.ReportDetailScreenContainer
17+
import com.threegap.bitnagil.presentation.screen.reportdetail.ReportDetailViewModel
18+
import com.threegap.bitnagil.presentation.screen.reportdetail.model.navarg.ReportDetailScreenArg
19+
import com.threegap.bitnagil.presentation.screen.reporthistory.ReportHistoryScreenContainer
20+
import com.threegap.bitnagil.presentation.screen.reportwrite.ReportWriteScreenContainer
21+
import com.threegap.bitnagil.presentation.screen.routinelist.RoutineListScreenContainer
22+
import com.threegap.bitnagil.presentation.screen.routinewrite.RoutineWriteScreenContainer
23+
import com.threegap.bitnagil.presentation.screen.routinewrite.RoutineWriteViewModel
24+
import com.threegap.bitnagil.presentation.screen.routinewrite.model.navarg.RoutineWriteScreenArg
25+
import com.threegap.bitnagil.presentation.screen.setting.SettingScreenContainer
26+
import com.threegap.bitnagil.presentation.screen.splash.SplashScreenContainer
27+
import com.threegap.bitnagil.presentation.screen.terms.TermsAgreementScreenContainer
28+
import com.threegap.bitnagil.presentation.screen.webview.BitnagilWebViewScreen
29+
import com.threegap.bitnagil.presentation.screen.withdrawal.WithdrawalScreenContainer
3030

3131
@Composable
3232
fun MainNavHost(
@@ -127,7 +127,7 @@ fun MainNavHost(
127127
}
128128
},
129129
navigateToRegisterRoutine = { routineId ->
130-
navigator.navController.navigate(Route.WriteRoutine(routineId = routineId))
130+
navigator.navController.navigate(Route.RoutineWrite(routineId = routineId))
131131
},
132132
navigateToEmotion = {
133133
navigator.navController.navigate(Route.Emotion)
@@ -140,7 +140,7 @@ fun MainNavHost(
140140
}
141141
},
142142
navigateToReport = {
143-
navigator.navController.navigate(Route.Report) {
143+
navigator.navController.navigate(Route.ReportWrite) {
144144
launchSingleTop = true
145145
}
146146
},
@@ -224,19 +224,19 @@ fun MainNavHost(
224224
)
225225
}
226226

227-
composable<Route.WriteRoutine> { navBackStackEntry ->
228-
val arg = navBackStackEntry.toRoute<Route.WriteRoutine>()
227+
composable<Route.RoutineWrite> { navBackStackEntry ->
228+
val arg = navBackStackEntry.toRoute<Route.RoutineWrite>()
229229
val writeScreenNavArg = if (arg.isRegister) {
230-
WriteRoutineScreenArg.Add(baseRoutineId = arg.routineId)
230+
RoutineWriteScreenArg.Add(baseRoutineId = arg.routineId)
231231
} else {
232-
WriteRoutineScreenArg.Edit(routineId = arg.routineId!!, updateRoutineFromNowDate = arg.isUpdateRoutineFromNowDate)
232+
RoutineWriteScreenArg.Edit(routineId = arg.routineId!!, updateRoutineFromNowDate = arg.isUpdateRoutineFromNowDate)
233233
}
234234

235-
val viewModel = hiltViewModel<WriteRoutineViewModel, WriteRoutineViewModel.Factory> { factory ->
235+
val viewModel = hiltViewModel<RoutineWriteViewModel, RoutineWriteViewModel.Factory> { factory ->
236236
factory.create(writeScreenNavArg)
237237
}
238238

239-
WriteRoutineScreenContainer(
239+
RoutineWriteScreenContainer(
240240
viewModel = viewModel,
241241
navigateToBack = {
242242
if (navigator.navController.previousBackStackEntry != null) {
@@ -281,11 +281,11 @@ fun MainNavHost(
281281
}
282282
},
283283
navigateToAddRoutine = {
284-
navigator.navController.navigate(Route.WriteRoutine())
284+
navigator.navController.navigate(Route.RoutineWrite())
285285
},
286286
navigateToEditRoutine = { routineId, updateRoutineFromNowDate ->
287287
navigator.navController.navigate(
288-
Route.WriteRoutine(
288+
Route.RoutineWrite(
289289
routineId = routineId,
290290
isRegister = false,
291291
isUpdateRoutineFromNowDate = updateRoutineFromNowDate,
@@ -305,8 +305,8 @@ fun MainNavHost(
305305
)
306306
}
307307

308-
composable<Route.Report> {
309-
ReportScreenContainer(
308+
composable<Route.ReportWrite> {
309+
ReportWriteScreenContainer(
310310
navigateToBack = {
311311
if (navigator.navController.previousBackStackEntry != null) {
312312
navigator.navController.popBackStack()

app/src/main/java/com/threegap/bitnagil/Route.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ sealed interface Route {
3131
) : Route
3232

3333
@Serializable
34-
data class WriteRoutine(
34+
data class RoutineWrite(
3535
val routineId: String? = null,
3636
val isRegister: Boolean = true,
3737
val isUpdateRoutineFromNowDate: Boolean = true,
@@ -50,7 +50,7 @@ sealed interface Route {
5050
data object Guide : Route
5151

5252
@Serializable
53-
data object Report : Route
53+
data object ReportWrite : Route
5454

5555
@Serializable
5656
data object ReportHistory : Route

0 commit comments

Comments
 (0)