Skip to content
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

🛠[Setting] Compose 기본 세팅과 템플릿 제작 #1

Merged
merged 42 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0de9f1b
[Chore]: 컴포즈 버전 추가
jinuemong Jan 17, 2024
3e20dba
[Style]: 코드 리포맷
jinuemong Jan 17, 2024
258d2af
[Chore]: 컴포즈 버전 적용
jinuemong Jan 17, 2024
a6299bf
[Chore]: 컴포즈 관련 라이브러리 수정
jinuemong Jan 17, 2024
4bec84b
[Chore]: 컴포즈 ui bundle 생성과 google system 라이브러리 추가
jinuemong Jan 17, 2024
ab37720
[Feat]: 컴포즈 환경에서 애플리케이션 상태를 관리하는 applicationState 클래스 구현
jinuemong Jan 17, 2024
516eacd
[Feat]: NavHost의 각 화면을 담당하는 ScreenRoot 기능 구현
jinuemong Jan 17, 2024
425b73e
[Feat]: BottomState, 상태바를 관리하는 클래스 기능 구현
jinuemong Jan 17, 2024
d048da6
[Feat]: Bottom Item 템플릿 생성
jinuemong Jan 17, 2024
464ebf5
[Style]: 코드 포맷, 불필요 import 제거
jinuemong Jan 17, 2024
cb2d5e6
[Feat]: bottomNavigation bottomGraph 템플릿 구현
jinuemong Jan 17, 2024
da77509
[Feat]: bottomNavigation ui 구현과 click 이벤트 시 currentRoute 전환 기능 구현
jinuemong Jan 17, 2024
0d6f65a
[Feat]: bottomGraph 연결과 splash 스크린 기능 구현
jinuemong Jan 17, 2024
2d8992d
[Feat]: main ui 구현과 BottomView 적용
jinuemong Jan 17, 2024
a5ac921
[Fix]: 빌드 오류로 버전 수정
jinuemong Jan 17, 2024
13296bb
[Feat]: Sample item 생성
jinuemong Jan 17, 2024
afe58a2
[Feat]: bottom item 템플릿 생성
jinuemong Jan 17, 2024
9f38bb8
[Fix]: ConfirmButton Error로 임시 주석 처리
jinuemong Jan 17, 2024
45a0e99
[Feat]: Compose ui Theme 지정과 뷰 활성화
jinuemong Jan 17, 2024
8a9afad
[Style]: 코드 포맷 변경, 불필요 import 제거
jinuemong Jan 17, 2024
cee9986
[Refactor]: 각 item 구분하기 위한 SampleScreen 구현
jinuemong Jan 17, 2024
a6f47b9
[Refactor]: 코드 컨벤션 준수하여 패키지 분리, 패키지명 수정
jinuemong Jan 18, 2024
eb5c004
[Style]: 코드 포맷 수정, applicationState 코드 병합
jinuemong Jan 18, 2024
7e9528e
[Refactor]: 스플래쉬 스크린 분리
jinuemong Jan 18, 2024
e46ae5c
[Feat]: Navigation Graph의 Root 진입점을 구분하기 위한 enum 클래스 생성
jinuemong Jan 18, 2024
72275f7
[Feat]: SplashViewModel 구현과 화면 이동 기능 구현
jinuemong Jan 18, 2024
bfe20f2
[Feat]: Login 플로우를 담당하는 LOGIN ScreenRootConstant 생성
jinuemong Jan 18, 2024
56a8a0d
[Feat]: Login 화면 이동 기능 구현
jinuemong Jan 18, 2024
eaa17e0
[Feat]: SplashScreen에 ViewModel을 연결하고 분기별 화면 이동 기능 구현
jinuemong Jan 18, 2024
8bf1fa2
[Fix]: 스플래쉬 파라미터 전달 오류 수정
jinuemong Jan 19, 2024
ebca65b
[Feat]: 로그인 화면 이동 관련 LoginRootConstant 구현
jinuemong Jan 19, 2024
a1ad4a7
[Feat]: Login, OnBoard Empty Screen 생성
jinuemong Jan 19, 2024
90e9ec9
[Refactor]: 각 그래프 별 SplashScreen 분기 처리
jinuemong Jan 19, 2024
2033be8
[Feat]: Login Navigation 플로우를 처리하는 LoginNavGraph 기능 구현
jinuemong Jan 19, 2024
89477ac
[Feat]: LoginViewModel 기능 구현
jinuemong Jan 19, 2024
3d13db0
[Feat]: Login,OnBoard Screen 버튼 생성과 네비게이션 전환 기능 구현
jinuemong Jan 19, 2024
5f81d7a
[Refactor]: Graph에 따른 SplashScreen 분기 처리
jinuemong Jan 19, 2024
0562ba0
[Refactor]: MainGraph Splash 분기 수정
jinuemong Jan 19, 2024
fd5a2a6
[Feat]: systemUiController NavigationBar State 설정
jinuemong Jan 19, 2024
da5628f
[Refactor]: BottomBarScreen 색상, 간격 수정
jinuemong Jan 19, 2024
f2d8100
[Feat]: 로그인&온보딩 흐름에서 같은 ViewModel 인스턴스 유지하도록 구현
jinuemong Jan 19, 2024
3cbdd06
[Chore]: 코드 포맷 수정, 컨벤션 준수
jinuemong Jan 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@ android {
isMinifyEnabled = true
isShrinkResources = true
isDebuggable = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
isMinifyEnabled = false
isShrinkResources = false
isDebuggable = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
applicationIdSuffix = ".debug"
}
}
Expand Down
1 change: 0 additions & 1 deletion common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ android {

dependencies {
implementation(libs.bundles.kotlin)
implementation(libs.bundles.androidx.presentation)
implementation(libs.google.material)
implementation(libs.glide)

Expand Down
28 changes: 26 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ androidx-room = "2.6.1"
androidx-paging = "3.1.1"
# Google
google-material = "1.11.0"
system-contoller = "0.20.1"
# Network
ktor = "2.3.7"
kotlinx-serialization = "1.6.1"
Expand All @@ -44,6 +45,14 @@ leakcanary = "2.12"
okhttp3-logging-interceptor = "4.9.1"
# Common
ted-permission = "3.3.0"
# Compose
androidx-compose = "1.4.3"
compose-viewmodel = "2.7.0"
compose-coil = "1.3.2"
compose-livedata = "1.5.4"
compose-navi = "2.7.0"
compose-hiltnavi = "1.1.0"
compose-bottomsheet = "1.3.1"

[libraries]
# Kotlin
Expand Down Expand Up @@ -71,6 +80,7 @@ androidx-paging-runtime = { module = "androidx.paging:paging-runtime-ktx", versi
androidx-paging-common = { module = "androidx.paging:paging-common-ktx", version.ref = "androidx-paging" }
# Google
google-material = { module = "com.google.android.material:material", version.ref = "google-material" }
google-system-contoller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "system-contoller" }
# Network
ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
Expand All @@ -92,6 +102,19 @@ sentry = { module = "io.sentry:sentry-android", version.ref = "sentry" }
# Debug
leakcanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" }
okhttp3-logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp3-logging-interceptor" }
# Compose
compose-material = { module = "androidx.compose.material:material", version.ref = "androidx-compose" }
compose-ui-ui = { module = "androidx.compose.ui:ui", version.ref = "androidx-compose" }
compose-ui-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "androidx-compose" }
compose-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "compose-viewmodel" }
compose-navi = { module = "androidx.navigation:navigation-compose", version.ref = "compose-navi" }
compose-hiltnavi = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "compose-hiltnavi" }

compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "androidx-compose" }
compose-ui-test = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "androidx-compose" }
compose-bottomsheet = { module = "com.holix.android:bottomsheetdialog-compose", version.ref = "compose-bottomsheet" }
compose-coil = { module = "io.coil-kt:coil-compose", version.ref = "compose-coil" }
compose-livedata = { module = "androidx.compose.runtime:runtime-livedata", version.ref = "compose-livedata" }

[plugins]
android-application = { id = "com.android.application", version.ref = "plugin-gradle" }
Expand All @@ -106,9 +129,10 @@ sentry = { id = "io.sentry.android.gradle", version.ref = "plugin-sentry" }

[bundles]
kotlin = ["kotlin", "kotlinx-coroutines-android", "kotlinx-coroutines-core", "kotlinx-datetime"]
androidx-presentation = ["androidx-core", "androidx-appcompat", "androidx-constraintlayout", "androidx-fragment",
"androidx-viewmodel", "androidx-livedata", "androidx-navigation-fragment", "androidx-navigation-ui"]
androidx-data = ["androidx-room-runtime", "androidx-room-coroutine", "androidx-paging-runtime"]
androidx-presentation = ["androidx-core", "androidx-appcompat", "androidx-constraintlayout", "androidx-fragment",
"androidx-viewmodel", "androidx-livedata", "androidx-navigation-fragment", "androidx-navigation-ui",
"compose-ui-ui", "compose-ui-preview", "compose-material", "compose-viewmodel", "compose-hiltnavi", "compose-navi"]
network = ["ktor-core", "ktor-okhttp", "ktor-resources", "ktor-content-negotiation", "ktor-kotlinx-serialization",
"ktor-auth", "kotlinx-serialization"]
logging = ["timber", "sentry"]
24 changes: 22 additions & 2 deletions presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ android {

buildTypes {
debug {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
release {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}

Expand All @@ -37,6 +43,10 @@ android {

buildFeatures {
dataBinding = true
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.6"
}
}

Expand All @@ -59,6 +69,16 @@ dependencies {
implementation(libs.ted.permission)

implementation(libs.bundles.logging)

debugImplementation(libs.compose.ui.tooling)
debugImplementation(libs.compose.ui.test)

implementation(libs.compose.bottomsheet)
implementation(libs.compose.coil)
implementation(libs.compose.livedata)

implementation(libs.google.system.contoller)

}

fun getLocalProperty(propertyKey: String): String {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ac.dnd.bookkeeping.android.presentation.common.root

object LoginRootConstant {

const val LOGIN_MAIN = "loginMainScreen"
const val LOGIN_ONBOARD = "loginOnboardScreen"

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ac.dnd.bookkeeping.android.presentation.common.root

object MainRootConstant {

const val BOTTOM_FIRST = "firstScreen"
const val BOTTOM_SECOND = "secondScreen"
const val BOTTOM_THIRD = "thirdScreen"
const val BOTTOM_FOURTH = "fourthScreen"
const val BOTTOM_FIFTH = "fifthScreen"

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ac.dnd.bookkeeping.android.presentation.common.root

enum class RootEntryPoint {
LOGIN,
MAIN
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ac.dnd.bookkeeping.android.presentation.common.root

object ScreenRootConstant {

const val LOGIN_SPLASH = "loginSplashScreen"
const val MAIN_SPLASH = "mainSplashScreen"
const val LOGIN_GRAPH = "loginGraph"
const val MAIN_GRAPH = "mainGraph"

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ac.dnd.bookkeeping.android.presentation.common.state

import androidx.compose.material.ScaffoldState
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.google.accompanist.systemuicontroller.SystemUiController
import com.google.accompanist.systemuicontroller.rememberSystemUiController

@Stable
class ApplicationState(
val bottomBarState: MutableState<Boolean>,
val navController: NavHostController,
val systemUiController: SystemUiController,
val scaffoldState: ScaffoldState
)

@Composable
fun rememberApplicationState(
bottomBarState: MutableState<Boolean> = remember { mutableStateOf(false) },
navController: NavHostController = rememberNavController(),
systemUiController: SystemUiController = rememberSystemUiController(),
scaffoldState: ScaffoldState = rememberScaffoldState()
) = remember(
bottomBarState,
navController,
systemUiController,
scaffoldState
) {
ApplicationState(
bottomBarState = bottomBarState,
navController = navController,
systemUiController = systemUiController,
scaffoldState = scaffoldState
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ac.dnd.bookkeeping.android.presentation.common.state

import ac.dnd.bookkeeping.android.presentation.common.root.LoginRootConstant
import ac.dnd.bookkeeping.android.presentation.common.root.MainRootConstant
import ac.dnd.bookkeeping.android.presentation.common.root.ScreenRootConstant
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.navigation.compose.currentBackStackEntryAsState

@Composable
fun ManageSystemUiState(
appState: ApplicationState
) {
val navBackStackEntry by appState.navController.currentBackStackEntryAsState()

when (navBackStackEntry?.destination?.route) {

ScreenRootConstant.LOGIN_SPLASH, ScreenRootConstant.MAIN_SPLASH -> {
appState.systemUiController.isStatusBarVisible = false
appState.systemUiController.isNavigationBarVisible = false
appState.bottomBarState.value = false
}

MainRootConstant.BOTTOM_FIRST,
MainRootConstant.BOTTOM_SECOND,
MainRootConstant.BOTTOM_THIRD,
MainRootConstant.BOTTOM_FOURTH,
MainRootConstant.BOTTOM_FIFTH -> {
appState.systemUiController.isStatusBarVisible = false
appState.systemUiController.isNavigationBarVisible = true
appState.bottomBarState.value = true
}

LoginRootConstant.LOGIN_ONBOARD, LoginRootConstant.LOGIN_MAIN -> {
appState.systemUiController.isStatusBarVisible = true
appState.systemUiController.isNavigationBarVisible = true
appState.bottomBarState.value = false
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package ac.dnd.bookkeeping.android.presentation.ui.bottombar

import ac.dnd.bookkeeping.android.presentation.R
import ac.dnd.bookkeeping.android.presentation.common.root.MainRootConstant
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes

sealed class BottomBarItem(
val route: String,
@DrawableRes val drawableResId: Int,
@StringRes val stringResId: Int
) {
data object BottomFirst :
BottomBarItem(
route = MainRootConstant.BOTTOM_FIRST,
drawableResId = R.drawable.bottom_sample,
stringResId = R.string.bottom_sample
)

data object BottomSecond :
BottomBarItem(
route = MainRootConstant.BOTTOM_SECOND,
drawableResId = R.drawable.bottom_sample,
stringResId = R.string.bottom_sample
)

data object BottomThird :
BottomBarItem(
route = MainRootConstant.BOTTOM_THIRD,
drawableResId = R.drawable.bottom_sample,
stringResId = R.string.bottom_sample
)

data object BottomFourth :
BottomBarItem(
route = MainRootConstant.BOTTOM_FOURTH,
drawableResId = R.drawable.bottom_sample,
stringResId = R.string.bottom_sample
)

data object BottomFifth :
BottomBarItem(
route = MainRootConstant.BOTTOM_FIFTH,
drawableResId = R.drawable.bottom_sample,
stringResId = R.string.bottom_sample
)

companion object {
val BOTTOM_NAV_ITEMS = listOf<BottomBarItem>(
BottomFirst, BottomSecond, BottomThird, BottomFourth, BottomFifth
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package ac.dnd.bookkeeping.android.presentation.ui.bottombar

import ac.dnd.bookkeeping.android.presentation.common.root.ScreenRootConstant
import ac.dnd.bookkeeping.android.presentation.common.state.ApplicationState
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.compose.currentBackStackEntryAsState

@Composable
fun BottomBarScreen(
appState: ApplicationState,
bottomBarItems: List<BottomBarItem> = BottomBarItem.BOTTOM_NAV_ITEMS
) {

AnimatedVisibility(
visible = appState.bottomBarState.value,
modifier = Modifier
.fillMaxWidth()
.height(80.dp)
) {

BottomNavigation(
elevation = 0.dp,
backgroundColor = Color.LightGray,
modifier = Modifier.fillMaxSize()
) {
val navBackStackEntry by appState.navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route

bottomBarItems.forEach { screen ->

BottomNavigationItem(
selected = currentRoute == screen.route,
icon = {
Icon(
painter = painterResource(id = screen.drawableResId),
contentDescription = "bottom icon"
)
},
label = {
Text(
text = stringResource(id = screen.stringResId),
fontSize = 12.sp,
color = Color.Black,
modifier = Modifier.padding(0.dp)
)
},
selectedContentColor = Color.Black,
unselectedContentColor = Color.Gray,
onClick = {
appState.navController.navigate(screen.route) {
popUpTo(ScreenRootConstant.MAIN_GRAPH) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)

}
}

}
}
Loading