diff --git a/core/common/src/main/kotlin/com/ninecraft/booket/core/common/constants/ErrorDialogSpec.kt b/core/common/src/main/kotlin/com/ninecraft/booket/core/common/constants/ErrorDialogSpec.kt index a6cefa89..33ce49ec 100644 --- a/core/common/src/main/kotlin/com/ninecraft/booket/core/common/constants/ErrorDialogSpec.kt +++ b/core/common/src/main/kotlin/com/ninecraft/booket/core/common/constants/ErrorDialogSpec.kt @@ -2,6 +2,6 @@ package com.ninecraft.booket.core.common.constants data class ErrorDialogSpec( val message: String, - val buttonLabel: String, + val buttonLabelResId: Int, val action: () -> Unit, ) diff --git a/core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt b/core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt index 0920c555..fb2850a2 100644 --- a/core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt +++ b/core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt @@ -1,5 +1,7 @@ package com.ninecraft.booket.core.common.utils +import androidx.annotation.StringRes +import com.ninecraft.booket.core.common.R import com.ninecraft.booket.core.common.constants.ErrorDialogSpec import com.ninecraft.booket.core.common.constants.ErrorScope import com.ninecraft.booket.core.common.event.ErrorEvent @@ -46,11 +48,13 @@ fun handleException( fun postErrorDialog( errorScope: ErrorScope, exception: Throwable, + @StringRes buttonLabelResId: Int = R.string.confirm, action: () -> Unit = {}, ) { val spec = buildDialog( scope = errorScope, exception = exception, + buttonLabelResId = buttonLabelResId, action = action, ) @@ -60,6 +64,7 @@ fun postErrorDialog( private fun buildDialog( scope: ErrorScope, exception: Throwable, + @StringRes buttonLabelResId: Int, action: () -> Unit, ): ErrorDialogSpec { val message = when { @@ -92,7 +97,7 @@ private fun buildDialog( } } - return ErrorDialogSpec(message = message, buttonLabel = "확인", action = action) + return ErrorDialogSpec(message = message, buttonLabelResId = buttonLabelResId, action = action) } @Suppress("TooGenericExceptionCaught") diff --git a/core/common/src/main/res/values/strings.xml b/core/common/src/main/res/values/strings.xml index 71ff450b..45506ca4 100644 --- a/core/common/src/main/res/values/strings.xml +++ b/core/common/src/main/res/values/strings.xml @@ -5,4 +5,5 @@ 독서 완료 페이지순 최신 등록순 + 확인 diff --git a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookUpsertModel.kt b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookUpsertModel.kt index 40843cef..617f1d11 100644 --- a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookUpsertModel.kt +++ b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookUpsertModel.kt @@ -1,8 +1,5 @@ package com.ninecraft.booket.core.model -import androidx.compose.runtime.Stable - -@Stable data class BookUpsertModel( val userBookId: String, val userId: String, diff --git a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/ReadingRecordsModel.kt b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/ReadingRecordsModel.kt index f60f2dee..1c6356e1 100644 --- a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/ReadingRecordsModel.kt +++ b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/ReadingRecordsModel.kt @@ -1,5 +1,7 @@ package com.ninecraft.booket.core.model +import androidx.compose.runtime.Stable + data class ReadingRecordsModel( val lastPage: Boolean = true, val totalResults: Int = 0, @@ -8,6 +10,7 @@ data class ReadingRecordsModel( val readingRecords: List = emptyList(), ) +@Stable data class ReadingRecordModel( val id: String = "", val userBookId: String = "", diff --git a/core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/ReedScaffold.kt b/core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/ReedScaffold.kt index 3e4f4edd..be8a59c2 100644 --- a/core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/ReedScaffold.kt +++ b/core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/ReedScaffold.kt @@ -22,13 +22,13 @@ fun ReedScaffold( content: @Composable (PaddingValues) -> Unit, ) { Scaffold( + modifier = modifier.keyboardHide(), topBar = topBar, bottomBar = bottomBar, snackbarHost = snackbarHost, floatingActionButton = floatingActionButton, containerColor = containerColor, contentWindowInsets = contentWindowInsets, - modifier = modifier.keyboardHide(), ) { innerPadding -> content(innerPadding) } diff --git a/feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/MainActivity.kt b/feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/MainActivity.kt index 4ee9010b..93ad9fcc 100644 --- a/feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/MainActivity.kt +++ b/feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/MainActivity.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import com.ninecraft.booket.core.common.constants.ErrorDialogSpec import com.ninecraft.booket.core.common.event.ErrorEvent @@ -70,7 +71,8 @@ class MainActivity : ComponentActivity() { dialogSpec.value?.let { spec -> ReedDialog( description = spec.message, - confirmButtonText = spec.buttonLabel, + confirmButtonText = stringResource(spec.buttonLabelResId), + onConfirmRequest = { spec.action() dialogSpec.value = null diff --git a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt index fa7031e8..242b1c84 100644 --- a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt +++ b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt @@ -56,7 +56,7 @@ internal fun RecordRegisterUi( ) RecordProgressBar( currentStep = state.currentStep, - modifier = modifier.padding(horizontal = ReedTheme.spacing.spacing5), + modifier = Modifier.padding(horizontal = ReedTheme.spacing.spacing5), ) Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing10)) when (state.currentStep) { diff --git a/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt b/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt index 62efcce8..677465fc 100644 --- a/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt +++ b/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt @@ -158,7 +158,7 @@ class BookSearchPresenter @AssistedInject constructor( } is BookSearchUiEvent.OnSearchClick -> { - val query = event.text.trim() + val query = event.query.trim() if (query.isNotEmpty()) { searchBooks(query = query, startIndex = START_INDEX) } diff --git a/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUi.kt b/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUi.kt index 28b8ea15..42d48337 100644 --- a/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUi.kt +++ b/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUi.kt @@ -93,13 +93,13 @@ internal fun SearchContent( ReedTextField( queryState = state.queryState, queryHintRes = designR.string.search_book_hint, - onSearch = { text -> - state.eventSink(BookSearchUiEvent.OnSearchClick(text)) + onSearch = { query -> + state.eventSink(BookSearchUiEvent.OnSearchClick(query)) }, onClear = { state.eventSink(BookSearchUiEvent.OnClearClick) }, - modifier = modifier.padding(horizontal = ReedTheme.spacing.spacing5), + modifier = Modifier.padding(horizontal = ReedTheme.spacing.spacing5), borderStroke = BorderStroke(width = 1.dp, color = ReedTheme.colors.borderBrand), searchIconTint = ReedTheme.colors.contentBrand, ) diff --git a/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUiState.kt b/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUiState.kt index 3f534a38..edb48186 100644 --- a/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUiState.kt +++ b/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUiState.kt @@ -48,7 +48,7 @@ sealed interface BookSearchUiEvent : CircuitUiEvent { data object OnBackClick : BookSearchUiEvent data class OnRecentSearchClick(val query: String) : BookSearchUiEvent data class OnRecentSearchRemoveClick(val query: String) : BookSearchUiEvent - data class OnSearchClick(val text: String) : BookSearchUiEvent + data class OnSearchClick(val query: String) : BookSearchUiEvent data object OnClearClick : BookSearchUiEvent data class OnBookClick(val isbn13: String) : BookSearchUiEvent data object OnLoadMore : BookSearchUiEvent diff --git a/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/library/LibrarySearchUi.kt b/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/library/LibrarySearchUi.kt index b40cb66e..9634eb60 100644 --- a/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/library/LibrarySearchUi.kt +++ b/feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/library/LibrarySearchUi.kt @@ -75,13 +75,13 @@ internal fun LibrarySearchContent( ReedTextField( queryState = state.queryState, queryHintRes = R.string.library_search_hint, - onSearch = { text -> - state.eventSink(LibrarySearchUiEvent.OnSearchClick(text)) + onSearch = { query -> + state.eventSink(LibrarySearchUiEvent.OnSearchClick(query)) }, onClear = { state.eventSink(LibrarySearchUiEvent.OnClearClick) }, - modifier = modifier.padding(horizontal = ReedTheme.spacing.spacing5), + modifier = Modifier.padding(horizontal = ReedTheme.spacing.spacing5), backgroundColor = ReedTheme.colors.baseSecondary, borderStroke = null, ) diff --git a/feature/settings/src/main/assets/oss_licenses.json b/feature/settings/src/main/assets/oss_licenses.json index 71d1421f..ce75a00b 100644 --- a/feature/settings/src/main/assets/oss_licenses.json +++ b/feature/settings/src/main/assets/oss_licenses.json @@ -44,6 +44,56 @@ "license": "Apache License 2.0", "url": "https://github.com/coil-kt/coil" }, + { + "name": "Landscapist", + "license": "Apache License 2.0", + "url": "https://github.com/skydoves/landscapist" + }, + { + "name": "Google Analytics", + "license": "Apache License 2.0", + "url": "https://firebase.google.com/docs/analytics" + }, + { + "name": "Firebase Crashlytics", + "license": "Apache License 2.0", + "url": "https://firebase.google.com/docs/crashlytics" + }, + { + "name": "ML Kit Text Recognition", + "license": "Apache License 2.0", + "url": "https://developers.google.com/ml-kit/vision/text-recognition" + }, + { + "name": "Compose System UI Controller", + "license": "MIT License", + "url": "https://github.com/taehwandev/ComposeExtensions" + }, + { + "name": "Compose Keyboard State", + "license": "MIT License", + "url": "https://github.com/taehwandev/ComposeExtensions" + }, + { + "name": "Lottie Compose", + "license": "Apache License 2.0", + "url": "https://github.com/airbnb/lottie-android" + }, + { + "name": "Kakao SDK", + "license": "Apache License 2.0", + "url": "https://developers.kakao.com/docs/latest/ko/android/getting-started" + }, + { + "name": "Kotlinx Collections Immutable", + "license": "Apache License 2.0", + "url": "https://github.com/Kotlin/kotlinx.collections.immutable" + }, + { + "name": "Compose Shadow", + "license": "MIT License", + "url": "https://github.com/adamglin0/compose-shadow" + }, { "name": "Detekt", "license": "Apache License 2.0", diff --git a/feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt b/feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt index ef79f06f..b8715ef5 100644 --- a/feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt +++ b/feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt @@ -6,10 +6,13 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import com.ninecraft.booket.core.common.constants.ErrorScope +import com.ninecraft.booket.core.common.utils.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.AutoLoginState import com.ninecraft.booket.core.model.OnboardingState +import com.ninecraft.booket.core.ui.R import com.ninecraft.booket.feature.screens.HomeScreen import com.ninecraft.booket.feature.screens.LoginScreen import com.ninecraft.booket.feature.screens.OnboardingScreen @@ -50,8 +53,13 @@ class SplashPresenter @AssistedInject constructor( navigator.resetRoot(LoginScreen) } } - .onFailure { - navigator.resetRoot(LoginScreen) + .onFailure { exception -> + postErrorDialog( + errorScope = ErrorScope.GLOBAL, + exception = exception, + buttonLabelResId = R.string.retry, + action = { checkTermsAgreement() }, + ) } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 96ee3042..896dd695 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -123,7 +123,6 @@ landscapist-placeholder = { group = "com.github.skydoves", name = "landscapist-p kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" } -kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinx-datetime" } kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinx-collections-immutable" } circuit-foundation = { group = "com.slack.circuit", name = "circuit-foundation", version.ref = "circuit" }