티스토리 뷰

레파지토리  전략

main: 프로젝트의 최신 안정 버전을 유지하는 브랜치
dev: 프로젝트의 개발이 이루어지는 브랜치

dev 브랜치에서 기능 구현, 버그 수정, UX 개선 등의 작업을 진행하고,

기능 개발이 완료 되었다면 dev 브랜치를 main 브랜치에 병합한다.

 

main 브랜치는 프로젝트 백업 및 앱 배포를 진행하는데 사용되는 브랜치이다.

 

 

폴더 구조

com.hamond.escapeanchovy/ (패키지명)
│    
├── constants/: 전역적으로 사용할 상수들 모음
│    
├── data/: 애플리케이션의 데이터 로직 및 API 호출 처리
│     ├── model/: 데이터 모델
│     ├── repository/: 데이터 관련 로직  
│	  │     └── ex/ (예시)
│     │            ├── ExRepository: 레파지토리 인터페이스
│     │            ├── ExRepositoryImpl: 레파지토리 구현체
│     │            └── ExRepositoryMoudle: 레파지토리 모듈
│     ├── source/: 
│            ├── local: 로컬 저장소와의 상호작용 담당
│            └── remote: 원격 서버와의 통신 관리
│
├── presentation/: 사용자에게 보여지는 부분
│     ├── preview/: 미리보기 화면 
│	  ├── ui/: UI 관련
│     │     ├── components/: 공통적으로 사용될 위젯 
│     │     ├── screens/: 앱 화면
│     │     └── state/: 각 화면의 상태 
│     └── viewmodel/: 각 화면의 뷰모델
│
├── ui.theme/: 
│     ├── Color: 테마별 색상
│     ├── Theme: 앱 테마 
│     └── Type: 텍스트 스타일
│
├── utils/: 전역적으로 사용할 유틸리티 함수 모음
│
├── MainActivity: MainActivity 및 내비게이션 설정
└── MyApplication: Hilt 초기화

Compose, MVVM, Respoistory, Hilt를 사용할 것이기에 폴더구조를 이런식으로 짰다.

 

 

폰트 시스템 정의

 

res/font에 사용할 폰트들을 추가한다.

오픈 타입 폰트(otf)가 디자인 자유도가 높다해서 이걸로 추가해줬다.

 

private val pretendard = FontFamily(
    Font(R.font.pretendard_regular, FontWeight.Normal),
    Font(R.font.pretendard_medium, FontWeight.Medium),
    Font(R.font.pretendard_bold, FontWeight.Bold)
)

data class CustomTypography(
    val h1Bold: TextStyle = TextStyle(
        fontFamily = pretendard,
        fontWeight = FontWeight.Bold,
        fontSize = 28.sp,
        lineHeight = 38.sp,
    ),
    val h1Medium: TextStyle = TextStyle(
        fontFamily = pretendard,
        fontWeight = FontWeight.Medium,
        fontSize = 28.sp,
        lineHeight = 38.sp,
    ),
    val h1Regular: TextStyle = TextStyle(
        fontFamily = pretendard,
        fontWeight = FontWeight.Normal,
        fontSize = 28.sp,
        lineHeight = 38.sp,
    )
    ...
)

ui.Theme/Type.kt에 폰트 스타일을 정의한다.

 

 

컬러 시스템 정의

private val DarkColorPalette = darkColors(
    primary = PrimaryDark,
    secondary = SecondaryDark,
    ...
)

private val LightColorPalette = lightColors(
    primary = Primary,
    secondaryVariant = Secondary
)

기존 방식으로 테마별 색상을 지정하려면 컬러 팔레트를 활용해야 하는데

이걸 활용하면 색 이름을 내가 원하는대로 지정할 수 없다는 문제점이 있다.

 

class CustomColorScheme(
    background: Color,
    ...
) {
    var background by mutableStateOf(background)
        private set
    ...
}

val customLightColorScheme by lazy {
    CustomColorScheme(
        background = Color(0xFFF9F9F9),
		...
    )
}

