diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index f3e8862f5..50a4d03d3 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -84,5 +84,8 @@ jobs: - name: Generate google-services.json run: echo '${{ secrets.GOOGLE_SERVICES }}' | base64 -d > ./app/google-services.json + - name: Compose Stability Dump + run: ./gradlew stabilityDump + - name: Compose Stability Check run: ./gradlew stabilityCheck diff --git a/app/stability/app.stability b/app/stability/app.stability index dc1f99ee2..93818f146 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/src/main/kotlin/com/ninecraft/booket/core/designsystem/ComponentPreview.kt b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/ComponentPreview.kt index 065804537..488855406 100644 --- a/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/ComponentPreview.kt +++ b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/ComponentPreview.kt @@ -1,7 +1,6 @@ package com.ninecraft.booket.core.designsystem import android.content.res.Configuration.UI_MODE_NIGHT_NO -import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.ui.tooling.preview.Preview @Preview( @@ -9,9 +8,4 @@ import androidx.compose.ui.tooling.preview.Preview showBackground = true, uiMode = UI_MODE_NIGHT_NO, ) -@Preview( - name = "Dark", - showBackground = true, - uiMode = UI_MODE_NIGHT_YES, -) annotation class ComponentPreview diff --git a/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/DevicePreview.kt b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/DevicePreview.kt index 8dbd713d1..ad9b39ac4 100644 --- a/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/DevicePreview.kt +++ b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/DevicePreview.kt @@ -1,7 +1,6 @@ package com.ninecraft.booket.core.designsystem import android.content.res.Configuration.UI_MODE_NIGHT_NO -import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.ui.tooling.preview.Preview @Preview( @@ -10,10 +9,4 @@ import androidx.compose.ui.tooling.preview.Preview uiMode = UI_MODE_NIGHT_NO, device = "spec:width=360dp,height=800dp,dpi=411", ) -@Preview( - name = "Dark", - showBackground = true, - uiMode = UI_MODE_NIGHT_YES, - device = "spec:width=360dp,height=800dp,dpi=411", -) annotation class DevicePreview diff --git a/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/Emotion.kt b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/Emotion.kt index 931074a10..52bb4fdb0 100644 --- a/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/Emotion.kt +++ b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/Emotion.kt @@ -1,14 +1,21 @@ package com.ninecraft.booket.core.designsystem import androidx.compose.ui.graphics.Color +import com.ninecraft.booket.core.designsystem.theme.Blue300 +import com.ninecraft.booket.core.designsystem.theme.EtcBgColor +import com.ninecraft.booket.core.designsystem.theme.EtcTextColor import com.ninecraft.booket.core.designsystem.theme.InsightBgColor import com.ninecraft.booket.core.designsystem.theme.InsightTextColor import com.ninecraft.booket.core.designsystem.theme.JoyBgColor import com.ninecraft.booket.core.designsystem.theme.JoyTextColor +import com.ninecraft.booket.core.designsystem.theme.Neutral300 +import com.ninecraft.booket.core.designsystem.theme.Orange300 import com.ninecraft.booket.core.designsystem.theme.SadnessBgColor import com.ninecraft.booket.core.designsystem.theme.SadnessTextColor +import com.ninecraft.booket.core.designsystem.theme.Violet300 import com.ninecraft.booket.core.designsystem.theme.WarmthBgColor import com.ninecraft.booket.core.designsystem.theme.WarmthTextColor +import com.ninecraft.booket.core.designsystem.theme.Yellow300 import com.ninecraft.booket.core.model.Emotion val Emotion.bgColor: Color @@ -17,6 +24,7 @@ val Emotion.bgColor: Color Emotion.JOY -> JoyBgColor Emotion.SAD -> SadnessBgColor Emotion.INSIGHT -> InsightBgColor + Emotion.ETC -> EtcBgColor } val Emotion.textColor: Color @@ -25,6 +33,7 @@ val Emotion.textColor: Color Emotion.JOY -> JoyTextColor Emotion.SAD -> SadnessTextColor Emotion.INSIGHT -> InsightTextColor + Emotion.ETC -> EtcTextColor } val Emotion.graphicRes: Int @@ -33,14 +42,25 @@ val Emotion.graphicRes: Int Emotion.JOY -> R.drawable.img_emotion_joy Emotion.SAD -> R.drawable.img_emotion_sadness Emotion.INSIGHT -> R.drawable.img_emotion_insight + Emotion.ETC -> R.drawable.img_emotion_warmth } -val Emotion.graphicResV2: Int +val Emotion.ratioBarColor: Color + get() = when (this) { + Emotion.WARM -> Yellow300 + Emotion.JOY -> Orange300 + Emotion.SAD -> Blue300 + Emotion.INSIGHT -> Violet300 + Emotion.ETC -> Neutral300 + } + +val Emotion.graphicResV2: Int? get() = when (this) { Emotion.WARM -> R.drawable.img_category_warm Emotion.JOY -> R.drawable.img_category_joy Emotion.SAD -> R.drawable.img_category_sad Emotion.INSIGHT -> R.drawable.img_category_insight + Emotion.ETC -> null } val Emotion.descriptionRes: Int @@ -49,4 +69,5 @@ val Emotion.descriptionRes: Int Emotion.JOY -> R.string.emotion_joy_description Emotion.SAD -> R.string.emotion_sad_description Emotion.INSIGHT -> R.string.emotion_insight_description + Emotion.ETC -> R.string.emotion_etc_description } diff --git a/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt index 61997cc91..e3b2588f0 100644 --- a/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt +++ b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt @@ -63,6 +63,28 @@ val Blue700 = Color(0xFF007BFF) val Blue800 = Color(0xFF1269EC) val Blue900 = Color(0xFF1F47CD) +val Orange50 = Color(0xFFFFF1EB) +val Orange100 = Color(0xFFFFD2BE) +val Orange200 = Color(0xFFFFB392) +val Orange300 = Color(0xFFFF9365) +val Orange400 = Color(0xFFEF6D35) +val Orange500 = Color(0xFFCD5622) +val Orange600 = Color(0xFFAB4114) +val Orange700 = Color(0xFF892F08) +val Orange800 = Color(0xFF672001) +val Orange900 = Color(0xFF451500) + +val Violet50 = Color(0xFFF7F0FF) +val Violet100 = Color(0xFFE6CEFF) +val Violet200 = Color(0xFFD4ADFF) +val Violet300 = Color(0xFFC38CFF) +val Violet400 = Color(0xFFB26AFF) +val Violet500 = Color(0xFF9A55E4) +val Violet600 = Color(0xFF7F40C2) +val Violet700 = Color(0xFF652EA0) +val Violet800 = Color(0xFF4C1E7E) +val Violet900 = Color(0xFF36125C) + val Kakao = Color(0xFFFBD300) val Blank = Color(0xFFD6D6D6) val HomeBg = Color(0xFFF0F9E8) @@ -76,6 +98,8 @@ val InsightTextColor = Color(0xFF9A55E4) val InsightBgColor = Color(0xFFF3E8FF) val SadnessTextColor = Color(0xFF2872E9) val SadnessBgColor = Color(0xFFE1ECFF) +val EtcTextColor = Color(0xFF737373) +val EtcBgColor = Color(0xFFF5F5F5) @Immutable data class ReedColorScheme( diff --git a/core/designsystem/src/main/res/values/strings.xml b/core/designsystem/src/main/res/values/strings.xml index 674c8c554..1bc404a78 100644 --- a/core/designsystem/src/main/res/values/strings.xml +++ b/core/designsystem/src/main/res/values/strings.xml @@ -8,4 +8,5 @@ 흥미롭고 유쾌한 순간 눈물이 고인 순간 생각이 깊어지는 순간 + 네 가지 감정으로 표현하기 어려울 때 diff --git a/core/designsystem/stability/designsystem.stability b/core/designsystem/stability/designsystem.stability index 9261a0737..7a2aa49f4 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 @@ -163,18 +163,6 @@ public fun com.ninecraft.booket.core.designsystem.component.checkbox.TickOnlyChe - onCheckedChange: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -public fun com.ninecraft.booket.core.designsystem.component.chip.(): com.ninecraft.booket.core.designsystem.component.chip.ChipSizeStyle - skippable: true - restartable: true - params: - -@Composable -public fun com.ninecraft.booket.core.designsystem.component.chip.(): com.ninecraft.booket.core.designsystem.component.chip.ChipSizeStyle - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.core.designsystem.component.chip.ReedRemovableChip(label: kotlin.String, chipSizeStyle: com.ninecraft.booket.core.designsystem.component.chip.ChipSizeStyle, onRemove: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -196,6 +184,18 @@ public fun com.ninecraft.booket.core.designsystem.component.chip.ReedSelectableC - onClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) +@Composable +public fun com.ninecraft.booket.core.designsystem.component.chip.mediumChipStyle(): com.ninecraft.booket.core.designsystem.component.chip.ChipSizeStyle + skippable: true + restartable: true + params: + +@Composable +public fun com.ninecraft.booket.core.designsystem.component.chip.smallChipStyle(): com.ninecraft.booket.core.designsystem.component.chip.ChipSizeStyle + skippable: true + restartable: true + params: + @Composable public fun com.ninecraft.booket.core.designsystem.component.textfield.ReedRecordTextField(recordState: androidx.compose.foundation.text.input.TextFieldState, recordHintRes: kotlin.Int, modifier: androidx.compose.ui.Modifier, inputTransformation: androidx.compose.foundation.text.input.InputTransformation?, keyboardOptions: androidx.compose.foundation.text.KeyboardOptions, lineLimits: androidx.compose.foundation.text.input.TextFieldLineLimits, isError: kotlin.Boolean, errorMessage: kotlin.String, onClear: kotlin.Function0?, onNext: kotlin.Function0, backgroundColor: androidx.compose.ui.graphics.Color, textColor: androidx.compose.ui.graphics.Color, cornerShape: androidx.compose.foundation.shape.RoundedCornerShape, borderStroke: androidx.compose.foundation.BorderStroke): kotlin.Unit skippable: true @@ -240,31 +240,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/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 1c6356e16..6bf289d17 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,6 +1,6 @@ package com.ninecraft.booket.core.model -import androidx.compose.runtime.Stable +import androidx.compose.runtime.Immutable data class ReadingRecordsModel( val lastPage: Boolean = true, @@ -10,7 +10,7 @@ data class ReadingRecordsModel( val readingRecords: List = emptyList(), ) -@Stable +@Immutable data class ReadingRecordModel( val id: String = "", val userBookId: String = "", diff --git a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/SeedModel.kt b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/SeedModel.kt index 670b050df..24ee2845a 100644 --- a/core/model/src/main/kotlin/com/ninecraft/booket/core/model/SeedModel.kt +++ b/core/model/src/main/kotlin/com/ninecraft/booket/core/model/SeedModel.kt @@ -20,6 +20,7 @@ enum class Emotion( JOY("즐거움"), SAD("슬픔"), INSIGHT("깨달음"), + ETC("기타"), ; companion object { diff --git a/core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/ReedService.kt b/core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/ReedService.kt index f3926e64e..0521ac594 100644 --- a/core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/ReedService.kt +++ b/core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/ReedService.kt @@ -127,7 +127,7 @@ interface ReedService { @Path("userBookId") userBookId: String, ): SeedResponse - @GET("api/v1/reading-records/detail/{readingRecordId}") + @GET("api/v2/reading-records/detail/{readingRecordId}") suspend fun getRecordDetail( @Path("readingRecordId") readingRecordId: String, ): RecordDetailResponse diff --git a/core/ui/stability/ui.stability b/core/ui/stability/ui.stability index 964ce26ce..0305109da 100644 --- a/core/ui/stability/ui.stability +++ b/core/ui/stability/ui.stability @@ -64,12 +64,6 @@ public fun com.ninecraft.booket.core.ui.component.ReedBottomSheet(onDismissReque - sheetState: STABLE (marked @Stable or @Immutable) - content: STABLE (composable function type) -@Composable -private fun com.ninecraft.booket.core.ui.component.ReedBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.core.ui.component.ReedCloseTopAppBar(modifier: androidx.compose.ui.Modifier, isDark: kotlin.Boolean, title: kotlin.String, onClose: kotlin.Function0): kotlin.Unit skippable: true @@ -119,24 +113,6 @@ public fun com.ninecraft.booket.core.ui.component.ReedLoadingIndicator(modifier: - modifier: STABLE (marked @Stable or @Immutable) - delayMillis: STABLE (primitive type) -@Composable -private fun com.ninecraft.booket.core.ui.component.ReedLoadingIndicatorPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.core.ui.component.ReedNetworkErrorUiPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.core.ui.component.ReedServerErrorUiPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.core.ui.component.ReedTopAppBar(modifier: androidx.compose.ui.Modifier, isDark: kotlin.Boolean, title: kotlin.String, startIconRes: kotlin.Int?, startIconDescription: kotlin.String, startIconOnClick: kotlin.Function0, endIconRes: kotlin.Int?, endIconDescription: kotlin.String, endIconOnClick: kotlin.Function0): kotlin.Unit skippable: true diff --git a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt index c49bd0d5e..7d9ca4422 100644 --- a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt +++ b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt @@ -79,6 +79,7 @@ class BookDetailPresenter( var footerState by rememberRetained { mutableStateOf(FooterState.Idle) } var bookDetail by rememberRetained { mutableStateOf(BookDetailModel()) } var seedsStates by rememberRetained { mutableStateOf>(persistentListOf()) } + var isStatsExpanded by rememberRetained { mutableStateOf(false) } var readingRecords by rememberRetained { mutableStateOf(persistentListOf()) } var readingRecordsTotalCount by rememberRetained { mutableIntStateOf(0) } var currentStartIndex by rememberRetained { mutableIntStateOf(START_INDEX) } @@ -398,6 +399,10 @@ class BookDetailPresenter( initialLoad() } } + + is BookDetailUiEvent.OnStatsToggleClick -> { + isStatsExpanded = event.flag + } } } @@ -410,6 +415,7 @@ class BookDetailPresenter( footerState = footerState, bookDetail = bookDetail, seedsStats = seedsStates, + isStatsExpanded = isStatsExpanded, readingRecords = readingRecords, readingRecordsTotalCount = readingRecordsTotalCount, isBookUpdateBottomSheetVisible = isBookUpdateBottomSheetVisible, diff --git a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt index 2c7ce7f64..83c7e25cb 100644 --- a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt +++ b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt @@ -1,6 +1,5 @@ package com.ninecraft.booket.feature.detail.book -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -37,6 +36,9 @@ import com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorSt import com.ninecraft.booket.core.designsystem.component.button.mediumButtonStyle import com.ninecraft.booket.core.designsystem.theme.ReedTheme import com.ninecraft.booket.core.model.BookDetailModel +import com.ninecraft.booket.core.model.Emotion +import com.ninecraft.booket.core.model.EmotionModel +import com.ninecraft.booket.core.model.ReadingRecordModel import com.ninecraft.booket.core.ui.ReedScaffold import com.ninecraft.booket.core.ui.component.InfinityLazyColumn import com.ninecraft.booket.core.ui.component.LoadStateFooter @@ -57,6 +59,7 @@ import com.ninecraft.booket.feature.screens.BookDetailScreen import com.skydoves.compose.stability.runtime.TraceRecomposition import com.slack.circuit.codegen.annotations.CircuitInject import dev.zacsweers.metro.AppScope +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.launch import com.ninecraft.booket.core.designsystem.R as designR @@ -238,7 +241,7 @@ internal fun BookDetailContent( item { Column { BookItem(bookDetail = state.bookDetail) - Spacer(Modifier.height(ReedTheme.spacing.spacing7)) + Spacer(Modifier.height(ReedTheme.spacing.spacing5)) Row( modifier = Modifier .fillMaxWidth() @@ -280,7 +283,13 @@ internal fun BookDetailContent( item { if (state.hasEmotionData()) { - CollectedSeeds(seedsStats = state.seedsStats) + CollectedSeeds( + seedsStats = state.seedsStats, + isStatsExpanded = state.isStatsExpanded, + onToggleClick = { + state.eventSink(BookDetailUiEvent.OnStatsToggleClick(!state.isStatsExpanded)) + }, + ) } else { Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing10)) } @@ -292,7 +301,7 @@ internal fun BookDetailContent( Column( modifier = Modifier.padding(horizontal = ReedTheme.spacing.spacing5), ) { - Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing6)) + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing8)) ReadingRecordsHeader( totalCount = state.readingRecordsTotalCount, currentRecordSort = state.currentRecordSort, @@ -329,6 +338,9 @@ internal fun BookDetailContent( val record = state.readingRecords[index] RecordItem( recordInfo = record, + onRecordClick = { + state.eventSink(BookDetailUiEvent.OnRecordItemClick(record.id)) + }, onRecordMenuClick = { recordInfo -> state.eventSink(BookDetailUiEvent.OnRecordMenuClick(recordInfo)) }, @@ -337,10 +349,7 @@ internal fun BookDetailContent( start = ReedTheme.spacing.spacing5, end = ReedTheme.spacing.spacing5, bottom = ReedTheme.spacing.spacing3, - ) - .clickable { - state.eventSink(BookDetailUiEvent.OnRecordItemClick(record.id)) - }, + ), ) } @@ -365,7 +374,27 @@ internal fun BookDetailContent( @ComponentPreview @Composable -private fun BookDetailPreview() { +private fun BookDetailEmptyPreview() { + ReedTheme { + BookDetailUi( + state = BookDetailUiState( + uiState = UiState.Success, + bookDetail = BookDetailModel( + title = "데미안", + author = "헤르만 헤세", + publisher = "민음사", + pubDate = "2023-01-01", + coverImageUrl = "", + ), + eventSink = {}, + ), + ) + } +} + +@ComponentPreview +@Composable +private fun BookDetailSeedStatsPreview() { ReedTheme { BookDetailUi( state = BookDetailUiState( @@ -377,6 +406,93 @@ private fun BookDetailPreview() { pubDate = "2023-01-01", coverImageUrl = "", ), + seedsStats = persistentListOf( + EmotionModel(name = Emotion.WARM, count = 5), + EmotionModel(name = Emotion.JOY, count = 3), + EmotionModel(name = Emotion.SAD, count = 2), + EmotionModel(name = Emotion.INSIGHT, count = 7), + ), + readingRecords = persistentListOf( + ReadingRecordModel( + id = "1", + pageNumber = 42, + quote = "새는 알에서 나오려고 투쟁한다. 알은 세계이다.", + review = "정말 인상 깊은 구절이었다.", + emotionTags = listOf("깨달음", "따뜻함"), + createdAt = "2024-01-15T10:30:00.000000", + ), + ReadingRecordModel( + id = "2", + pageNumber = 78, + quote = "나는 더 이상 꿈을 꾸지 않으려 했다.", + review = "성장통을 느끼는 부분", + emotionTags = listOf("슬픔"), + createdAt = "2024-01-20T14:20:00.000000", + ), + ReadingRecordModel( + id = "3", + pageNumber = 156, + quote = "운명과 성향은 같은 개념의 두 이름이다.", + review = "내 삶을 돌아보게 되었다.", + emotionTags = listOf("깨달음", "즐거움"), + createdAt = "2024-01-25T09:15:00.000000", + ), + ), + readingRecordsTotalCount = 3, + eventSink = {}, + ), + ) + } +} + +@ComponentPreview +@Composable +private fun BookDetailSeedsStatsExpandedPreview() { + ReedTheme { + BookDetailUi( + state = BookDetailUiState( + uiState = UiState.Success, + bookDetail = BookDetailModel( + title = "데미안", + author = "헤르만 헤세", + publisher = "민음사", + pubDate = "2023-01-01", + coverImageUrl = "", + ), + seedsStats = persistentListOf( + EmotionModel(name = Emotion.WARM, count = 5), + EmotionModel(name = Emotion.JOY, count = 3), + EmotionModel(name = Emotion.SAD, count = 2), + EmotionModel(name = Emotion.INSIGHT, count = 7), + ), + isStatsExpanded = true, + readingRecords = persistentListOf( + ReadingRecordModel( + id = "1", + pageNumber = 42, + quote = "새는 알에서 나오려고 투쟁한다. 알은 세계이다.", + review = "정말 인상 깊은 구절이었다.", + emotionTags = listOf("깨달음", "따뜻함"), + createdAt = "2024-01-15T10:30:00.000000", + ), + ReadingRecordModel( + id = "2", + pageNumber = 78, + quote = "나는 더 이상 꿈을 꾸지 않으려 했다.", + review = "성장통을 느끼는 부분", + emotionTags = listOf("슬픔"), + createdAt = "2024-01-20T14:20:00.000000", + ), + ReadingRecordModel( + id = "3", + pageNumber = 156, + quote = "운명과 성향은 같은 개념의 두 이름이다.", + review = "내 삶을 돌아보게 되었다.", + emotionTags = listOf("깨달음", "즐거움"), + createdAt = "2024-01-25T09:15:00.000000", + ), + ), + readingRecordsTotalCount = 3, eventSink = {}, ), ) diff --git a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUiState.kt b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUiState.kt index 550d0ee10..2d0246ce2 100644 --- a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUiState.kt +++ b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUiState.kt @@ -27,6 +27,7 @@ data class BookDetailUiState( val isLoading: Boolean = false, val bookDetail: BookDetailModel = BookDetailModel(), val seedsStats: ImmutableList = persistentListOf(), + val isStatsExpanded: Boolean = false, val readingRecords: ImmutableList = persistentListOf(), val readingRecordsTotalCount: Int = 0, val currentStartIndex: Int = 1, @@ -84,6 +85,7 @@ sealed interface BookDetailUiEvent : CircuitUiEvent { data class OnRecordItemClick(val recordId: String) : BookDetailUiEvent data object OnLoadMore : BookDetailUiEvent data object OnRetryClick : BookDetailUiEvent + data class OnStatsToggleClick(val flag: Boolean) : BookDetailUiEvent } enum class RecordSort(val value: String) { diff --git a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/CollectedSeeds.kt b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/CollectedSeeds.kt index db940fd56..67e6ac947 100644 --- a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/CollectedSeeds.kt +++ b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/CollectedSeeds.kt @@ -1,7 +1,11 @@ package com.ninecraft.booket.feature.detail.book.component +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -10,27 +14,43 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp +import com.ninecraft.booket.core.common.utils.analyzeEmotions import com.ninecraft.booket.core.designsystem.ComponentPreview +import com.ninecraft.booket.core.designsystem.ratioBarColor import com.ninecraft.booket.core.designsystem.theme.ReedTheme +import com.ninecraft.booket.core.designsystem.theme.Yellow700 import com.ninecraft.booket.core.model.Emotion import com.ninecraft.booket.core.model.EmotionModel -import com.ninecraft.booket.feature.detail.R import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf +import com.ninecraft.booket.core.designsystem.R as designR @Composable internal fun CollectedSeeds( seedsStats: ImmutableList, + isStatsExpanded: Boolean, + onToggleClick: () -> Unit, modifier: Modifier = Modifier, ) { + val analysisResult = remember(seedsStats) { analyzeEmotions(seedsStats) } + val topEmotion = analysisResult.topEmotions.firstOrNull() + Column( modifier = modifier .fillMaxWidth() @@ -41,67 +61,222 @@ internal fun CollectedSeeds( bottom = ReedTheme.spacing.spacing6, ) .clip(RoundedCornerShape(ReedTheme.radius.md)) - .background(ReedTheme.colors.baseSecondary), + .background(ReedTheme.colors.baseSecondary) + .padding(ReedTheme.spacing.spacing4), ) { - Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4)) - Text( - text = stringResource(R.string.collected_seed_title), - modifier = Modifier.padding(horizontal = ReedTheme.spacing.spacing4), - color = ReedTheme.colors.contentSecondary, - style = ReedTheme.typography.body2Medium, + CollectedSeedsHeader( + topEmotion = topEmotion, + isStatsExpanded = isStatsExpanded, + onToggleClick = onToggleClick, ) - Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing5)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly, + + AnimatedVisibility( + visible = isStatsExpanded, + enter = expandVertically(), + exit = shrinkVertically(), ) { - seedsStats.forEach { emotion -> - SeedItem(emotion = emotion) + Column { + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4)) + HorizontalDivider( + color = ReedTheme.colors.dividerSm, + thickness = 1.dp, + ) + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing5)) + + EmotionRatioBar(seedsStats = seedsStats) + + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(ReedTheme.spacing.spacing1), + ) { + Emotion.entries.forEach { emotion -> + val emotionModel = seedsStats.find { it.name == emotion } + ?: EmotionModel(emotion, 0) + EmotionStatCard( + emotion = emotionModel, + modifier = Modifier.weight(1f), + ) + } + } } } - Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing5)) - Box( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = ReedTheme.spacing.spacing4) - .clip(RoundedCornerShape(ReedTheme.radius.sm)) - .background(ReedTheme.colors.basePrimary) - .border( - width = 1.dp, - color = ReedTheme.colors.borderPrimary, - shape = RoundedCornerShape(ReedTheme.radius.sm), - ) - .padding(ReedTheme.spacing.spacing3), + } +} + +@Composable +private fun CollectedSeedsHeader( + topEmotion: EmotionModel?, + isStatsExpanded: Boolean, + onToggleClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier + .fillMaxWidth() + .clickable { onToggleClick() }, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, ) { - EmotionAnalysisResultText( - emotions = seedsStats, - brandColor = ReedTheme.colors.contentBrand, - secondaryColor = ReedTheme.colors.contentSecondary, - emotionTextStyle = ReedTheme.typography.label2SemiBold, - regularTextStyle = ReedTheme.typography.label2Regular, - )?.let { annotatedString -> + topEmotion?.let { emotion -> + Image( + painter = painterResource(id = getEmotionImageResourceByDisplayName(emotion.name.displayName)), + contentDescription = "Seed Image", + modifier = Modifier + .size(36.dp) + .clip(CircleShape) + .background(ReedTheme.colors.basePrimary), + ) + Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing2)) + } + + Row { Text( - text = annotatedString, - modifier = Modifier.fillMaxWidth(), - textAlign = TextAlign.Center, + text = "'${topEmotion?.name?.displayName ?: ""}'", + color = Yellow700, + style = ReedTheme.typography.label1SemiBold, + ) + Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing1)) + Text( + text = "감정을 많이 느꼈어요", + color = ReedTheme.colors.contentSecondary, + style = ReedTheme.typography.label1Medium, + ) + } + } + + Icon( + imageVector = ImageVector.vectorResource( + if (isStatsExpanded) designR.drawable.ic_chevron_up else designR.drawable.ic_chevron_down, + ), + contentDescription = if (isStatsExpanded) "Collapse" else "Expand", + modifier = Modifier.size(24.dp), + tint = ReedTheme.colors.contentTertiary, + ) + } +} + +@Composable +private fun EmotionRatioBar( + seedsStats: ImmutableList, + modifier: Modifier = Modifier, +) { + val totalCount = seedsStats.sumOf { it.count }.coerceAtLeast(1) + + Row( + modifier = modifier + .fillMaxWidth() + .height(12.dp) + .clip(RoundedCornerShape(ReedTheme.radius.full)), + ) { + Emotion.entries.forEach { emotion -> + val emotionModel = seedsStats.find { it.name == emotion } + val count = emotionModel?.count ?: 0 + if (count > 0) { + val weight = count.toFloat() / totalCount + Box( + modifier = Modifier + .weight(weight) + .height(12.dp) + .background(emotion.ratioBarColor), ) } } - Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4)) + } +} + +@Composable +private fun EmotionStatCard( + emotion: EmotionModel, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .clip(RoundedCornerShape(ReedTheme.radius.md)) + .background(ReedTheme.colors.basePrimary) + .padding( + top = ReedTheme.spacing.spacing3, + bottom = ReedTheme.spacing.spacing2, + ), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Box( + modifier = Modifier + .size(10.dp) + .clip(RoundedCornerShape(ReedTheme.radius.xs)) + .background(emotion.name.ratioBarColor), + ) + + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing2)) + + Text( + text = emotion.name.displayName, + color = ReedTheme.colors.contentSecondary, + style = ReedTheme.typography.label2Regular, + ) + + Text( + text = "${emotion.count}개", + color = ReedTheme.colors.contentTertiary, + style = ReedTheme.typography.caption1Regular, + ) + } +} + +@ComponentPreview +@Composable +private fun CollectedSeedsCollapsedPreview() { + ReedTheme { + CollectedSeeds( + seedsStats = persistentListOf( + EmotionModel(Emotion.WARM, 4), + EmotionModel(Emotion.JOY, 2), + EmotionModel(Emotion.SAD, 2), + EmotionModel(Emotion.INSIGHT, 2), + EmotionModel(Emotion.ETC, 2), + ), + isStatsExpanded = false, + onToggleClick = {}, + ) } } @ComponentPreview @Composable -private fun CollectedSeedPreview() { +private fun CollectedSeedsExpandedPreview() { ReedTheme { CollectedSeeds( seedsStats = persistentListOf( - EmotionModel(Emotion.WARM, 3), + EmotionModel(Emotion.WARM, 4), EmotionModel(Emotion.JOY, 2), - EmotionModel(Emotion.SAD, 1), - EmotionModel(Emotion.INSIGHT, 3), + EmotionModel(Emotion.SAD, 2), + EmotionModel(Emotion.INSIGHT, 2), + EmotionModel(Emotion.ETC, 2), + ), + isStatsExpanded = true, + onToggleClick = {}, + ) + } +} + +@ComponentPreview +@Composable +private fun CollectedSeedsExpandedDuplicatedPreview() { + ReedTheme { + CollectedSeeds( + seedsStats = persistentListOf( + EmotionModel(Emotion.WARM, 4), + EmotionModel(Emotion.JOY, 4), + EmotionModel(Emotion.SAD, 2), + EmotionModel(Emotion.INSIGHT, 2), + EmotionModel(Emotion.ETC, 2), ), + isStatsExpanded = true, + onToggleClick = {}, ) } } diff --git a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/ReadingRecordsHeader.kt b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/ReadingRecordsHeader.kt index 7dfdefb26..d0cf80d0e 100644 --- a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/ReadingRecordsHeader.kt +++ b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/ReadingRecordsHeader.kt @@ -43,7 +43,7 @@ internal fun ReadingRecordsHeader( Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing1)) Text( text = "$totalCount", - color = ReedTheme.colors.contentBrand, + color = ReedTheme.colors.contentTertiary, style = ReedTheme.typography.headline2SemiBold, ) } diff --git a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordItem.kt b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordItem.kt index 4b0b8d3b7..a5f8f05eb 100644 --- a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordItem.kt +++ b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordItem.kt @@ -1,6 +1,5 @@ package com.ninecraft.booket.feature.detail.book.component -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -11,8 +10,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.material3.Text @@ -21,7 +18,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.style.TextOverflow @@ -36,6 +32,7 @@ import com.ninecraft.booket.core.designsystem.R as designR @Composable internal fun RecordItem( recordInfo: ReadingRecordModel, + onRecordClick: () -> Unit, onRecordMenuClick: (ReadingRecordModel) -> Unit, modifier: Modifier = Modifier, ) { @@ -43,6 +40,7 @@ internal fun RecordItem( modifier = modifier .fillMaxSize() .clip(RoundedCornerShape(ReedTheme.radius.md)) + .clickable { onRecordClick() } .background(ReedTheme.colors.baseSecondary) .padding( start = ReedTheme.spacing.spacing5, @@ -55,19 +53,12 @@ internal fun RecordItem( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, ) { - Image( - painter = painterResource(getEmotionImageResourceByDisplayName(recordInfo.emotionTags[0])), - contentDescription = "Emotion Graphic", - modifier = Modifier - .size(ReedTheme.spacing.spacing8) - .clip(CircleShape) - .background(ReedTheme.colors.basePrimary), - ) - Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing2)) Text( - text = "#${recordInfo.emotionTags[0]}", + text = if (recordInfo.pageNumber != 0) "${recordInfo.pageNumber}p" + else "-p", color = ReedTheme.colors.contentBrand, - style = ReedTheme.typography.body1SemiBold, + style = ReedTheme.typography.label1Medium, + fontStyle = FontStyle.Italic, ) Spacer(modifier = Modifier.weight(1f)) Icon( @@ -81,7 +72,7 @@ internal fun RecordItem( tint = ReedTheme.colors.contentTertiary, ) } - Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing3)) + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4)) Text( text = "\"${recordInfo.quote}\"", color = ReedTheme.colors.contentSecondary, @@ -89,22 +80,21 @@ internal fun RecordItem( maxLines = 4, style = ReedTheme.typography.body2Medium, ) - Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4)) + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing3)) Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, ) { Text( - text = recordInfo.createdAt.toFormattedDate(), + text = "#${recordInfo.emotionTags[0]}", color = ReedTheme.colors.contentTertiary, style = ReedTheme.typography.label1Medium, ) Spacer(modifier = Modifier.weight(1f)) Text( - text = "${recordInfo.pageNumber}p", + text = recordInfo.createdAt.toFormattedDate(), color = ReedTheme.colors.contentTertiary, - style = ReedTheme.typography.body2Medium, - fontStyle = FontStyle.Italic, + style = ReedTheme.typography.label1Medium, ) } } @@ -116,6 +106,7 @@ fun getEmotionImageResourceByDisplayName(displayName: String): Int { "즐거움" -> R.drawable.img_joy "슬픔" -> R.drawable.img_sad "깨달음" -> R.drawable.img_insight + "기타" -> R.drawable.img_etc else -> R.drawable.img_warm } } @@ -129,8 +120,9 @@ private fun RecordItemPreview() { quote = "소설가들은 늘 소재를 찾아 떠도는 존재 같지만, 실은 그 반대인 경우가 더 잦다.", emotionTags = persistentListOf("따뜻함"), pageNumber = 12, - createdAt = "2025.06.25", + createdAt = "2025-06-25T10:30:00.000000", ), + onRecordClick = {}, onRecordMenuClick = {}, ) } diff --git a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/SeedItem.kt b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/SeedItem.kt index ebeaf2a46..b35e49652 100644 --- a/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/SeedItem.kt +++ b/feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/SeedItem.kt @@ -70,6 +70,7 @@ private fun getEmotionImageResource(emotion: Emotion): Int { Emotion.JOY -> R.drawable.img_joy Emotion.SAD -> R.drawable.img_sad Emotion.INSIGHT -> R.drawable.img_insight + Emotion.ETC -> R.drawable.img_etc } } diff --git a/feature/detail/src/main/res/drawable/img_etc.webp b/feature/detail/src/main/res/drawable/img_etc.webp new file mode 100644 index 000000000..0672c2431 Binary files /dev/null and b/feature/detail/src/main/res/drawable/img_etc.webp differ diff --git a/feature/detail/src/main/res/drawable/img_insight.webp b/feature/detail/src/main/res/drawable/img_insight.webp index 77d816fdb..b86a84417 100644 Binary files a/feature/detail/src/main/res/drawable/img_insight.webp and b/feature/detail/src/main/res/drawable/img_insight.webp differ diff --git a/feature/detail/src/main/res/drawable/img_joy.webp b/feature/detail/src/main/res/drawable/img_joy.webp index 00414f16c..ab3c16844 100644 Binary files a/feature/detail/src/main/res/drawable/img_joy.webp and b/feature/detail/src/main/res/drawable/img_joy.webp differ diff --git a/feature/detail/src/main/res/drawable/img_sad.webp b/feature/detail/src/main/res/drawable/img_sad.webp index 439e3224e..72e11cf4f 100644 Binary files a/feature/detail/src/main/res/drawable/img_sad.webp and b/feature/detail/src/main/res/drawable/img_sad.webp differ diff --git a/feature/detail/src/main/res/drawable/img_warm.webp b/feature/detail/src/main/res/drawable/img_warm.webp index a432f9e6f..636b5a412 100644 Binary files a/feature/detail/src/main/res/drawable/img_warm.webp and b/feature/detail/src/main/res/drawable/img_warm.webp differ diff --git a/feature/detail/stability/detail.stability b/feature/detail/stability/detail.stability index 4866c0780..b7345b547 100644 --- a/feature/detail/stability/detail.stability +++ b/feature/detail/stability/detail.stability @@ -20,12 +20,6 @@ public fun com.ninecraft.booket.feature.detail.book.BookDetailPresenter.present( restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.detail.book.BookDetailPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.detail.book.BookDetailUi(state: com.ninecraft.booket.feature.detail.book.BookDetailUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -50,12 +44,6 @@ internal fun com.ninecraft.booket.feature.detail.book.component.BookItem(bookDet - bookDetail: STABLE (marked @Stable or @Immutable) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.book.component.BookItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.detail.book.component.BookStatusItem(item: com.ninecraft.booket.core.common.constants.BookStatus, selected: kotlin.Boolean, onClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -82,29 +70,23 @@ internal fun com.ninecraft.booket.feature.detail.book.component.BookUpdateBottom - modifier: STABLE (marked @Stable or @Immutable) @Composable -private fun com.ninecraft.booket.feature.detail.book.component.BookUpdateBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.detail.book.component.ChoiceBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.detail.book.component.CollectedSeedPreview(): kotlin.Unit +internal fun com.ninecraft.booket.feature.detail.book.component.CollectedSeeds(seedsStats: kotlinx.collections.immutable.ImmutableList, isStatsExpanded: kotlin.Boolean, onToggleClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true restartable: true params: + - seedsStats: STABLE (known stable type) + - isStatsExpanded: STABLE (primitive type) + - onToggleClick: STABLE (function type) + - modifier: STABLE (marked @Stable or @Immutable) @Composable -internal fun com.ninecraft.booket.feature.detail.book.component.CollectedSeeds(seedsStats: kotlinx.collections.immutable.ImmutableList, modifier: androidx.compose.ui.Modifier): kotlin.Unit +private fun com.ninecraft.booket.feature.detail.book.component.CollectedSeedsHeader(topEmotion: com.ninecraft.booket.core.model.EmotionModel?, isStatsExpanded: kotlin.Boolean, onToggleClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true restartable: true params: - - seedsStats: STABLE (known stable type) + - topEmotion: STABLE (marked @Stable or @Immutable) + - isStatsExpanded: STABLE (primitive type) + - onToggleClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) @Composable @@ -141,42 +123,41 @@ internal fun com.ninecraft.booket.feature.detail.book.component.EmotionAnalysisR - regularTextStyle: STABLE (marked @Stable or @Immutable) @Composable -private fun com.ninecraft.booket.feature.detail.book.component.EmotionTextAllCasesPreview(): kotlin.Unit +private fun com.ninecraft.booket.feature.detail.book.component.EmotionRatioBar(seedsStats: kotlinx.collections.immutable.ImmutableList, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true restartable: true params: + - seedsStats: STABLE (known stable type) + - modifier: STABLE (marked @Stable or @Immutable) @Composable -internal fun com.ninecraft.booket.feature.detail.book.component.ReadingRecordsHeader(totalCount: kotlin.Int, currentRecordSort: com.ninecraft.booket.feature.detail.book.RecordSort, onReadingRecordClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit +private fun com.ninecraft.booket.feature.detail.book.component.EmotionStatCard(emotion: com.ninecraft.booket.core.model.EmotionModel, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true restartable: true params: - - totalCount: STABLE (primitive type) - - currentRecordSort: STABLE (class with no mutable properties) - - onReadingRecordClick: STABLE (function type) + - emotion: STABLE (marked @Stable or @Immutable) - modifier: STABLE (marked @Stable or @Immutable) @Composable -private fun com.ninecraft.booket.feature.detail.book.component.ReadingRecordsHeaderPreview(): kotlin.Unit +internal fun com.ninecraft.booket.feature.detail.book.component.ReadingRecordsHeader(totalCount: kotlin.Int, currentRecordSort: com.ninecraft.booket.feature.detail.book.RecordSort, onReadingRecordClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true restartable: true params: + - totalCount: STABLE (primitive type) + - currentRecordSort: STABLE (class with no mutable properties) + - onReadingRecordClick: STABLE (function type) + - modifier: STABLE (marked @Stable or @Immutable) @Composable -internal fun com.ninecraft.booket.feature.detail.book.component.RecordItem(recordInfo: com.ninecraft.booket.core.model.ReadingRecordModel, onRecordMenuClick: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit +internal fun com.ninecraft.booket.feature.detail.book.component.RecordItem(recordInfo: com.ninecraft.booket.core.model.ReadingRecordModel, onRecordClick: kotlin.Function0, onRecordMenuClick: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true restartable: true params: - recordInfo: STABLE (marked @Stable or @Immutable) + - onRecordClick: STABLE (function type) - onRecordMenuClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.book.component.RecordItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.detail.book.component.RecordSortBottomSheet(onDismissRequest: kotlin.Function0, sheetState: androidx.compose.material3.SheetState, onCloseButtonClick: kotlin.Function0, recordSortItems: kotlinx.collections.immutable.ImmutableList, currentRecordSort: com.ninecraft.booket.feature.detail.book.RecordSort, onItemSelected: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -190,12 +171,6 @@ internal fun com.ninecraft.booket.feature.detail.book.component.RecordSortBottom - onItemSelected: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.book.component.RecordSortBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.detail.book.component.RecordSortItem(item: com.ninecraft.booket.feature.detail.book.RecordSort, selected: kotlin.Boolean, onClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -214,12 +189,6 @@ internal fun com.ninecraft.booket.feature.detail.book.component.SeedItem(emotion - emotion: STABLE (marked @Stable or @Immutable) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.book.component.SeedItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.detail.card.HandleRecordCardSideEffects(state: com.ninecraft.booket.feature.detail.card.RecordCardUiState, recordCardGraphicsLayer: androidx.compose.ui.graphics.layer.GraphicsLayer, eventSink: kotlin.Function1): kotlin.Unit skippable: false @@ -243,12 +212,6 @@ internal fun com.ninecraft.booket.feature.detail.card.RecordCardUi(state: com.ni - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.card.RecordCardUiPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.detail.card.component.RecordCard(quote: kotlin.String, bookTitle: kotlin.String, emotion: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -259,12 +222,6 @@ internal fun com.ninecraft.booket.feature.detail.card.component.RecordCard(quote - emotion: STABLE (String is immutable) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.card.component.RecordCardPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.detail.record.HandleRecordDetailSideEffects(state: com.ninecraft.booket.feature.detail.record.RecordDetailUiState): kotlin.Unit skippable: true @@ -294,18 +251,6 @@ internal fun com.ninecraft.booket.feature.detail.record.RecordDetailUi(state: co - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.record.ReviewDetailEmptyPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.detail.record.ReviewDetailPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.detail.record.component.BookItem(imageUrl: kotlin.String, bookTitle: kotlin.String, author: kotlin.String, publisher: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -317,24 +262,6 @@ internal fun com.ninecraft.booket.feature.detail.record.component.BookItem(image - publisher: STABLE (String is immutable) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.record.component.BookItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.detail.record.component.ChoiceBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.detail.record.component.QuoteBoxPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.detail.record.component.QuoteItem(quote: kotlin.String, page: kotlin.Int, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -368,18 +295,6 @@ private fun com.ninecraft.booket.feature.detail.record.component.RecordMenuItem( - onClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.detail.record.component.ReviewBoxEmptyPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.detail.record.component.ReviewBoxPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.detail.record.component.ReviewItem(emotion: kotlin.String, createdAt: kotlin.String, review: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true diff --git a/feature/edit/stability/edit.stability b/feature/edit/stability/edit.stability index b44dddd06..5543c7f9e 100644 --- a/feature/edit/stability/edit.stability +++ b/feature/edit/stability/edit.stability @@ -26,12 +26,6 @@ internal fun com.ninecraft.booket.feature.edit.emotion.EmotionEditUi(state: com. - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.edit.emotion.EmotionEditUiPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable private fun com.ninecraft.booket.feature.edit.emotion.EmotionItem(emotion: com.ninecraft.booket.core.model.Emotion, onClick: kotlin.Function0, isSelected: kotlin.Boolean, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -70,12 +64,6 @@ internal fun com.ninecraft.booket.feature.edit.record.RecordEditUi(state: com.ni - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.edit.record.RecordEditUiPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.edit.record.component.BookItem(imageUrl: kotlin.String, bookTitle: kotlin.String, author: kotlin.String, publisher: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -87,9 +75,3 @@ internal fun com.ninecraft.booket.feature.edit.record.component.BookItem(imageUr - publisher: STABLE (String is immutable) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.edit.record.component.BookItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - diff --git a/feature/home/stability/home.stability b/feature/home/stability/home.stability index d30e4f8bb..7c83f45e2 100644 --- a/feature/home/stability/home.stability +++ b/feature/home/stability/home.stability @@ -25,12 +25,6 @@ public fun com.ninecraft.booket.feature.home.HomePresenter.present(): com.ninecr restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.home.HomePreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.home.HomeUi(state: com.ninecraft.booket.feature.home.HomeUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -49,12 +43,6 @@ public fun com.ninecraft.booket.feature.home.component.BookCard(recentBookInfo: - onRecordButtonClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.home.component.BookCardPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.home.component.EmptyBookCard(onBookRegisterClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -63,12 +51,6 @@ public fun com.ninecraft.booket.feature.home.component.EmptyBookCard(onBookRegis - onBookRegisterClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.home.component.EmptyBookCardPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.home.component.HomeBanner(onBookRegisterClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -77,12 +59,6 @@ public fun com.ninecraft.booket.feature.home.component.HomeBanner(onBookRegister - onBookRegisterClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.home.component.HomeBannerPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.home.component.HomeHeader(onSettingsClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -91,9 +67,3 @@ public fun com.ninecraft.booket.feature.home.component.HomeHeader(onSettingsClic - onSettingsClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.home.component.HomeHeaderPreview(): kotlin.Unit - skippable: true - restartable: true - params: - diff --git a/feature/library/stability/library.stability b/feature/library/stability/library.stability index 73e108888..1138df11d 100644 --- a/feature/library/stability/library.stability +++ b/feature/library/stability/library.stability @@ -32,12 +32,6 @@ public fun com.ninecraft.booket.feature.library.LibraryPresenter.present(): com. restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.library.LibraryPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.library.LibraryUi(state: com.ninecraft.booket.feature.library.LibraryUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -46,12 +40,6 @@ internal fun com.ninecraft.booket.feature.library.LibraryUi(state: com.ninecraft - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.library.component.ChipPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.library.component.FilterChip(option: com.ninecraft.booket.feature.library.LibraryFilterOption, count: kotlin.Int, isSelected: kotlin.Boolean, onChipClick: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -73,12 +61,6 @@ public fun com.ninecraft.booket.feature.library.component.FilterChipGroup(filter - onChipClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.library.component.FilterChipGroupPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.library.component.LibraryBookItem(book: com.ninecraft.booket.core.model.LibraryBookSummaryModel, onBookClick: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -88,12 +70,6 @@ public fun com.ninecraft.booket.feature.library.component.LibraryBookItem(book: - onBookClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.library.component.LibraryBookItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.library.component.LibraryHeader(onSearchClick: kotlin.Function0, onSettingClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -103,9 +79,3 @@ public fun com.ninecraft.booket.feature.library.component.LibraryHeader(onSearch - onSettingClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.library.component.LibraryHeaderPreview(): kotlin.Unit - skippable: true - restartable: true - params: - diff --git a/feature/login/stability/login.stability b/feature/login/stability/login.stability index 43c486b5c..005d619f2 100644 --- a/feature/login/stability/login.stability +++ b/feature/login/stability/login.stability @@ -18,12 +18,6 @@ public fun com.ninecraft.booket.feature.login.LoginPresenter.present(): com.nine restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.login.LoginPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.login.LoginUi(state: com.ninecraft.booket.feature.login.LoginUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -45,12 +39,6 @@ public fun com.ninecraft.booket.feature.termsagreement.TermsAgreementPresenter.p restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.termsagreement.TermsAgreementPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.termsagreement.TermsAgreementUi(state: com.ninecraft.booket.feature.termsagreement.TermsAgreementUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -71,9 +59,3 @@ internal fun com.ninecraft.booket.feature.termsagreement.component.TermItem(titl - hasDetailAction: STABLE (primitive type) - onDetailClick: STABLE (function type) -@Composable -private fun com.ninecraft.booket.feature.termsagreement.component.TermItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - diff --git a/feature/onboarding/stability/onboarding.stability b/feature/onboarding/stability/onboarding.stability index 74d90270d..cf927d4cb 100644 --- a/feature/onboarding/stability/onboarding.stability +++ b/feature/onboarding/stability/onboarding.stability @@ -10,12 +10,6 @@ public fun com.ninecraft.booket.feature.onboarding.OnboardingPresenter.present() restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.onboarding.OnboardingScreenPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.onboarding.OnboardingUi(state: com.ninecraft.booket.feature.onboarding.OnboardingUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -35,12 +29,6 @@ internal fun com.ninecraft.booket.feature.onboarding.component.OnboardingPage(im - descriptionRes: STABLE (primitive type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.onboarding.component.OnboardingPagePreview(): kotlin.Unit - skippable: true - 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 @@ -50,9 +38,3 @@ internal fun com.ninecraft.booket.feature.onboarding.component.PagerIndicator(pa - 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/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt index 8a01ac5ce..2f9e225d5 100644 --- a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt +++ b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt @@ -32,6 +32,7 @@ import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedInject import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.PersistentMap import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toPersistentList @@ -96,9 +97,9 @@ class RecordRegisterPresenter( val emotions by rememberRetained { mutableStateOf(Emotion.entries.toPersistentList()) } var emotionDetails by rememberRetained { mutableStateOf(persistentListOf()) } var selectedEmotion by rememberRetained { mutableStateOf(null) } - var selectedEmotionDetails by rememberRetained { mutableStateOf>>(emptyMap()) } + var selectedEmotionDetails by rememberRetained { mutableStateOf>>(persistentMapOf()) } var committedEmotion by rememberRetained { mutableStateOf(null) } - var committedEmotionDetails by rememberRetained { mutableStateOf>>(emptyMap()) } + var committedEmotionDetails by rememberRetained { mutableStateOf>>(persistentMapOf()) } var isEmotionDetailBottomSheetVisible by rememberRetained { mutableStateOf(false) } var savedRecordId by rememberRetained { mutableStateOf("") } var isExitDialogVisible by rememberRetained { mutableStateOf(false) } @@ -243,7 +244,7 @@ class RecordRegisterPresenter( currentDetails + event.detail } - selectedEmotionDetails = selectedEmotionDetails + (emotionKey to updatedDetails.toPersistentList()) + selectedEmotionDetails = selectedEmotionDetails.put(emotionKey, updatedDetails.toPersistentList()) } is RecordRegisterUiEvent.OnEmotionDetailRemoved -> { @@ -251,8 +252,8 @@ class RecordRegisterPresenter( val currentDetails = committedEmotionDetails[selectedEmotion].orEmpty() val updatedDetails = currentDetails - event.detail - committedEmotionDetails = committedEmotionDetails + (emotionKey to updatedDetails.toPersistentList()) - selectedEmotionDetails = selectedEmotionDetails + (emotionKey to updatedDetails.toPersistentList()) + committedEmotionDetails = committedEmotionDetails.put(emotionKey, updatedDetails.toPersistentList()) + selectedEmotionDetails = selectedEmotionDetails.put(emotionKey, updatedDetails.toPersistentList()) } is RecordRegisterUiEvent.OnEmotionDetailSkipped -> { @@ -268,8 +269,8 @@ class RecordRegisterPresenter( val details = selectedEmotionDetails[emotionKey] ?: persistentListOf() committedEmotion = emotionKey - committedEmotionDetails = mapOf(emotionKey to details) - selectedEmotionDetails = mapOf(emotionKey to details) + committedEmotionDetails = persistentMapOf(emotionKey to details) + selectedEmotionDetails = persistentMapOf(emotionKey to details) isEmotionDetailBottomSheetVisible = false } diff --git a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUiState.kt b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUiState.kt index 2aed1fe4e..8989a371f 100644 --- a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUiState.kt +++ b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUiState.kt @@ -7,7 +7,9 @@ import com.ninecraft.booket.core.model.Emotion import com.slack.circuit.runtime.CircuitUiEvent import com.slack.circuit.runtime.CircuitUiState import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.PersistentMap import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentMapOf import java.util.UUID data class RecordRegisterUiState( @@ -20,9 +22,9 @@ data class RecordRegisterUiState( val emotions: ImmutableList = persistentListOf(), val emotionDetails: ImmutableList = persistentListOf(), val selectedEmotion: Emotion? = null, - val selectedEmotionDetails: Map> = emptyMap(), + val selectedEmotionDetails: PersistentMap> = persistentMapOf(), val committedEmotion: Emotion? = null, - val committedEmotionDetails: Map> = emptyMap(), + val committedEmotionDetails: PersistentMap> = persistentMapOf(), val isEmotionDetailBottomSheetVisible: Boolean = false, val impressionState: TextFieldState = TextFieldState(), val impressionGuideList: ImmutableList = persistentListOf(), diff --git a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step_v2/EmotionItem.kt b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step_v2/EmotionItem.kt index 8311cbd67..022e66ead 100644 --- a/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step_v2/EmotionItem.kt +++ b/feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step_v2/EmotionItem.kt @@ -73,13 +73,15 @@ internal fun EmotionItem( ), ) { Row(verticalAlignment = Alignment.CenterVertically) { - Image( - painter = painterResource(emotion.graphicResV2), - contentDescription = "Emotion Image", - modifier = Modifier - .size(60.dp) - .clip(CircleShape), - ) + if (emotion.graphicResV2 != null) { + Image( + painter = painterResource(emotion.graphicResV2!!), + contentDescription = "Emotion Image", + modifier = Modifier + .size(60.dp) + .clip(CircleShape), + ) + } Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing4)) Column { Text( diff --git a/feature/record/stability/record.stability b/feature/record/stability/record.stability index ca90752cb..f0302675e 100644 --- a/feature/record/stability/record.stability +++ b/feature/record/stability/record.stability @@ -11,12 +11,6 @@ internal fun com.ninecraft.booket.feature.record.component.CustomTooltipBox(mess 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 @@ -32,12 +26,6 @@ public fun com.ninecraft.booket.feature.record.component.ImpressionGuideBottomSh - onCloseButtonClick: STABLE (function type) - onSelectionConfirmButtonClick: STABLE (function type) -@Composable -private fun com.ninecraft.booket.feature.record.component.ImpressionGuideBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.record.component.ImpressionGuideBox(onClick: kotlin.Function0, impressionText: kotlin.String, modifier: androidx.compose.ui.Modifier, isSelected: kotlin.Boolean): kotlin.Unit skippable: true @@ -48,12 +36,6 @@ public fun com.ninecraft.booket.feature.record.component.ImpressionGuideBox(onCl - modifier: STABLE (marked @Stable or @Immutable) - isSelected: STABLE (primitive type) -@Composable -private fun com.ninecraft.booket.feature.record.component.ImpressionGuideBoxPreview(): 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 @@ -62,12 +44,6 @@ private fun com.ninecraft.booket.feature.record.ocr.CameraPreview(state: com.nin - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.record.ocr.CameraPreviewPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.record.ocr.HandleOcrSideEffects(state: com.ninecraft.booket.feature.record.ocr.OcrUiState): kotlin.Unit skippable: true @@ -89,12 +65,6 @@ internal fun com.ninecraft.booket.feature.record.ocr.OcrUi(state: com.ninecraft. - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.record.ocr.TextRecognitionResultPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable private fun com.ninecraft.booket.feature.record.ocr.TextScanResult(state: com.ninecraft.booket.feature.record.ocr.OcrUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -110,12 +80,6 @@ public fun com.ninecraft.booket.feature.record.ocr.component.CameraFrame(modifie params: - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.record.ocr.component.CameraFramePreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.record.ocr.component.SentenceBox(onClick: kotlin.Function0, sentence: kotlin.String, modifier: androidx.compose.ui.Modifier, isSelected: kotlin.Boolean): kotlin.Unit skippable: true @@ -126,37 +90,25 @@ public fun com.ninecraft.booket.feature.record.ocr.component.SentenceBox(onClick - modifier: STABLE (marked @Stable or @Immutable) - isSelected: STABLE (primitive type) -@Composable -private fun com.ninecraft.booket.feature.record.ocr.component.SentenceBoxPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.record.register.HandleRecordRegisterSideEffects(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState): kotlin.Unit - skippable: false - restartable: true - params: - - state: RUNTIME (requires runtime check) - -@Composable -public fun com.ninecraft.booket.feature.record.register.RecordRegisterPresenter.present(): com.ninecraft.booket.feature.record.register.RecordRegisterUiState skippable: true restartable: true params: + - state: STABLE (class with no mutable properties) @Composable -private fun com.ninecraft.booket.feature.record.register.RecordRegisterPreview(): kotlin.Unit +public fun com.ninecraft.booket.feature.record.register.RecordRegisterPresenter.present(): com.ninecraft.booket.feature.record.register.RecordRegisterUiState skippable: true restartable: true params: @Composable internal fun com.ninecraft.booket.feature.record.register.RecordRegisterUi(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: false + skippable: true restartable: true params: - - state: RUNTIME (requires runtime check) + - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) @Composable @@ -171,45 +123,27 @@ private fun com.ninecraft.booket.feature.record.step.EmotionItem(emotion: com.ni @Composable public fun com.ninecraft.booket.feature.record.step.EmotionStep(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: false + skippable: true restartable: true params: - - state: RUNTIME (requires runtime check) + - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) @Composable public fun com.ninecraft.booket.feature.record.step.ImpressionStep(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: false - restartable: true - params: - - state: RUNTIME (requires runtime check) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.ninecraft.booket.feature.record.step.ImpressionStepPreview(): kotlin.Unit skippable: true restartable: true params: - -@Composable -internal fun com.ninecraft.booket.feature.record.step.QuoteStep(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: false - restartable: true - params: - - state: RUNTIME (requires runtime check) + - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) @Composable -private fun com.ninecraft.booket.feature.record.step.QuoteStepPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.record.step.RecordRegisterPreview(): kotlin.Unit +internal fun com.ninecraft.booket.feature.record.step.QuoteStep(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true restartable: true params: + - state: STABLE (class with no mutable properties) + - modifier: STABLE (marked @Stable or @Immutable) @Composable internal fun com.ninecraft.booket.feature.record.step_v2.EmotionDetailBottomSheet(emotion: com.ninecraft.booket.core.model.Emotion, emotionDetails: kotlinx.collections.immutable.ImmutableList, selectedEmotionDetail: kotlinx.collections.immutable.ImmutableList, onDismissRequest: kotlin.Function0, sheetState: androidx.compose.material3.SheetState, onCloseButtonClick: kotlin.Function0, onEmotionDetailToggled: kotlin.Function1, onSkipButtonClick: kotlin.Function0, onConfirmButtonClick: kotlin.Function0): kotlin.Unit @@ -226,12 +160,6 @@ internal fun com.ninecraft.booket.feature.record.step_v2.EmotionDetailBottomShee - onSkipButtonClick: STABLE (function type) - onConfirmButtonClick: STABLE (function type) -@Composable -private fun com.ninecraft.booket.feature.record.step_v2.EmotionDetailBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.record.step_v2.EmotionItem(emotion: com.ninecraft.booket.core.model.Emotion, selectedEmotionDetails: kotlinx.collections.immutable.ImmutableList, onClick: kotlin.Function0, isSelected: kotlin.Boolean, onEmotionDetailRemove: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -244,37 +172,19 @@ internal fun com.ninecraft.booket.feature.record.step_v2.EmotionItem(emotion: co - onEmotionDetailRemove: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.record.step_v2.EmotionItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.record.step_v2.EmotionStepV2(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: false - restartable: true - params: - - state: RUNTIME (requires runtime check) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.ninecraft.booket.feature.record.step_v2.EmotionStepV2Preview(): kotlin.Unit skippable: true restartable: true params: - -@Composable -internal fun com.ninecraft.booket.feature.record.step_v2.QuoteStepV2(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: false - restartable: true - params: - - state: RUNTIME (requires runtime check) + - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) @Composable -private fun com.ninecraft.booket.feature.record.step_v2.QuoteStepV2Preview(): kotlin.Unit +internal fun com.ninecraft.booket.feature.record.step_v2.QuoteStepV2(state: com.ninecraft.booket.feature.record.register.RecordRegisterUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true restartable: true params: + - state: STABLE (class with no mutable properties) + - modifier: STABLE (marked @Stable or @Immutable) diff --git a/feature/screens/stability/screens.stability b/feature/screens/stability/screens.stability index a47d75b1e..70f3502dc 100644 --- a/feature/screens/stability/screens.stability +++ b/feature/screens/stability/screens.stability @@ -23,9 +23,3 @@ private fun com.ninecraft.booket.feature.screens.component.MainBottomBarItem(tab - selected: STABLE (primitive type) - onClick: STABLE (function type) -@Composable -private fun com.ninecraft.booket.feature.screens.component.MainBottomBarPreview(): kotlin.Unit - skippable: true - restartable: true - params: - diff --git a/feature/search/stability/search.stability b/feature/search/stability/search.stability index 5e758f5e1..89be1232a 100644 --- a/feature/search/stability/search.stability +++ b/feature/search/stability/search.stability @@ -4,12 +4,6 @@ // Do not edit this file directly. To update it, run: // ./gradlew :search:stabilityDump -@Composable -private fun com.ninecraft.booket.feature.search.book.BookRecentSearchPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.search.book.BookSearchContent(state: com.ninecraft.booket.feature.search.book.BookSearchUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -18,12 +12,6 @@ internal fun com.ninecraft.booket.feature.search.book.BookSearchContent(state: c - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.search.book.BookSearchEmptyResultPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.search.book.BookSearchPresenter.present(): com.ninecraft.booket.feature.search.book.BookSearchUiState skippable: true @@ -56,12 +44,6 @@ public fun com.ninecraft.booket.feature.search.book.component.BookItem(book: com - modifier: STABLE (marked @Stable or @Immutable) - enabled: STABLE (primitive type) -@Composable -private fun com.ninecraft.booket.feature.search.book.component.BookItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.search.book.component.BookRegisterBottomSheet(onDismissRequest: kotlin.Function0, sheetState: androidx.compose.material3.SheetState, onCloseButtonClick: kotlin.Function0, bookStatuses: kotlinx.collections.immutable.ImmutableList, currentBookStatus: com.ninecraft.booket.core.common.constants.BookStatus?, onItemSelected: kotlin.Function1, onBookRegisterButtonClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -76,18 +58,6 @@ public fun com.ninecraft.booket.feature.search.book.component.BookRegisterBottom - onBookRegisterButtonClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.search.book.component.BookRegisterBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.search.book.component.BookRegisterSuccessBeforeReadingBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.search.book.component.BookRegisterSuccessBottomSheet(onDismissRequest: kotlin.Function0, sheetState: androidx.compose.material3.SheetState, upsertedBookStatus: com.ninecraft.booket.core.common.constants.BookStatus, onCancelButtonClick: kotlin.Function0, onOKButtonClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -100,18 +70,6 @@ public fun com.ninecraft.booket.feature.search.book.component.BookRegisterSucces - onOKButtonClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.search.book.component.BookRegisterSuccessCompletedBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - -@Composable -private fun com.ninecraft.booket.feature.search.book.component.BookRegisterSuccessReadingBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.search.book.component.BookStatusItem(item: com.ninecraft.booket.core.common.constants.BookStatus, selected: kotlin.Boolean, onClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -129,12 +87,6 @@ internal fun com.ninecraft.booket.feature.search.common.component.RecentSearchTi params: - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.search.common.component.RecentSearchTitlePreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.search.common.component.SearchItem(query: kotlin.String, onQueryClick: kotlin.Function1, onDeleteIconClick: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -145,12 +97,6 @@ public fun com.ninecraft.booket.feature.search.common.component.SearchItem(query - onDeleteIconClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.search.common.component.SearchItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.search.library.HandlingLibrarySearchSideEffect(state: com.ninecraft.booket.feature.search.library.LibrarySearchUiState): kotlin.Unit skippable: true @@ -173,12 +119,6 @@ public fun com.ninecraft.booket.feature.search.library.LibrarySearchPresenter.pr restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.search.library.LibrarySearchPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.search.library.LibrarySearchUi(state: com.ninecraft.booket.feature.search.library.LibrarySearchUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -196,9 +136,3 @@ public fun com.ninecraft.booket.feature.search.library.component.LibraryBookItem - onBookClick: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.search.library.component.LibraryBookItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - diff --git a/feature/settings/stability/settings.stability b/feature/settings/stability/settings.stability index 1d72f777a..8fdafda67 100644 --- a/feature/settings/stability/settings.stability +++ b/feature/settings/stability/settings.stability @@ -18,12 +18,6 @@ public fun com.ninecraft.booket.feature.settings.SettingsPresenter.present(): co restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.settings.SettingsScreenPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.settings.SettingsUi(state: com.ninecraft.booket.feature.settings.SettingsUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -41,12 +35,6 @@ internal fun com.ninecraft.booket.feature.settings.component.ReedSwitch(checked: - onCheckedChange: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.settings.component.ReedSwitchPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.settings.component.SettingItem(title: kotlin.String, modifier: androidx.compose.ui.Modifier, isClickable: kotlin.Boolean, onItemClick: kotlin.Function0, action: @[Composable] androidx.compose.runtime.internal.ComposableFunction0, description: @[Composable] androidx.compose.runtime.internal.ComposableFunction0): kotlin.Unit skippable: true @@ -59,12 +47,6 @@ internal fun com.ninecraft.booket.feature.settings.component.SettingItem(title: - action: STABLE (composable function type) - description: STABLE (composable function type) -@Composable -private fun com.ninecraft.booket.feature.settings.component.SettingItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.settings.component.ToggleItem(title: kotlin.String, description: kotlin.String, isChecked: kotlin.Boolean, onCheckedChange: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -76,12 +58,6 @@ internal fun com.ninecraft.booket.feature.settings.component.ToggleItem(title: k - onCheckedChange: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.settings.component.ToggleItemPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.feature.settings.component.WithdrawConfirmationBottomSheet(onDismissRequest: kotlin.Function0, sheetState: androidx.compose.material3.SheetState, isCheckBoxChecked: kotlin.Boolean, onCheckBoxCheckedChange: kotlin.Function0, onCancelButtonClick: kotlin.Function0, onWithdrawButtonClick: kotlin.Function0): kotlin.Unit skippable: true @@ -94,12 +70,6 @@ public fun com.ninecraft.booket.feature.settings.component.WithdrawConfirmationB - onCancelButtonClick: STABLE (function type) - onWithdrawButtonClick: STABLE (function type) -@Composable -private fun com.ninecraft.booket.feature.settings.component.WithdrawConfirmationBottomSheetPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable internal fun com.ninecraft.booket.feature.settings.notification.HandleNotificationSideEffects(state: com.ninecraft.booket.feature.settings.notification.NotificationUiState, eventSink: kotlin.Function1): kotlin.Unit skippable: true @@ -130,12 +100,6 @@ internal fun com.ninecraft.booket.feature.settings.notification.NotificationUi(s - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.settings.notification.NotificationUiPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable private fun com.ninecraft.booket.feature.settings.osslicenses.OssLicenseItem(name: kotlin.String, license: kotlin.String, url: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -160,9 +124,3 @@ public fun com.ninecraft.booket.feature.settings.osslicenses.OssLicensesPresente restartable: true params: -@Composable -private fun com.ninecraft.booket.feature.settings.osslicenses.OssLicensesScreenPreview(): kotlin.Unit - skippable: true - restartable: true - params: - diff --git a/feature/splash/stability/splash.stability b/feature/splash/stability/splash.stability index bc5f1e0e5..0791787f1 100644 --- a/feature/splash/stability/splash.stability +++ b/feature/splash/stability/splash.stability @@ -18,12 +18,6 @@ public fun com.ninecraft.booket.splash.SplashPresenter.present(): com.ninecraft. restartable: true params: -@Composable -private fun com.ninecraft.booket.splash.SplashPreview(): kotlin.Unit - skippable: true - restartable: true - params: - @Composable public fun com.ninecraft.booket.splash.SplashUi(state: com.ninecraft.booket.splash.SplashUiState, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true diff --git a/feature/webview/stability/webview.stability b/feature/webview/stability/webview.stability index 20982550f..5a8b88673 100644 --- a/feature/webview/stability/webview.stability +++ b/feature/webview/stability/webview.stability @@ -27,9 +27,3 @@ internal fun com.ninecraft.booket.feature.webview.WebViewUi(state: com.ninecraft - state: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.ninecraft.booket.feature.webview.WebViewUiPreview(): kotlin.Unit - skippable: true - restartable: true - params: - diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b3f5690b6..03a0fc802 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,38 +8,38 @@ versionCode = "9" packageName = "com.ninecraft.booket" ## Android gradle plugin -android-gradle-plugin = "8.9.3" +android-gradle-plugin = "8.12.0" ## AndroidX androidx-core = "1.16.0" androidx-activity-compose = "1.10.1" androidx-startup = "1.2.0" androidx-splash = "1.2.0" -androidx-datastore = "1.1.7" -androidx-camera = "1.5.1" +androidx-datastore = "1.2.0" +androidx-camera = "1.5.2" ## Compose -androidx-compose-bom = "2025.07.00" +androidx-compose-bom = "2025.12.01" 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" +ksp = "2.3.4" ## Kotlin -kotlin = "2.2.21" +kotlin = "2.3.0" kotlinx-coroutines = "1.10.2" kotlinx-serialization-json = "1.9.0" kotlinx-collections-immutable = "0.4.0" ## Metro -metro = "0.7.7" +metro = "0.9.4" ## Network -okhttp = "5.1.0" +okhttp = "5.3.2" retrofit = "3.0.0" ## Circuit @@ -70,13 +70,13 @@ kotlin-ktlint-gradle = "11.6.1" kotlin-ktlint-source = "0.50.0" ## Test -androidx-test-ext-junit = "1.2.1" -androidx-test-runner = "1.6.2" +androidx-test-ext-junit = "1.3.0" +androidx-test-runner = "1.7.0" ## Firebase -google-service = "4.4.3" -firebase-bom = "34.1.0" -firebase-crashlytics = "3.0.4" +google-service = "4.4.4" +firebase-bom = "34.7.0" +firebase-crashlytics = "3.0.6" [libraries] android-gradle-plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android-gradle-plugin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8f89fa561..70a31fa76 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Jun 13 20:04:35 KST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists