From d4e3170f37aa9fa8f311a46947d3370908134202 Mon Sep 17 00:00:00 2001 From: easyhooon Date: Thu, 18 Dec 2025 17:54:40 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[BOOK-475]=20feat:=20LoginTooltipBox=20?= =?UTF-8?q?=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 CustomTooltipBox -> RecordTooltipBox로 네이밍 변경 --- .../login/component/LoginTooltipBox.kt | 99 +++++++++++++++++++ feature/login/src/main/res/values/strings.xml | 1 + ...ustomTooltipBox.kt => RecordTooltipBox.kt} | 6 +- .../feature/record/step/ImpressionStep.kt | 4 +- .../booket/feature/record/step/QuoteStep.kt | 4 +- 5 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt rename feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/{CustomTooltipBox.kt => RecordTooltipBox.kt} (94%) diff --git a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt new file mode 100644 index 00000000..45d6beff --- /dev/null +++ b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt @@ -0,0 +1,99 @@ +package com.ninecraft.booket.feature.login.component + +import androidx.annotation.StringRes +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Outline +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import com.ninecraft.booket.core.designsystem.ComponentPreview +import com.ninecraft.booket.core.designsystem.theme.ReedTheme +import com.ninecraft.booket.feature.login.R + +private val TriangleShape = object : Shape { + override fun createOutline( + size: Size, + layoutDirection: LayoutDirection, + density: Density, + ): Outline { + val path = Path().apply { + // 왼쪽 위 + moveTo(0f, 0f) + // 오른쪽 위 + lineTo(size.width, 0f) + // 중앙 아래 (뾰족한 부분) + lineTo(size.width / 2, size.height) + // 닫기 + close() + } + return Outline.Generic(path) + } +} + +@Composable +internal fun LoginTooltipBox( + @StringRes messageResId: Int, +) { + Column(horizontalAlignment = Alignment.Start) { + Box( + Modifier + .shadow(ReedTheme.radius.xs, RoundedCornerShape(ReedTheme.radius.xs), clip = false) + .clip(RoundedCornerShape(ReedTheme.radius.xs)) + .background(ReedTheme.colors.contentBrand) + .padding( + horizontal = ReedTheme.spacing.spacing3, + vertical = ReedTheme.spacing.spacing2, + ), + ) { + Text( + text = stringResource(messageResId), + color = ReedTheme.colors.contentInverse, + style = ReedTheme.typography.label2Regular, + ) + } + Box( + Modifier + .width(ReedTheme.spacing.spacing3) + .height(ReedTheme.spacing.spacing3 / 2) + .offset { + IntOffset( + x = 14.dp.roundToPx(), + y = 0, + ) + } + .graphicsLayer { + shadowElevation = 8.dp.toPx() + shape = TriangleShape + clip = true + } + .background(ReedTheme.colors.contentBrand), + ) + } +} + +@ComponentPreview +@Composable +private fun RecordTooltipBoxPreview() { + ReedTheme { + LoginTooltipBox(messageResId = R.string.recent_login) + } +} diff --git a/feature/login/src/main/res/values/strings.xml b/feature/login/src/main/res/values/strings.xml index 51ac38df..4250a70b 100644 --- a/feature/login/src/main/res/values/strings.xml +++ b/feature/login/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ 약관 전체 동의 시작하기 회원가입 없이 둘러보기 + 최근 로그인 (필수)서비스 이용약관 (필수)개인정보처리방침 diff --git a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/CustomTooltipBox.kt b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/RecordTooltipBox.kt similarity index 94% rename from feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/CustomTooltipBox.kt rename to feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/RecordTooltipBox.kt index 5fd7d65c..fb70bdff 100644 --- a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/CustomTooltipBox.kt +++ b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/RecordTooltipBox.kt @@ -23,7 +23,7 @@ import com.ninecraft.booket.core.designsystem.theme.ReedTheme import com.ninecraft.booket.feature.record.R @Composable -internal fun CustomTooltipBox( +internal fun RecordTooltipBox( @StringRes messageResId: Int, ) { Row(verticalAlignment = Alignment.CenterVertically) { @@ -65,8 +65,8 @@ internal fun CustomTooltipBox( @ComponentPreview @Composable -private fun CustomTooltipBoxPreview() { +private fun RecordTooltipBoxPreview() { ReedTheme { - CustomTooltipBox(messageResId = R.string.scan_tooltip_message) + RecordTooltipBox(messageResId = R.string.scan_tooltip_message) } } diff --git a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt index 016546ce..677e05df 100644 --- a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt +++ b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt @@ -51,7 +51,7 @@ import com.ninecraft.booket.core.designsystem.component.textfield.ReedRecordText import com.ninecraft.booket.core.designsystem.theme.ReedTheme import com.ninecraft.booket.core.designsystem.theme.White import com.ninecraft.booket.feature.record.R -import com.ninecraft.booket.feature.record.component.CustomTooltipBox +import com.ninecraft.booket.feature.record.component.RecordTooltipBox import com.ninecraft.booket.feature.record.component.ImpressionGuideBottomSheet import com.ninecraft.booket.feature.record.register.RecordRegisterUiEvent import com.ninecraft.booket.feature.record.register.RecordRegisterUiState @@ -156,7 +156,7 @@ fun ImpressionStep( verticalAlignment = Alignment.CenterVertically, ) { if (state.isImpressionGuideTooltipVisible) { - CustomTooltipBox( + RecordTooltipBox( messageResId = R.string.impression_guide_tooltip_message, ) } diff --git a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt index 602ed8f7..80e0835a 100644 --- a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt +++ b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt @@ -45,7 +45,7 @@ import com.ninecraft.booket.core.designsystem.component.textfield.digitOnlyInput import com.ninecraft.booket.core.designsystem.theme.ReedTheme import com.ninecraft.booket.core.designsystem.theme.White import com.ninecraft.booket.feature.record.R -import com.ninecraft.booket.feature.record.component.CustomTooltipBox +import com.ninecraft.booket.feature.record.component.RecordTooltipBox import com.ninecraft.booket.feature.record.register.RecordRegisterUiEvent import com.ninecraft.booket.feature.record.register.RecordRegisterUiState import com.skydoves.compose.stability.runtime.TraceRecomposition @@ -145,7 +145,7 @@ internal fun QuoteStep( verticalAlignment = Alignment.CenterVertically, ) { if (state.isScanTooltipVisible) { - CustomTooltipBox(messageResId = R.string.scan_tooltip_message) + RecordTooltipBox(messageResId = R.string.scan_tooltip_message) } ReedButton( From 55d9c59441aa7cefd86e68079698294e6c4d7f8b Mon Sep 17 00:00:00 2001 From: easyhooon Date: Fri, 26 Dec 2025 11:58:44 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[BOOK-475]=20feat:=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B0=A9=EC=8B=9D=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20=EC=9C=84=ED=95=9C=20DataStore=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=20=EA=B5=AC=EC=B6=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/api/repository/AuthRepository.kt | 7 +++ .../impl/repository/DefaultAuthRepository.kt | 14 ++++++ .../api/datasource/LoginMethodDataSource.kt | 10 ++++ .../DefaultLoginMethodDataSource.kt | 48 +++++++++++++++++++ .../core/datastore/impl/di/DataStoreGraph.kt | 13 +++++ .../datastore/impl/di/DataStoreQualifier.kt | 4 ++ .../booket/core/model/LoginMethod.kt | 7 +++ .../booket/feature/login/LoginPresenter.kt | 18 +++++++ .../booket/feature/login/LoginUiState.kt | 4 ++ 9 files changed, 125 insertions(+) create mode 100644 core/datastore/api/src/main/kotlin/com/ninecraft/booket/core/datastore/api/datasource/LoginMethodDataSource.kt create mode 100644 core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultLoginMethodDataSource.kt create mode 100644 core/model/src/main/kotlin/com/ninecraft/booket/core/model/LoginMethod.kt diff --git a/core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/AuthRepository.kt b/core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/AuthRepository.kt index c8943668..5dde9334 100644 --- a/core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/AuthRepository.kt +++ b/core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/AuthRepository.kt @@ -1,6 +1,7 @@ package com.ninecraft.booket.core.data.api.repository import com.ninecraft.booket.core.model.AutoLoginState +import com.ninecraft.booket.core.model.LoginMethod import com.ninecraft.booket.core.model.UserState import kotlinx.coroutines.flow.Flow @@ -16,4 +17,10 @@ interface AuthRepository { val userState: Flow suspend fun getCurrentUserState(): UserState + + val recentLoginMethod: Flow + + suspend fun setRecentLoginMethod(loginMethod: LoginMethod) + + suspend fun clearRecentLoginMethod() } diff --git a/core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultAuthRepository.kt b/core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultAuthRepository.kt index 4172d9e0..3163b68f 100644 --- a/core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultAuthRepository.kt +++ b/core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultAuthRepository.kt @@ -2,8 +2,10 @@ package com.ninecraft.booket.core.data.impl.repository import com.ninecraft.booket.core.common.utils.runSuspendCatching import com.ninecraft.booket.core.data.api.repository.AuthRepository +import com.ninecraft.booket.core.datastore.api.datasource.LoginMethodDataSource import com.ninecraft.booket.core.datastore.api.datasource.TokenDataSource import com.ninecraft.booket.core.model.AutoLoginState +import com.ninecraft.booket.core.model.LoginMethod import com.ninecraft.booket.core.model.UserState import com.ninecraft.booket.core.network.request.LoginRequest import com.ninecraft.booket.core.network.service.ReedService @@ -19,6 +21,7 @@ private const val KAKAO_PROVIDER_TYPE = "KAKAO" class DefaultAuthRepository( private val service: ReedService, private val tokenDataSource: TokenDataSource, + private val loginMethodDataSource: LoginMethodDataSource, ) : AuthRepository { override suspend fun login(accessToken: String) = runSuspendCatching { val response = service.login( @@ -38,6 +41,7 @@ class DefaultAuthRepository( override suspend fun withdraw() = runSuspendCatching { service.withdraw() clearTokens() + clearRecentLoginMethod() } private suspend fun saveTokens(accessToken: String, refreshToken: String) { @@ -51,6 +55,10 @@ class DefaultAuthRepository( tokenDataSource.clearTokens() } + override suspend fun clearRecentLoginMethod() { + loginMethodDataSource.clearRecentLoginMethod() + } + override val autoLoginState = tokenDataSource.accessToken .map { accessToken -> if (accessToken.isBlank()) AutoLoginState.NOT_LOGGED_IN else AutoLoginState.LOGGED_IN @@ -65,4 +73,10 @@ class DefaultAuthRepository( val accessToken = tokenDataSource.getAccessToken() return if (accessToken.isBlank()) UserState.Guest else UserState.LoggedIn } + + override val recentLoginMethod = loginMethodDataSource.recentLoginMethod + + override suspend fun setRecentLoginMethod(loginMethod: LoginMethod) { + loginMethodDataSource.setRecentLoginMethod(loginMethod) + } } diff --git a/core/datastore/api/src/main/kotlin/com/ninecraft/booket/core/datastore/api/datasource/LoginMethodDataSource.kt b/core/datastore/api/src/main/kotlin/com/ninecraft/booket/core/datastore/api/datasource/LoginMethodDataSource.kt new file mode 100644 index 00000000..5a3bcf79 --- /dev/null +++ b/core/datastore/api/src/main/kotlin/com/ninecraft/booket/core/datastore/api/datasource/LoginMethodDataSource.kt @@ -0,0 +1,10 @@ +package com.ninecraft.booket.core.datastore.api.datasource + +import com.ninecraft.booket.core.model.LoginMethod +import kotlinx.coroutines.flow.Flow + +interface LoginMethodDataSource { + val recentLoginMethod: Flow + suspend fun setRecentLoginMethod(loginMethod: LoginMethod) + suspend fun clearRecentLoginMethod() +} \ No newline at end of file diff --git a/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultLoginMethodDataSource.kt b/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultLoginMethodDataSource.kt new file mode 100644 index 00000000..0cef2c5e --- /dev/null +++ b/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultLoginMethodDataSource.kt @@ -0,0 +1,48 @@ +package com.ninecraft.booket.core.datastore.impl.datasource + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import com.ninecraft.booket.core.datastore.api.datasource.LoginMethodDataSource +import com.ninecraft.booket.core.datastore.impl.di.LoginMethodDataStore +import com.ninecraft.booket.core.datastore.impl.util.handleIOException +import com.ninecraft.booket.core.di.DataScope +import com.ninecraft.booket.core.model.LoginMethod +import dev.zacsweers.metro.Inject +import dev.zacsweers.metro.SingleIn +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +@SingleIn(DataScope::class) +@Inject +class DefaultLoginMethodDataSource( + @LoginMethodDataStore private val dataStore: DataStore, +) : LoginMethodDataSource { + override val recentLoginMethod: Flow = dataStore.data + .handleIOException() + .map { prefs -> + val method = prefs[RECENT_LOGIN_METHOD] + when (method) { + "KAKAO" -> LoginMethod.KAKAO + "GOOGLE" -> LoginMethod.GOOGLE + else -> LoginMethod.NONE + } + } + + override suspend fun setRecentLoginMethod(loginMethod: LoginMethod) { + dataStore.edit { prefs -> + prefs[RECENT_LOGIN_METHOD] = loginMethod.name + } + } + + override suspend fun clearRecentLoginMethod() { + dataStore.edit { prefs -> + prefs.remove(RECENT_LOGIN_METHOD) + } + } + + companion object { + private val RECENT_LOGIN_METHOD = stringPreferencesKey("RECENT_LOGIN_METHOD") + } +} \ No newline at end of file diff --git a/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreGraph.kt b/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreGraph.kt index a052bb43..b390b5ab 100644 --- a/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreGraph.kt +++ b/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreGraph.kt @@ -6,11 +6,13 @@ import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStore import com.ninecraft.booket.core.datastore.api.datasource.BookRecentSearchDataSource import com.ninecraft.booket.core.datastore.api.datasource.LibraryRecentSearchDataSource +import com.ninecraft.booket.core.datastore.api.datasource.LoginMethodDataSource import com.ninecraft.booket.core.datastore.api.datasource.NotificationDataSource import com.ninecraft.booket.core.datastore.api.datasource.OnboardingDataSource import com.ninecraft.booket.core.datastore.api.datasource.TokenDataSource import com.ninecraft.booket.core.datastore.impl.datasource.DefaultBookRecentSearchDataSource import com.ninecraft.booket.core.datastore.impl.datasource.DefaultLibraryRecentSearchDataSource +import com.ninecraft.booket.core.datastore.impl.datasource.DefaultLoginMethodDataSource import com.ninecraft.booket.core.datastore.impl.datasource.DefaultNotificationDataSource import com.ninecraft.booket.core.datastore.impl.datasource.DefaultOnboardingDataSource import com.ninecraft.booket.core.datastore.impl.datasource.DefaultTokenDataSource @@ -25,12 +27,14 @@ private const val BOOK_RECENT_SEARCH_DATASTORE_NAME = "BOOK_RECENT_SEARCH_DATAST private const val LIBRARY_RECENT_SEARCH_DATASTORE_NAME = "LIBRARY_RECENT_SEARCH_DATASTORE" private const val ONBOARDING_DATASTORE_NAME = "ONBOARDING_DATASTORE" private const val NOTIFICATION_DATASTORE_NAME = "NOTIFICATION_DATASTORE" +private const val LOGIN_METHOD_DATASTORE_NAME = "LOGIN_METHOD_DATASTORE" private val Context.tokenDataStore by preferencesDataStore(name = TOKEN_DATASTORE_NAME) private val Context.bookRecentSearchDataStore by preferencesDataStore(name = BOOK_RECENT_SEARCH_DATASTORE_NAME) private val Context.libraryRecentSearchDataStore by preferencesDataStore(name = LIBRARY_RECENT_SEARCH_DATASTORE_NAME) private val Context.onboardingDataStore by preferencesDataStore(name = ONBOARDING_DATASTORE_NAME) private val Context.notificationDataStore by preferencesDataStore(name = NOTIFICATION_DATASTORE_NAME) +private val Context.loginMethodDataStore by preferencesDataStore(name = LOGIN_METHOD_DATASTORE_NAME) @ContributesTo(DataScope::class) interface DataStoreGraph { @@ -65,6 +69,12 @@ interface DataStoreGraph { @ApplicationContext context: Context, ): DataStore = context.notificationDataStore + @LoginMethodDataStore + @Provides + fun provideLoginMethodDataStore( + @ApplicationContext context: Context, + ): DataStore = context.loginMethodDataStore + @Binds val DefaultTokenDataSource.bind: TokenDataSource @@ -79,4 +89,7 @@ interface DataStoreGraph { @Binds val DefaultNotificationDataSource.bind: NotificationDataSource + + @Binds + val DefaultLoginMethodDataSource.bind: LoginMethodDataSource } diff --git a/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreQualifier.kt b/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreQualifier.kt index 9dd43f0c..4f404203 100644 --- a/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreQualifier.kt +++ b/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreQualifier.kt @@ -21,3 +21,7 @@ annotation class OnboardingDataStore @Qualifier @Retention(AnnotationRetention.BINARY) annotation class NotificationDataStore + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class LoginMethodDataStore diff --git a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/LoginMethod.kt b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/LoginMethod.kt new file mode 100644 index 00000000..906e5ff5 --- /dev/null +++ b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/LoginMethod.kt @@ -0,0 +1,7 @@ +package com.ninecraft.booket.core.model + +enum class LoginMethod { + NONE, + KAKAO, + GOOGLE, +} \ No newline at end of file diff --git a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginPresenter.kt b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginPresenter.kt index 6a717c49..abda69fb 100644 --- a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginPresenter.kt +++ b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginPresenter.kt @@ -1,6 +1,7 @@ package com.ninecraft.booket.feature.login import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.rememberCoroutineScope @@ -10,6 +11,7 @@ import com.ninecraft.booket.core.common.constants.ErrorScope import com.ninecraft.booket.core.common.event.postErrorDialog import com.ninecraft.booket.core.data.api.repository.AuthRepository import com.ninecraft.booket.core.data.api.repository.UserRepository +import com.ninecraft.booket.core.model.LoginMethod import com.ninecraft.booket.feature.screens.HomeScreen import com.ninecraft.booket.feature.screens.LoginScreen import com.ninecraft.booket.feature.screens.TermsAgreementScreen @@ -50,6 +52,15 @@ class LoginPresenter( val scope = rememberCoroutineScope() var isLoading by rememberRetained { mutableStateOf(false) } var sideEffect by rememberRetained { mutableStateOf(null) } + var showLoginTooltip by rememberRetained { mutableStateOf(false) } + var recentLoginMethod by rememberRetained { mutableStateOf(LoginMethod.NONE) } + + LaunchedEffect(Unit) { + authRepository.recentLoginMethod.collect { method -> + recentLoginMethod = method + showLoginTooltip = method != LoginMethod.NONE + } + } fun navigateAfterLogin() { scope.launch { @@ -97,6 +108,7 @@ class LoginPresenter( isLoading = true authRepository.login(event.accessToken) .onSuccess { + authRepository.setRecentLoginMethod(LoginMethod.KAKAO) userRepository.syncFcmToken() navigateAfterLogin() }.onFailure { exception -> @@ -120,6 +132,10 @@ class LoginPresenter( is LoginUiEvent.OnCloseButtonClick -> { navigator.pop() } + + is LoginUiEvent.OnDismissLoginTooltip -> { + showLoginTooltip = false + } } } @@ -131,6 +147,8 @@ class LoginPresenter( isLoading = isLoading, returnToScreen = screen.returnToScreen, sideEffect = sideEffect, + showLoginTooltip = showLoginTooltip, + recentLoginMethod = recentLoginMethod, eventSink = ::handleEvent, ) } diff --git a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUiState.kt b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUiState.kt index 1f58e248..6af2f2ad 100644 --- a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUiState.kt +++ b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUiState.kt @@ -1,6 +1,7 @@ package com.ninecraft.booket.feature.login import androidx.compose.runtime.Immutable +import com.ninecraft.booket.core.model.LoginMethod import com.slack.circuit.runtime.CircuitUiEvent import com.slack.circuit.runtime.CircuitUiState import com.slack.circuit.runtime.screen.Screen @@ -10,6 +11,8 @@ data class LoginUiState( val isLoading: Boolean = false, val returnToScreen: Screen? = null, val sideEffect: LoginSideEffect? = null, + val showLoginTooltip: Boolean = false, + val recentLoginMethod: LoginMethod = LoginMethod.NONE, val eventSink: (LoginUiEvent) -> Unit, ) : CircuitUiState @@ -28,4 +31,5 @@ sealed interface LoginUiEvent : CircuitUiEvent { data class LoginFailure(val message: String) : LoginUiEvent data object OnGuestLoginButtonClick : LoginUiEvent data object OnCloseButtonClick : LoginUiEvent + data object OnDismissLoginTooltip : LoginUiEvent } From 4fee1382cc303ec2a77e23ddef3df459b0ecd7a4 Mon Sep 17 00:00:00 2001 From: easyhooon Date: Fri, 26 Dec 2025 14:24:48 +0900 Subject: [PATCH 3/6] =?UTF-8?q?[BOOK-475]=20feat:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EB=B2=84=ED=8A=BC=EC=97=90=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=ED=88=B4=ED=8C=81=20=EB=B0=B0=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ninecraft/booket/feature/login/LoginUi.kt | 163 ++++++++++-------- .../login/component/LoginTooltipBox.kt | 6 +- 2 files changed, 95 insertions(+), 74 deletions(-) diff --git a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt index 2b0d8f83..aeb788b8 100644 --- a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt +++ b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt @@ -2,14 +2,16 @@ package com.ninecraft.booket.feature.login import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding +import androidx.compose.ui.zIndex +import com.ninecraft.booket.core.common.extensions.noRippleClickable import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -20,6 +22,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import com.ninecraft.booket.core.designsystem.DevicePreview import com.ninecraft.booket.core.designsystem.component.button.ReedButton @@ -32,6 +35,7 @@ import com.ninecraft.booket.core.designsystem.theme.White import com.ninecraft.booket.core.ui.ReedScaffold import com.ninecraft.booket.core.ui.component.ReedCloseTopAppBar import com.ninecraft.booket.core.ui.component.ReedLoadingIndicator +import com.ninecraft.booket.feature.login.component.LoginTooltipBox import com.ninecraft.booket.feature.screens.LoginScreen import com.skydoves.compose.stability.runtime.TraceRecomposition import com.slack.circuit.codegen.annotations.CircuitInject @@ -52,87 +56,104 @@ internal fun LoginUi( ReedScaffold( modifier = modifier.fillMaxSize(), ) { innerPadding -> - Column( - modifier = modifier + Box( + modifier = Modifier .fillMaxSize() .background(White) - .padding(innerPadding), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, + .padding(innerPadding) + .then( + if (state.showLoginTooltip) { + Modifier.noRippleClickable { + state.eventSink(LoginUiEvent.OnDismissLoginTooltip) + } + } else { + Modifier + }, + ), ) { - Box(modifier = Modifier.fillMaxSize()) { - Column { - if (state.returnToScreen != null) { - ReedCloseTopAppBar( - onClose = { - state.eventSink(LoginUiEvent.OnCloseButtonClick) - }, - ) - } - Column( + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + if (state.returnToScreen != null) { + ReedCloseTopAppBar( + onClose = { + state.eventSink(LoginUiEvent.OnCloseButtonClick) + }, + ) + } + Spacer(modifier = Modifier.weight(1f)) + Image( + painter = painterResource(R.drawable.img_reed_logo_big), + contentDescription = "Reed Logo", + modifier = Modifier.height(67.14.dp), + ) + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing5)) + Text( + text = stringResource(R.string.login_reed_slogan), + color = ReedTheme.colors.contentBrand, + style = ReedTheme.typography.headline2SemiBold, + ) + Spacer(modifier = Modifier.weight(1f)) + Box( + modifier = Modifier + .fillMaxWidth(), + ) { + ReedButton( + onClick = { + state.eventSink(LoginUiEvent.OnKakaoLoginButtonClick) + }, + sizeStyle = largeButtonStyle, + colorStyle = ReedButtonColorStyle.KAKAO, modifier = Modifier .fillMaxWidth() - .weight(1f), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Image( - painter = painterResource(R.drawable.img_reed_logo_big), - contentDescription = "Reed Logo", - modifier = Modifier.height(67.14.dp), - ) - Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing5)) - Text( - text = stringResource(R.string.login_reed_slogan), - color = ReedTheme.colors.contentBrand, - style = ReedTheme.typography.headline2SemiBold, - ) - } - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - ReedButton( - onClick = { - state.eventSink(LoginUiEvent.OnKakaoLoginButtonClick) - }, - sizeStyle = largeButtonStyle, - colorStyle = ReedButtonColorStyle.KAKAO, + .padding( + start = ReedTheme.spacing.spacing5, + end = ReedTheme.spacing.spacing5, + ), + text = stringResource(id = R.string.kakao_login), + leadingIcon = { + Icon( + imageVector = ImageVector.vectorResource(id = R.drawable.ic_kakao), + contentDescription = "Kakao Icon", + tint = Color.Unspecified, + ) + }, + ) + + if (state.showLoginTooltip) { + LoginTooltipBox( + messageResId = R.string.recent_login, modifier = Modifier - .fillMaxWidth() - .padding( - start = ReedTheme.spacing.spacing5, - end = ReedTheme.spacing.spacing5, - ), - text = stringResource(id = R.string.kakao_login), - leadingIcon = { - Icon( - imageVector = ImageVector.vectorResource(id = R.drawable.ic_kakao), - contentDescription = "Kakao Icon", - tint = Color.Unspecified, - ) - }, - ) - Spacer( - modifier = Modifier.height(if (state.returnToScreen == null) ReedTheme.spacing.spacing2 else ReedTheme.spacing.spacing8), + .align(Alignment.BottomEnd) + .offset { + IntOffset( + x = (-28).dp.roundToPx(), + y = (-32).dp.roundToPx() + ) + } + .zIndex(10f) ) - if (state.returnToScreen == null) { - ReedTextButton( - onClick = { - state.eventSink(LoginUiEvent.OnGuestLoginButtonClick) - }, - text = stringResource(R.string.guest_login), - sizeStyle = smallButtonStyle, - colorStyle = ReedButtonColorStyle.TEXT, - ) - } } } - - if (state.isLoading) { - ReedLoadingIndicator() + Spacer( + modifier = Modifier.height(if (state.returnToScreen == null) ReedTheme.spacing.spacing2 else ReedTheme.spacing.spacing8), + ) + if (state.returnToScreen == null) { + ReedTextButton( + onClick = { + state.eventSink(LoginUiEvent.OnGuestLoginButtonClick) + }, + text = stringResource(R.string.guest_login), + sizeStyle = smallButtonStyle, + colorStyle = ReedButtonColorStyle.TEXT, + ) } } + + if (state.isLoading) { + ReedLoadingIndicator() + } } } } diff --git a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt index 45d6beff..48f9222d 100644 --- a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt +++ b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt @@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow @@ -52,10 +51,11 @@ private val TriangleShape = object : Shape { @Composable internal fun LoginTooltipBox( @StringRes messageResId: Int, + modifier: Modifier = Modifier, ) { - Column(horizontalAlignment = Alignment.Start) { + Column(modifier = modifier) { Box( - Modifier + modifier = Modifier .shadow(ReedTheme.radius.xs, RoundedCornerShape(ReedTheme.radius.xs), clip = false) .clip(RoundedCornerShape(ReedTheme.radius.xs)) .background(ReedTheme.colors.contentBrand) From 50ebe6ec076f4b3b67769c0405da9d7124002835 Mon Sep 17 00:00:00 2001 From: easyhooon Date: Fri, 26 Dec 2025 14:32:45 +0900 Subject: [PATCH 4/6] [BOOK-475] chore: code style check success --- .../booket/core/model/LoginMethod.kt | 2 +- .../ninecraft/booket/feature/login/LoginUi.kt | 3 +-- .../onboarding/stability/onboarding.stability | 21 ------------------- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/LoginMethod.kt b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/LoginMethod.kt index 906e5ff5..dd7f9445 100644 --- a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/LoginMethod.kt +++ b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/LoginMethod.kt @@ -4,4 +4,4 @@ enum class LoginMethod { NONE, KAKAO, GOOGLE, -} \ No newline at end of file +} diff --git a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt index aeb788b8..cbc7080f 100644 --- a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt +++ b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt @@ -129,10 +129,9 @@ internal fun LoginUi( .offset { IntOffset( x = (-28).dp.roundToPx(), - y = (-32).dp.roundToPx() + y = (-32).dp.roundToPx(), ) } - .zIndex(10f) ) } } diff --git a/feature/onboarding/stability/onboarding.stability b/feature/onboarding/stability/onboarding.stability index 4a020e64..50af8bfe 100644 --- a/feature/onboarding/stability/onboarding.stability +++ b/feature/onboarding/stability/onboarding.stability @@ -4,12 +4,6 @@ // Do not edit this file directly. To update it, run: // ./gradlew :onboarding:stabilityDump -@Composable -public fun com.ninecraft.booket.feature.onboarding.OnboardingPresenter.present(): com.ninecraft.booket.feature.onboarding.OnboardingUiState - skippable: true - restartable: true - params: - @Composable private fun com.ninecraft.booket.feature.onboarding.OnboardingScreenPreview(): kotlin.Unit skippable: true @@ -41,18 +35,3 @@ private fun com.ninecraft.booket.feature.onboarding.component.OnboardingPagePrev restartable: true params: -@Composable -internal fun com.ninecraft.booket.feature.onboarding.component.PagerIndicator(pageCount: kotlin.Int, pagerState: androidx.compose.foundation.pager.PagerState, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - pageCount: STABLE (primitive type) - - pagerState: STABLE (marked @Stable or @Immutable) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.ninecraft.booket.feature.onboarding.component.PagerIndicatorPreview(): kotlin.Unit - skippable: true - restartable: true - params: - From 810ad583d461ec1c30f226b7ff4f8a53739871fd Mon Sep 17 00:00:00 2001 From: easyhooon Date: Mon, 29 Dec 2025 17:41:46 +0900 Subject: [PATCH 5/6] [BOOK-475] chore: compose stability check success MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit compose stability analyzer 버전 최신화 --- app/stability/app.stability | 2 +- .../stability/designsystem.stability | 56 +++++++++---------- .../login/component/LoginTooltipBox.kt | 2 +- feature/login/stability/login.stability | 14 +++++ .../onboarding/stability/onboarding.stability | 21 +++++++ feature/record/stability/record.stability | 26 ++++----- gradle/libs.versions.toml | 2 +- 7 files changed, 79 insertions(+), 44 deletions(-) diff --git a/app/stability/app.stability b/app/stability/app.stability index dc1f99ee..93818f14 100644 --- a/app/stability/app.stability +++ b/app/stability/app.stability @@ -9,7 +9,7 @@ public fun com.ninecraft.booket.di.CrossFadeNavDecorator.Decoration(targetState: skippable: false restartable: true params: - - targetState: RUNTIME (requires runtime check) + - targetState: UNSTABLE (has mutable properties or unstable members) - innerContent: STABLE (composable function type) @Composable diff --git a/core/designsystem/stability/designsystem.stability b/core/designsystem/stability/designsystem.stability index 2bf67bed..ed4f6c9e 100644 --- a/core/designsystem/stability/designsystem.stability +++ b/core/designsystem/stability/designsystem.stability @@ -42,43 +42,53 @@ public fun com.ninecraft.booket.core.designsystem.component.ResourceImage(imageR - contentScale: STABLE (marked @Stable or @Immutable) @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle +public fun com.ninecraft.booket.core.designsystem.component.button.ReedButton(onClick: kotlin.Function0, text: kotlin.String, sizeStyle: com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle, colorStyle: com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle, modifier: androidx.compose.ui.Modifier, enabled: kotlin.Boolean, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, trailingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, multipleEventsCutterEnabled: kotlin.Boolean): kotlin.Unit skippable: true restartable: true params: + - onClick: STABLE (function type) + - text: STABLE (String is immutable) + - sizeStyle: STABLE (class with no mutable properties) + - colorStyle: STABLE (class with no mutable properties) + - modifier: STABLE (marked @Stable or @Immutable) + - enabled: STABLE (primitive type) + - leadingIcon: STABLE (composable function type) + - trailingIcon: STABLE (composable function type) + - multipleEventsCutterEnabled: STABLE (primitive type) @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle +public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.borderStroke(): androidx.compose.foundation.BorderStroke? skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle +public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.containerColor(isPressed: kotlin.Boolean): androidx.compose.ui.graphics.Color skippable: true restartable: true params: + - isPressed: STABLE (primitive type) @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle +public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.contentColor(): androidx.compose.ui.graphics.Color skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle +public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.disabledContainerColor(): androidx.compose.ui.graphics.Color skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle +public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.disabledContentColor(): androidx.compose.ui.graphics.Color skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.ReedButton(onClick: kotlin.Function0, text: kotlin.String, sizeStyle: com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle, colorStyle: com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle, modifier: androidx.compose.ui.Modifier, enabled: kotlin.Boolean, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, trailingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, multipleEventsCutterEnabled: kotlin.Boolean): kotlin.Unit +public fun com.ninecraft.booket.core.designsystem.component.button.ReedTextButton(onClick: kotlin.Function0, text: kotlin.String, sizeStyle: com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle, colorStyle: com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle, modifier: androidx.compose.ui.Modifier, enabled: kotlin.Boolean, multipleEventsCutterEnabled: kotlin.Boolean): kotlin.Unit skippable: true restartable: true params: @@ -88,53 +98,43 @@ public fun com.ninecraft.booket.core.designsystem.component.button.ReedButton(on - colorStyle: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) - enabled: STABLE (primitive type) - - leadingIcon: STABLE (composable function type) - - trailingIcon: STABLE (composable function type) - multipleEventsCutterEnabled: STABLE (primitive type) @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.borderStroke(): androidx.compose.foundation.BorderStroke? +public fun com.ninecraft.booket.core.designsystem.component.button.largeButtonStyle(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.containerColor(isPressed: kotlin.Boolean): androidx.compose.ui.graphics.Color +public fun com.ninecraft.booket.core.designsystem.component.button.largeRoundedButtonStyle(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle skippable: true restartable: true params: - - isPressed: STABLE (primitive type) @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.contentColor(): androidx.compose.ui.graphics.Color +public fun com.ninecraft.booket.core.designsystem.component.button.mediumButtonStyle(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.disabledContainerColor(): androidx.compose.ui.graphics.Color +public fun com.ninecraft.booket.core.designsystem.component.button.mediumRoundedButtonStyle(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle.disabledContentColor(): androidx.compose.ui.graphics.Color +public fun com.ninecraft.booket.core.designsystem.component.button.smallButtonStyle(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.component.button.ReedTextButton(onClick: kotlin.Function0, text: kotlin.String, sizeStyle: com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle, colorStyle: com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle, modifier: androidx.compose.ui.Modifier, enabled: kotlin.Boolean, multipleEventsCutterEnabled: kotlin.Boolean): kotlin.Unit +public fun com.ninecraft.booket.core.designsystem.component.button.smallRoundedButtonStyle(): com.ninecraft.booket.core.designsystem.component.button.ButtonSizeStyle skippable: true restartable: true params: - - onClick: STABLE (function type) - - text: STABLE (String is immutable) - - sizeStyle: STABLE (class with no mutable properties) - - colorStyle: STABLE (class with no mutable properties) - - modifier: STABLE (marked @Stable or @Immutable) - - enabled: STABLE (primitive type) - - multipleEventsCutterEnabled: STABLE (primitive type) @Composable public fun com.ninecraft.booket.core.designsystem.component.checkbox.CircleCheckBox(checked: kotlin.Boolean, onCheckedChange: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit @@ -207,31 +207,31 @@ public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme(content: @[Com - content: STABLE (composable function type) @Composable -public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.(): com.ninecraft.booket.core.designsystem.theme.ReedBorder +public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.border(): com.ninecraft.booket.core.designsystem.theme.ReedBorder skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.(): com.ninecraft.booket.core.designsystem.theme.ReedColorScheme +public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.colors(): com.ninecraft.booket.core.designsystem.theme.ReedColorScheme skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.(): com.ninecraft.booket.core.designsystem.theme.ReedRadius +public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.radius(): com.ninecraft.booket.core.designsystem.theme.ReedRadius skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.(): com.ninecraft.booket.core.designsystem.theme.ReedSpacing +public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.spacing(): com.ninecraft.booket.core.designsystem.theme.ReedSpacing skippable: true restartable: true params: @Composable -public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.(): com.ninecraft.booket.core.designsystem.theme.ReedTypography +public fun com.ninecraft.booket.core.designsystem.theme.ReedTheme.typography(): com.ninecraft.booket.core.designsystem.theme.ReedTypography skippable: true restartable: true params: diff --git a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt index 48f9222d..dfe09878 100644 --- a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt +++ b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/component/LoginTooltipBox.kt @@ -92,7 +92,7 @@ internal fun LoginTooltipBox( @ComponentPreview @Composable -private fun RecordTooltipBoxPreview() { +private fun LoginTooltipBoxPreview() { ReedTheme { LoginTooltipBox(messageResId = R.string.recent_login) } diff --git a/feature/login/stability/login.stability b/feature/login/stability/login.stability index 43c486b5..583e3126 100644 --- a/feature/login/stability/login.stability +++ b/feature/login/stability/login.stability @@ -32,6 +32,20 @@ internal fun com.ninecraft.booket.feature.login.LoginUi(state: com.ninecraft.boo - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) +@Composable +internal fun com.ninecraft.booket.feature.login.component.LoginTooltipBox(messageResId: kotlin.Int, modifier: androidx.compose.ui.Modifier): kotlin.Unit + skippable: true + restartable: true + params: + - messageResId: STABLE (primitive type) + - modifier: STABLE (marked @Stable or @Immutable) + +@Composable +private fun com.ninecraft.booket.feature.login.component.LoginTooltipBoxPreview(): kotlin.Unit + skippable: true + restartable: true + params: + @Composable internal fun com.ninecraft.booket.feature.termsagreement.HandleTermsAgreementSideEffects(state: com.ninecraft.booket.feature.termsagreement.TermsAgreementUiState): kotlin.Unit skippable: true diff --git a/feature/onboarding/stability/onboarding.stability b/feature/onboarding/stability/onboarding.stability index 50af8bfe..4a020e64 100644 --- a/feature/onboarding/stability/onboarding.stability +++ b/feature/onboarding/stability/onboarding.stability @@ -4,6 +4,12 @@ // Do not edit this file directly. To update it, run: // ./gradlew :onboarding:stabilityDump +@Composable +public fun com.ninecraft.booket.feature.onboarding.OnboardingPresenter.present(): com.ninecraft.booket.feature.onboarding.OnboardingUiState + skippable: true + restartable: true + params: + @Composable private fun com.ninecraft.booket.feature.onboarding.OnboardingScreenPreview(): kotlin.Unit skippable: true @@ -35,3 +41,18 @@ private fun com.ninecraft.booket.feature.onboarding.component.OnboardingPagePrev restartable: true params: +@Composable +internal fun com.ninecraft.booket.feature.onboarding.component.PagerIndicator(pageCount: kotlin.Int, pagerState: androidx.compose.foundation.pager.PagerState, modifier: androidx.compose.ui.Modifier): kotlin.Unit + skippable: true + restartable: true + params: + - pageCount: STABLE (primitive type) + - pagerState: STABLE (marked @Stable or @Immutable) + - modifier: STABLE (marked @Stable or @Immutable) + +@Composable +private fun com.ninecraft.booket.feature.onboarding.component.PagerIndicatorPreview(): kotlin.Unit + skippable: true + restartable: true + params: + diff --git a/feature/record/stability/record.stability b/feature/record/stability/record.stability index 0198cadd..41cde6e5 100644 --- a/feature/record/stability/record.stability +++ b/feature/record/stability/record.stability @@ -4,19 +4,6 @@ // Do not edit this file directly. To update it, run: // ./gradlew :record:stabilityDump -@Composable -internal fun com.ninecraft.booket.feature.record.component.CustomTooltipBox(messageResId: kotlin.Int): kotlin.Unit - skippable: true - restartable: true - params: - - messageResId: STABLE (primitive type) - -@Composable -private fun com.ninecraft.booket.feature.record.component.CustomTooltipBoxPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.record.component.ImpressionGuideBottomSheet(onDismissRequest: kotlin.Function0, sheetState: androidx.compose.material3.SheetState, impressionState: androidx.compose.foundation.text.input.TextFieldState, impressionGuideList: kotlinx.collections.immutable.ImmutableList, beforeSelectedImpressionGuide: kotlin.String, selectedImpressionGuide: kotlin.String, onGuideClick: kotlin.Function1, onCloseButtonClick: kotlin.Function0, onSelectionConfirmButtonClick: kotlin.Function0): kotlin.Unit skippable: true @@ -54,6 +41,19 @@ private fun com.ninecraft.booket.feature.record.component.ImpressionGuideBoxPrev restartable: true params: +@Composable +internal fun com.ninecraft.booket.feature.record.component.RecordTooltipBox(messageResId: kotlin.Int): kotlin.Unit + skippable: true + restartable: true + params: + - messageResId: STABLE (primitive type) + +@Composable +private fun com.ninecraft.booket.feature.record.component.RecordTooltipBoxPreview(): kotlin.Unit + skippable: true + restartable: true + params: + @Composable private fun com.ninecraft.booket.feature.record.ocr.CameraPreview(state: com.ninecraft.booket.feature.record.ocr.OcrUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b3f5690b..5e1377b6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ androidx-compose-material3 = "1.4.0" compose-stable-marker = "1.0.7" compose-effects = "0.1.4" compose-shadow = "2.0.4" -compose-stability-analyzer = "0.5.2" +compose-stability-analyzer = "0.6.6" ## Kotlin Symbol Processing ksp = "2.3.0" From afd22564d0b673cd825b2cbf99a228185a7272e8 Mon Sep 17 00:00:00 2001 From: easyhooon Date: Mon, 29 Dec 2025 17:43:21 +0900 Subject: [PATCH 6/6] [BOOK-475] chore: code style check success --- .../core/datastore/api/datasource/LoginMethodDataSource.kt | 2 +- .../impl/datasource/DefaultLoginMethodDataSource.kt | 2 +- .../kotlin/com/ninecraft/booket/feature/login/LoginUi.kt | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/datastore/api/src/main/kotlin/com/ninecraft/booket/core/datastore/api/datasource/LoginMethodDataSource.kt b/core/datastore/api/src/main/kotlin/com/ninecraft/booket/core/datastore/api/datasource/LoginMethodDataSource.kt index 5a3bcf79..b21df56a 100644 --- a/core/datastore/api/src/main/kotlin/com/ninecraft/booket/core/datastore/api/datasource/LoginMethodDataSource.kt +++ b/core/datastore/api/src/main/kotlin/com/ninecraft/booket/core/datastore/api/datasource/LoginMethodDataSource.kt @@ -7,4 +7,4 @@ interface LoginMethodDataSource { val recentLoginMethod: Flow suspend fun setRecentLoginMethod(loginMethod: LoginMethod) suspend fun clearRecentLoginMethod() -} \ No newline at end of file +} diff --git a/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultLoginMethodDataSource.kt b/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultLoginMethodDataSource.kt index 0cef2c5e..edb601d2 100644 --- a/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultLoginMethodDataSource.kt +++ b/core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultLoginMethodDataSource.kt @@ -45,4 +45,4 @@ class DefaultLoginMethodDataSource( companion object { private val RECENT_LOGIN_METHOD = stringPreferencesKey("RECENT_LOGIN_METHOD") } -} \ No newline at end of file +} diff --git a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt index cbc7080f..7cadd3c9 100644 --- a/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt +++ b/feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt @@ -10,8 +10,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding -import androidx.compose.ui.zIndex -import com.ninecraft.booket.core.common.extensions.noRippleClickable import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -24,6 +22,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp +import com.ninecraft.booket.core.common.extensions.noRippleClickable import com.ninecraft.booket.core.designsystem.DevicePreview import com.ninecraft.booket.core.designsystem.component.button.ReedButton import com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle @@ -131,7 +130,7 @@ internal fun LoginUi( x = (-28).dp.roundToPx(), y = (-32).dp.roundToPx(), ) - } + }, ) } }