val customDarkColorScheme by lazy {
    CustomColorScheme(
        background = Color(0xFF222329),
		...
    )
}

그래서 ColorScheme 클래스를 선언하고 테마별 색상을 정의해줬다.

 

 

디자인 패턴 사용 설정

테마 파일에 정의한 디자인 패턴을 사용할 수 있도록 설정할 것이다.

 

// CompositionLocal 객체를 생성해 정의한 색상 및 글꼴을 앱 전체에 제공
val LocalColorScheme = staticCompositionLocalOf { customLightColorScheme }
val LocalTypography = staticCompositionLocalOf { CustomTypography() }

@Composable
fun EscapeAnchovyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    // 정의한 글꼴 데이터 클래스
    val typography = CustomTypography()
    
    // 테마별 색상 스키마 클래스
    val currentColor = remember {
        if (!darkTheme) {
            customLightColorScheme
        } else {
            customDarkColorScheme
        }
    }
	
    // CompositionLocal 객체 초기화
    CompositionLocalProvider(
        LocalColorScheme provides currentColor,
        LocalTypography provides typography
    ) {
    	// 기본 텍스트 스타일 지정
        ProvideTextStyle(
            typography.b4Regular.copy(color = CustomTheme.colors.text),
            content = content
        )
    }
}

// 전역적으로 사용할 수 있는 색상 및 폰트 제공 객체
object CustomTheme {
    val colors: CustomColorScheme
        @Composable
        @ReadOnlyComposable
        get() = LocalColorScheme.current

    val typography: CustomTypography
        @Composable
        @ReadOnlyComposable
        get() = LocalTypography.current
}

해당 테마는 앱에서 공통된 색상과 글꼴 스타일을 관리하고,

시스템 테마에 따라 다르게 제공할 수 있도록 해준다.

 

 

Hilt 설정

 

공식문서 따라 Hilt 설정 시 빌드오류가 발생하는 문제 해결

문제 상황 Hilt를 사용한 종속 항목 삽입  |  Android Developers이 페이지는 Cloud Translation API를 통해 번역되었습니다. Hilt를 사용한 종속 항목 삽입 컬렉션을 사용해 정리하기 내 환경설정을 기준으

tsi0511.tistory.com

이걸 참고하여 Hilt 종속성을 프로젝트에 추가해준다.

 

@HiltAndroidApp
class MyApplication : Application() {
    override fun onCreate() {
    	// 앱 시작 전 진행할 초기화 작업
    }
}

어플리케이션에서 전역적으로 Hilt를 사용할 수 있도록 설정한다.

 

 

Compose Navigation

dependencies {
    ...
    implementation("androidx.navigation:navigation-compose:2.7.5")
    implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
}

앱 수준 그래들 파일에 해당 라이브러리를 추가한다.

 

object Routes {
    const val LOGIN = "login"
    const val SIGN_UP = "sign_up"
    const val HOME = "home"
    ...
}

각 화면에 해당하는 루트 네임을 정의해준다.

 

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            EscapeAnchovyTheme {
                Surface(color = CustomTheme.colors.background) {
                    MyApp()
                }
            }
        }
    }
}

@Composable
fun MyApp() {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = LOGIN
    ) {
        composable(route = LOGIN) { LoginScreen(navController) }
        composable(route = SIGN_UP) { SignUpScreen(navController) }
        composable(route = HOME) { HomeScreen(navController) }
        ...
    }
}

NavHost를 사용하여 루트 네임에 따른 내비게이션을 지정한다.

 

 

한 곳에서 선언된 NavController를 사용하는 이유

NavController는 네비게이션의 상태(백 스택, 현재 경로 등)를 관리하는 객체이다.
위와 같이 한 곳에서 NavController 선언하고 다른 화면에 이를 전달하는 방식을
사용하면 모든 화면이 동일한 네비게이션 상태를 참조하게 된다.
만약 NavController를 각 화면에서 새로 선언하게 되면 화면마다 독립적인 
NavController가 생겨 네비게이션 상태가 공유되지 않는다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함