Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
006156c
feat :: onboarding datastore ๊ตฌํ˜„
uson1004 Dec 7, 2025
13663ba
feat :: onboarding ๋ชจ๋“ˆ ์ถ”๊ฐ€
uson1004 Dec 7, 2025
f7d4ccc
feat :: onboarding datastore ๊ตฌํ˜„
uson1004 Dec 7, 2025
8e64624
feat :: onboarding ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ์— ์˜์กด์„ฑ ์ถ”๊ฐ€
uson1004 Dec 7, 2025
6cb7e5b
feat :: ์˜จ๋ณด๋”ฉ UI datastore ๊ตฌํ˜„
uson1004 Dec 8, 2025
6f01946
feat :: preference ์˜์กด์„ฑ ์ถ”๊ฐ€
uson1004 Dec 8, 2025
2b39cbe
feat :: ์˜จ๋ณด๋”ฉ ํ™”๋ฉด ๊ฐœ๋ฐœ
uson1004 Dec 8, 2025
4800669
refactor :: ๋””์ž์ธ ์‹œ์Šคํ…œ ์ฝ˜ํ”Œ๋ฆญํŠธ ํŒŒ์ผ ๋ถ„๋ฆฌ
uson1004 Dec 8, 2025
0ca756e
refactor :: ๋””์ž์ธ ์‹œ์Šคํ…œ ์ปฌ๋Ÿฌ ์ˆ˜์ •
uson1004 Dec 9, 2025
aed0ad2
feat :: button Primary ๋””์ž์ธ ์‹œ์Šคํ…œ ์ˆ˜์ •
uson1004 Dec 9, 2025
c9fceb8
refactor :: ๋กœ๊ณ  ์ด๋ฏธ์ง€ png๋กœ ๋ณ€๊ฒฝ
uson1004 Dec 9, 2025
4910699
refactor :: ์˜จ๋ณด๋”ฉ ํ…์ŠคํŠธ ์ปฌ๋Ÿฌ ๋ณ€๊ฒฝ
uson1004 Dec 9, 2025
8991c1d
fix :: ๋ฐฑ์Šคํƒ ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜ ํ•ด๊ฒฐ
uson1004 Dec 9, 2025
131e1ca
feat :: ๋””์ž์ธ ์‹œ์Šคํ…œ clickable ๊ตฌํ˜„
uson1004 Dec 9, 2025
a872ad4
feat :: ๋””์ž์ธ ์‹œ์Šคํ…œ modifyIf ๊ตฌํ˜„
uson1004 Dec 9, 2025
720bc54
feat :: ๋””์ž์ธ ์‹œ์Šคํ…œ ํ‚ค๋ณด๋“œ ์ƒํƒœ ๊ตฌํ˜„
uson1004 Dec 9, 2025
eb1e22a
refactor :: feature ํŒŒ์ผ ๋ฃจํŠธ ๋ณ€๊ฒฝ
uson1004 Dec 9, 2025
5a984ef
refactor :: onboarding ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ ๋ถ„๋ฆฌ
uson1004 Dec 9, 2025
9c18a5c
feat :: BaseStateViewModel ๊ตฌํ˜„
uson1004 Dec 10, 2025
e09b799
chore :: flavors ์ฝ˜ํ”Œ๋ฆญํŠธ ํ•ด๊ฒฐ
uson1004 Dec 10, 2025
f304ef1
refactor :: onboarding navigator ์ถ”๊ฐ€
uson1004 Dec 10, 2025
4cd2a14
refactor :: onboardingDataSource OnboardingViewModel๋กœ ๊ตฌํ˜„
uson1004 Dec 10, 2025
c45903f
chore :: ktlint check
uson1004 Dec 12, 2025
8fa4b06
refactor :: ์˜จ๋ณด๋”ฉ ๋ฐฑ์Šคํƒ ์‚ญ์ œ
uson1004 Dec 12, 2025
b4c1458
refactor :: ์ฑ„๋„์— ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๋‹ค ์ฐฐ ์‹œ ์ด๋ฒคํŠธ ๋“œ๋ž
uson1004 Dec 13, 2025
e9204a4
refactor :: setState ํ˜„์žฌ ์ƒํƒœ ๋žŒ๋‹ค๋กœ ์ „๋‹ฌ
uson1004 Dec 13, 2025
9f9a13c
refactor :: ๊ฐ€๋…์„ฑ ๋ฐ ์ผ๊ด€์„ฑ ๊ฐœ์„  ๋„ค์ด๋ฐ ์ˆ˜์ •
uson1004 Dec 13, 2025
8fe3da9
refactor :: button ๋””์ž์ธ ์‹œ์Šคํ…œ ์ˆ˜์ •
uson1004 Dec 13, 2025
ae79d45
refactor :: onboarding viewmodel setState ๋žŒ๋‹ค ์ ์šฉ
uson1004 Dec 13, 2025
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
4 changes: 3 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,11 @@ dependencies {
implementation(project(ProjectPaths.Core.NOTIFICATION))
implementation(project(ProjectPaths.Core.DEVICE))
implementation(project(ProjectPaths.Core.WIDGET))
implementation(project(ProjectPaths.Core.ONBOARDING))

implementation(project(ProjectPaths.DATA))
implementation(project(ProjectPaths.DATABASE))
add("prodImplementation", project(ProjectPaths.FEATURE))
implementation(project(ProjectPaths.FEATURE))
implementation(project(ProjectPaths.NETWORK))

implementation(libs.androidx.core)
Expand All @@ -124,6 +125,7 @@ dependencies {
add("prodImplementation", libs.androidx.hilt.navigation.compose)
add("devImplementation", libs.androidx.navigation3.runtime)
add("devImplementation", libs.androidx.navigation3.ui)
add("devImplementation", libs.androidx.hilt.navigation.compose)
Comment on lines 125 to +128
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

hilt-navigation-compose ์ข…์†์„ฑ์ด prodImplementation๊ณผ devImplementation์— ์ค‘๋ณต์œผ๋กœ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ข…์†์„ฑ์ด ๋‘ ๋นŒ๋“œ ์œ ํ˜• ๋ชจ๋‘์— ํ•„์š”ํ•˜๋‹ค๋ฉด implementation์œผ๋กœ ํ•œ ๋ฒˆ๋งŒ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ค‘๋ณต์„ ํ”ผํ•˜๊ณ  Gradle ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋” ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    implementation(libs.androidx.hilt.navigation.compose)
    add("devImplementation", libs.androidx.navigation3.runtime)
    add("devImplementation", libs.androidx.navigation3.ui)


implementation(libs.androidx.lifecycle.runtime.compose)

Expand Down
89 changes: 45 additions & 44 deletions app/src/dev/kotlin/team/aliens/dms/android/app/DmsApp.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package team.aliens.dms.android.app

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
Expand All @@ -19,59 +15,64 @@ import androidx.navigation3.ui.NavDisplay
import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.Serializable
import team.aliens.dms.android.core.designsystem.DmsTheme
import team.aliens.dms.android.core.designsystem.LocalToast
import team.aliens.dms.android.feature.onboarding.navigation.OnboardingRoute
import team.aliens.dms.android.feature.signin.navigation.SignInRoute

@Serializable
data object ScreenA : NavKey
data object OnboardingScreenNav : NavKey

@Serializable
data object ScreenB : NavKey
data object SignInScreenNav : NavKey

@Serializable
data object MainScreenNav : NavKey

@Composable
fun DmsApp(
windowSizeClass: WindowSizeClass,
// displayFeatures: List<DisplayFeature>,
isJwtAvailable: StateFlow<Boolean>,
// appState: DmsAppState = rememberDmsAppState(
// isJwtAvailable = isJwtAvailable,
// ),
mainViewModel: MainActivityViewModel,
) {
val backStack = rememberNavBackStack(ScreenA)
val isUpdateFailed by mainViewModel.isUpdateFailed.collectAsState()
val toast = LocalToast.current
val isOnboardingCompleted by mainViewModel.isOnboardingCompleted.collectAsState()
val isJwtAvailableState by isJwtAvailable.collectAsState()

val backStack = rememberNavBackStack(OnboardingScreenNav)

if (isUpdateFailed) {
LaunchedEffect(Unit) {
toast.showErrorToast(
message = "์—…๋ฐ์ดํŠธ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค",
)
LaunchedEffect(isOnboardingCompleted, isJwtAvailableState) {
val initialScreen = when {
!isOnboardingCompleted -> OnboardingScreenNav
isJwtAvailableState -> MainScreenNav
else -> SignInScreenNav
}
mainViewModel.consumeUpdateFailed()
}

Box(
modifier = Modifier
.fillMaxSize()
.systemBarsPadding(),
contentAlignment = Alignment.Center,
) {
NavDisplay(
backStack = backStack,
onBack = { backStack.removeLastOrNull() },
entryProvider = entryProvider {
entry<ScreenA> {
Button(onClick = { backStack.add(ScreenB) }) {
Text("Go to Screen B")
}
}
entry<ScreenB> {
Text(
text = "Screen B",
color = DmsTheme.colorScheme.onSurface,
)
}
},
)
if (backStack.lastOrNull() != initialScreen) {
backStack.clear()
backStack.add(initialScreen)
}
Comment on lines +41 to +51
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The navigation logic runs on every recomposition when isOnboardingCompleted or isJwtAvailableState changes, which could cause unnecessary navigation stack manipulations. Consider using a more stable approach or adding a flag to track if initial navigation has been performed.

Copilot uses AI. Check for mistakes.
}

NavDisplay(
modifier = Modifier.systemBarsPadding(),
backStack = backStack,
onBack = { backStack.removeLastOrNull() },
entryProvider = entryProvider {
entry<OnboardingScreenNav> {
OnboardingRoute(
navigateToSignIn = {
backStack.clear()
backStack.add(SignInScreenNav)
},
)
}
entry<SignInScreenNav> {
SignInRoute()
}
entry<MainScreenNav> {
Text(
text = "Main Screen (TODO)",
color = DmsTheme.colorScheme.onSurface,
)
}
},
)
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
package team.aliens.dms.android.app

import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import team.aliens.dms.android.core.jwt.JwtProvider
import team.aliens.dms.android.core.ui.viewmodel.BaseViewModel
import team.aliens.dms.android.onboarding.datastore.OnboardingDataStoreDataSource
import javax.inject.Inject

@HiltViewModel
class MainActivityViewModel @Inject constructor(
private val jwtProvider: JwtProvider,
private val onboardingDataSource: OnboardingDataStoreDataSource,
) : BaseViewModel() {
val autoSignInAvailable: StateFlow<Boolean> = jwtProvider.isCachedAccessTokenAvailable

private val _isUpdateFailed = MutableStateFlow(false)
val isUpdateFailed = _isUpdateFailed.asStateFlow()

fun onUpdateFailed() {
_isUpdateFailed.value = true
private val _isOnboardingCompleted = MutableStateFlow(false)
val isOnboardingCompleted: StateFlow<Boolean> = _isOnboardingCompleted.asStateFlow()

init {
viewModelScope.launch {
_isOnboardingCompleted.value = onboardingDataSource.getOnboardingCompleted()
}
}

fun consumeUpdateFailed() {
_isUpdateFailed.value = false
fun onUpdateFailed() {
_isUpdateFailed.value = true
}
}
25 changes: 25 additions & 0 deletions app/src/prod/kotlin/team/aliens/dms/android/app/DmsApplication.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package team.aliens.dms.android.app

import android.app.Application
import androidx.core.content.res.ResourcesCompat
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import dagger.hilt.android.HiltAndroidApp
Expand All @@ -16,4 +17,28 @@ class DmsApplication : Application(), Configuration.Provider {
get() = Configuration.Builder()
.setWorkerFactory(workFactory)
.build()

override fun onCreate() {
super.onCreate()
preloadFonts()
}

private fun preloadFonts() {
// Preload fonts to prevent text rendering delay
try {
val fontIds = listOf(
team.aliens.dms.android.core.designsystem.R.font.noto_sans_kr_black,
team.aliens.dms.android.core.designsystem.R.font.noto_sans_kr_bold,
team.aliens.dms.android.core.designsystem.R.font.noto_sans_kr_light,
team.aliens.dms.android.core.designsystem.R.font.noto_sans_kr_medium,
team.aliens.dms.android.core.designsystem.R.font.noto_sans_kr_regular,
team.aliens.dms.android.core.designsystem.R.font.noto_sans_kr_thin,
)
fontIds.forEach { fontId ->
ResourcesCompat.getFont(this, fontId)
}
} catch (e: Exception) {
// Font preloading failed, but continue app initialization
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

preloadFonts ํ•จ์ˆ˜ ๋‚ด์˜ catch ๋ธ”๋ก์ด ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค. ํฐํŠธ ํ”„๋ฆฌ๋กœ๋”ฉ์— ์‹คํŒจํ•˜๋”๋ผ๋„ ์•ฑ ์‹คํ–‰์„ ๊ณ„์†ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ๊ฒฐ์ •์ด์ง€๋งŒ, ๋””๋ฒ„๊น…์„ ์œ„ํ•ด ์‹คํŒจ ์‹œ ์˜ˆ์™ธ๋ฅผ ๋กœ๊น…ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

            // Font preloading failed, but continue app initialization
            e.printStackTrace() // ๋˜๋Š” Logger๋ฅผ ์‚ฌ์šฉํ•ด ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ import team.aliens.dms.android.feature.editpassword.navigation.EditPasswordNavGr
import team.aliens.dms.android.feature.outing.navigation.OutingNavGraph
import team.aliens.dms.android.feature.resetpassword.navigation.ResetPasswordNavGraph
import team.aliens.dms.android.feature.signup.navigation.SignUpNavGraph
import team.aliens.dms.android.feature.voting.navigation.VotingNavGraph
import team.aliens.dms.android.feature.volunteers.navigation.VolunteersNavGraph
import team.aliens.dms.android.feature.voting.navigation.VotingNavGraph
import java.util.UUID

class DmsNavigator(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ import team.aliens.dms.android.feature.destinations.PointHistoryScreenDestinatio
import team.aliens.dms.android.feature.destinations.RemainsApplicationScreenDestination
import team.aliens.dms.android.feature.destinations.StudyRoomDetailsScreenDestination
import team.aliens.dms.android.feature.destinations.StudyRoomListScreenDestination
import team.aliens.dms.android.feature.destinations.VolunteersScreenDestination
import team.aliens.dms.android.feature.destinations.VotingApprovalScreenDestination
import team.aliens.dms.android.feature.destinations.VotingModelStudentScreenDestination
import team.aliens.dms.android.feature.destinations.VotingSelectedScreenDestination
import team.aliens.dms.android.feature.destinations.VotingStudentScreenDestination
import team.aliens.dms.android.feature.destinations.VolunteersScreenDestination
import team.aliens.dms.android.feature.editpassword.navigation.EditPasswordNavGraph
import team.aliens.dms.android.feature.outing.navigation.OutingNavGraph
import team.aliens.dms.android.feature.studyroom.navigation.StudyRoomNavGraph
import team.aliens.dms.android.feature.voting.navigation.VotingNavGraph
import team.aliens.dms.android.feature.volunteers.navigation.VolunteersNavGraph
import team.aliens.dms.android.feature.voting.navigation.VotingNavGraph

object AuthorizedNavGraph : NavGraphSpec {
override val route: String = "authorized"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import team.aliens.dms.android.feature.outing.navigation.OutingNavigator
import team.aliens.dms.android.feature.point.navigation.PointHistoryNavigator
import team.aliens.dms.android.feature.remains.navigator.RemainsNavigator
import team.aliens.dms.android.feature.studyroom.navigation.StudyRoomNavigator
import team.aliens.dms.android.feature.voting.navigation.VotingNavigator
import team.aliens.dms.android.feature.volunteers.navigation.VolunteersNavigator
import team.aliens.dms.android.feature.voting.navigation.VotingNavigator

interface AuthorizedNavigator :
MainNavigator,
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ plugins {
alias(libs.plugins.ksp) apply false
alias(libs.plugins.jetbrainsKotlinJvm) apply false
alias(libs.plugins.firebase.crashlytics) apply false
alias(libs.plugins.compose.compiler) apply false
}
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/ProjectPaths.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ object ProjectPaths {
const val NOTIFICATION = ":core:notification"
const val DEVICE = ":core:device"
const val WIDGET = ":core:widget"
const val ONBOARDING = ":core:onboarding"
}

object Shared {
Expand Down
2 changes: 1 addition & 1 deletion core/datastore/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ dependencies {
implementation(libs.androidx.core)
implementation(libs.androidx.appcompat)

implementation(libs.androidx.datastore.preferences)
api(libs.androidx.datastore.preferences)

implementation(libs.hilt)
ksp(libs.hilt.compiler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ internal val Context.jwtStore: PreferencesDataStore by preferencesDataStore("jwt
internal val Context.featuresStore: PreferencesDataStore by preferencesDataStore("features-datastore")

internal val Context.deviceStore: PreferencesDataStore by preferencesDataStore("device-datastore")

internal val Context.onboardingStore: PreferencesDataStore by preferencesDataStore("onboarding-datastore")
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ annotation class FeaturesDataStore
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class JwtDataStore

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OnboardingDataStore
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import dagger.hilt.components.SingletonComponent
import team.aliens.dms.android.core.datastore.DeviceDataStore
import team.aliens.dms.android.core.datastore.FeaturesDataStore
import team.aliens.dms.android.core.datastore.JwtDataStore
import team.aliens.dms.android.core.datastore.OnboardingDataStore
import team.aliens.dms.android.core.datastore.PreferencesDataStore
import team.aliens.dms.android.core.datastore.deviceStore
import team.aliens.dms.android.core.datastore.featuresStore
import team.aliens.dms.android.core.datastore.jwtStore
import team.aliens.dms.android.core.datastore.onboardingStore
import javax.inject.Singleton

@Module
Expand All @@ -39,4 +41,11 @@ internal object DataStoreModule {
fun provideDeviceDataStore(
@ApplicationContext context: Context,
): PreferencesDataStore = context.deviceStore

@Provides
@Singleton
@OnboardingDataStore
fun provideOnboardingDataStore(
@ApplicationContext context: Context,
): PreferencesDataStore = context.onboardingStore
}
Loading
Loading