Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8159e56
[BOOK-482] feat: Reading-Records v2 스펙에 맞게 모델 스키마 변경
seoyoon513 Dec 31, 2025
98d4841
[BOOK-482] feat: emotions API 구성 WIP
seoyoon513 Dec 31, 2025
f58c308
[BOOK-482] feat: V2 API 작업 WIP
seoyoon513 Jan 1, 2026
d51436d
[BOOK-482] feat: 미사용 V1 컴포넌트 삭제
seoyoon513 Jan 8, 2026
307916b
[BOOK-482] feat: emotions API 연동 및 미사용 state 정리
seoyoon513 Jan 8, 2026
124869f
[BOOK-482] feat: 감정 선택 플로우를 임시 로컬 데이터에서 서버 데이터 기반으로 전환
seoyoon513 Jan 8, 2026
0ecd802
[BOOK-482] feat: 기타 감정 선택지 추가
seoyoon513 Jan 8, 2026
243a754
[BOOK-482] feat: 기록 상세 화면 UI 변경사항 반영
seoyoon513 Jan 8, 2026
67c6a33
[BOOK-482] feat: 기록 수정 화면 WIP
seoyoon513 Jan 8, 2026
a0dfb9b
[BOOK-482] feat: 기록 수정 UI 및 API 변경사항 적용
seoyoon513 Jan 8, 2026
5e68b07
[BOOK-482] feat: 기록 카드 '기타' 리소스 추가 및 EmotionCode를 사용하도록 수정
seoyoon513 Jan 8, 2026
65b22b2
[BOOK-482] chore: 빌드 에러를 막기 위한 임시 코드 추가
seoyoon513 Jan 8, 2026
7e44f39
[BOOK-482] refactor: 버저닝에 따른 독서 기록 모델 분리 ReadingRecord, ReadingRecordV2
seoyoon513 Jan 8, 2026
e6e1b7f
[BOOK-482] chore: code style check success
seoyoon513 Jan 8, 2026
ffcebad
[BOOK-482] refactor: 미사용 감정 그래픽 리소스 삭제 및 네이밍 수정
seoyoon513 Jan 8, 2026
fc9ff9f
[BOOK-482] feat: 독서 기록 프로그래스바 3단계 -> 2단계로 축소
seoyoon513 Jan 9, 2026
c579c86
[BOOK-482] feat: 페이지 입력 optional 처리
seoyoon513 Jan 10, 2026
9d3e7be
[BOOK-482] fix: 리뷰 아이템 날짜 영역 UI 찌그러지는 문제 수정
seoyoon513 Jan 10, 2026
927604f
[BOOK-482] feat: 감정 선택 & 수정 화면 에러 핸들링 추가
seoyoon513 Jan 10, 2026
c3b5561
[BOOK-482] fix: 기타 감정 선택 시 세부 감정 맵 초기화
seoyoon513 Jan 12, 2026
062c494
[BOOK-482] feat: 감정 수정 시 확인 다이얼로그 추가
seoyoon513 Jan 12, 2026
bc262ae
[BOOK-482] refactor: 감정 상태 Map -> PersistentMap으로 변경
seoyoon513 Jan 12, 2026
3389860
[BOOK-482] refactor: V2 suffix 제거
seoyoon513 Jan 12, 2026
fda02ec
[BOOK-482] chore: 감정 씨앗 리소스 변경
seoyoon513 Jan 12, 2026
ccfe6a7
[BOOK-482] feat: 기록 수정 화면 감상평 -> 메모 라벨 변경
seoyoon513 Jan 12, 2026
611ee4f
[BOOK-482] fix: 토끼 리뷰 반영
seoyoon513 Jan 12, 2026
f2f5532
Merge branch 'develop' into BOOK-482-feature/#244
seoyoon513 Jan 12, 2026
bad3fe2
[BOOK-482] fix: 빌드 오류 해결
seoyoon513 Jan 12, 2026
59b953c
[BOOK-482] fix: compose-bom 업그레이드 롤백
seoyoon513 Jan 13, 2026
5849c3d
[BOOK-482] refactor: Rename `committedEmotion` to `committedEmotionCode`
seoyoon513 Jan 13, 2026
0cd02b7
[BOOK-482] chore: compose stability 최신화
easyhooon Jan 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ninecraft.booket.core.data.api.repository

import com.ninecraft.booket.core.model.EmotionGroupsModel

interface EmotionRepository {
suspend fun getEmotions(): Result<EmotionGroupsModel>
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
package com.ninecraft.booket.core.data.api.repository

import com.ninecraft.booket.core.model.ReadingRecordModel
import com.ninecraft.booket.core.model.RecordRegisterModel
import com.ninecraft.booket.core.model.ReadingRecordModelV2
import com.ninecraft.booket.core.model.ReadingRecordsModel
import com.ninecraft.booket.core.model.RecordDetailModel

interface RecordRepository {
suspend fun postRecord(
userBookId: String,
pageNumber: Int,
pageNumber: Int?,
quote: String,
emotionTags: List<String>,
review: String,
): Result<RecordRegisterModel>
primaryEmotion: String,
detailEmotionTagIds: List<String>,
): Result<ReadingRecordModelV2>

suspend fun getReadingRecords(
userBookId: String,
sort: String,
page: Int,
size: Int,
): Result<ReadingRecordsModel>
): Result<ReadingRecordsModel> // TODO: V2로 변경 필요

suspend fun getRecordDetail(
readingRecordId: String,
): Result<RecordDetailModel>
): Result<ReadingRecordModelV2>

suspend fun editRecord(
readingRecordId: String,
pageNumber: Int,
pageNumber: Int?,
quote: String,
emotionTags: List<String>,
review: String,
): Result<ReadingRecordModel>
primaryEmotion: String,
detailEmotionTagIds: List<String>,
): Result<ReadingRecordModelV2>

suspend fun deleteRecord(
readingRecordId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package com.ninecraft.booket.core.data.impl.di

import com.ninecraft.booket.core.data.api.repository.AuthRepository
import com.ninecraft.booket.core.data.api.repository.BookRepository
import com.ninecraft.booket.core.data.api.repository.EmotionRepository
import com.ninecraft.booket.core.data.api.repository.RecordRepository
import com.ninecraft.booket.core.data.api.repository.RemoteConfigRepository
import com.ninecraft.booket.core.data.api.repository.UserRepository
import com.ninecraft.booket.core.data.impl.repository.DefaultAuthRepository
import com.ninecraft.booket.core.data.impl.repository.DefaultBookRepository
import com.ninecraft.booket.core.data.impl.repository.DefaultEmotionRepository
import com.ninecraft.booket.core.data.impl.repository.DefaultRecordRepository
import com.ninecraft.booket.core.data.impl.repository.DefaultRemoteConfigRepository
import com.ninecraft.booket.core.data.impl.repository.DefaultUserRepository
Expand All @@ -23,6 +25,9 @@ interface DataGraph {
@Binds
val DefaultBookRepository.bind: BookRepository

@Binds
val DefaultEmotionRepository.bind: EmotionRepository

@Binds
val DefaultRecordRepository.bind: RecordRepository

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
package com.ninecraft.booket.core.data.impl.mapper

import com.ninecraft.booket.core.common.extensions.decodeHtmlEntities
import com.ninecraft.booket.core.common.extensions.toFormattedDate
import com.ninecraft.booket.core.model.BookDetailModel
import com.ninecraft.booket.core.model.BookSearchModel
import com.ninecraft.booket.core.model.BookSummaryModel
import com.ninecraft.booket.core.model.BookUpsertModel
import com.ninecraft.booket.core.model.DetailEmotionModel
import com.ninecraft.booket.core.model.Emotion
import com.ninecraft.booket.core.model.EmotionCode
import com.ninecraft.booket.core.model.EmotionGroupModel
import com.ninecraft.booket.core.model.EmotionGroupsModel
import com.ninecraft.booket.core.model.EmotionModel
import com.ninecraft.booket.core.model.HomeModel
import com.ninecraft.booket.core.model.LibraryBookSummaryModel
import com.ninecraft.booket.core.model.LibraryBooksModel
import com.ninecraft.booket.core.model.LibraryModel
import com.ninecraft.booket.core.model.PageInfoModel
import com.ninecraft.booket.core.model.PrimaryEmotionModel
import com.ninecraft.booket.core.model.ReadingRecordModel
import com.ninecraft.booket.core.model.ReadingRecordModelV2
import com.ninecraft.booket.core.model.ReadingRecordsModel
import com.ninecraft.booket.core.model.RecentBookModel
import com.ninecraft.booket.core.model.RecordDetailModel
import com.ninecraft.booket.core.model.RecordRegisterModel
import com.ninecraft.booket.core.model.SeedModel
import com.ninecraft.booket.core.model.TermsAgreementModel
Expand All @@ -26,17 +30,21 @@ import com.ninecraft.booket.core.network.response.BookSearchResponse
import com.ninecraft.booket.core.network.response.BookSummary
import com.ninecraft.booket.core.network.response.BookUpsertResponse
import com.ninecraft.booket.core.network.response.Category
import com.ninecraft.booket.core.network.response.DetailEmotion
import com.ninecraft.booket.core.network.response.EmotionGroup
import com.ninecraft.booket.core.network.response.EmotionGroupsResponse
import com.ninecraft.booket.core.network.response.GuestBookSearchResponse
import com.ninecraft.booket.core.network.response.GuestBookSummary
import com.ninecraft.booket.core.network.response.HomeResponse
import com.ninecraft.booket.core.network.response.LibraryBookSummary
import com.ninecraft.booket.core.network.response.LibraryBooks
import com.ninecraft.booket.core.network.response.LibraryResponse
import com.ninecraft.booket.core.network.response.PageInfo
import com.ninecraft.booket.core.network.response.PrimaryEmotion
import com.ninecraft.booket.core.network.response.ReadingRecord
import com.ninecraft.booket.core.network.response.ReadingRecordV2
import com.ninecraft.booket.core.network.response.ReadingRecordsResponse
import com.ninecraft.booket.core.network.response.RecentBook
import com.ninecraft.booket.core.network.response.RecordDetailResponse
import com.ninecraft.booket.core.network.response.RecordRegisterResponse
import com.ninecraft.booket.core.network.response.SeedResponse
import com.ninecraft.booket.core.network.response.TermsAgreementResponse
Expand Down Expand Up @@ -187,6 +195,28 @@ internal fun PageInfo.toModel(): PageInfoModel {
)
}

internal fun EmotionGroupsResponse.toModel(): EmotionGroupsModel {
return EmotionGroupsModel(
emotions = emotions.map { it.toModel() },
)
}

internal fun EmotionGroup.toModel(): EmotionGroupModel {
val code = EmotionCode.fromCode(code) ?: EmotionCode.OTHER
return EmotionGroupModel(
code = code,
displayName = displayName,
detailEmotions = detailEmotions.map { it.toModel() },
)
}

internal fun DetailEmotion.toModel(): DetailEmotionModel {
return DetailEmotionModel(
id = id,
name = name,
)
}

internal fun RecordRegisterResponse.toModel(): RecordRegisterModel {
return RecordRegisterModel(
id = id,
Expand Down Expand Up @@ -220,27 +250,36 @@ internal fun ReadingRecord.toModel(): ReadingRecordModel {
emotionTags = emotionTags,
createdAt = createdAt,
updatedAt = updatedAt,
bookTitle = bookTitle,
bookPublisher = bookPublisher,
bookCoverImageUrl = bookCoverImageUrl,
author = author,
bookTitle = bookTitle ?: "",
bookPublisher = bookPublisher ?: "",
bookCoverImageUrl = bookCoverImageUrl ?: "",
author = author ?: "",
)
}

internal fun RecordDetailResponse.toModel(): RecordDetailModel {
return RecordDetailModel(
internal fun ReadingRecordV2.toModel(): ReadingRecordModelV2 {
return ReadingRecordModelV2(
id = id,
userBookId = userBookId,
pageNumber = pageNumber,
quote = quote,
review = review ?: "",
emotionTags = emotionTags,
createdAt = createdAt.toFormattedDate(),
updatedAt = updatedAt.toFormattedDate(),
bookTitle = bookTitle,
bookPublisher = bookPublisher,
bookCoverImageUrl = bookCoverImageUrl,
author = author,
primaryEmotion = primaryEmotion.toModel(),
detailEmotions = detailEmotions.map { it.toModel() },
createdAt = createdAt,
updatedAt = updatedAt,
bookTitle = bookTitle ?: "",
bookPublisher = bookPublisher ?: "",
bookCoverImageUrl = bookCoverImageUrl ?: "",
author = author ?: "",
)
}

internal fun PrimaryEmotion.toModel(): PrimaryEmotionModel {
val code = EmotionCode.fromCode(code) ?: EmotionCode.OTHER
return PrimaryEmotionModel(
code = code,
displayName = displayName,
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.ninecraft.booket.core.data.impl.repository

import com.ninecraft.booket.core.common.utils.runSuspendCatching
import com.ninecraft.booket.core.data.api.repository.EmotionRepository
import com.ninecraft.booket.core.data.impl.mapper.toModel
import com.ninecraft.booket.core.di.DataScope
import com.ninecraft.booket.core.model.EmotionGroupsModel
import com.ninecraft.booket.core.network.service.ReedService
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn

@SingleIn(DataScope::class)
@Inject
class DefaultEmotionRepository(
private val service: ReedService,
) : EmotionRepository {
override suspend fun getEmotions(): Result<EmotionGroupsModel> = runSuspendCatching {
service.getEmotions().toModel()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package com.ninecraft.booket.core.data.impl.repository
import com.ninecraft.booket.core.common.utils.runSuspendCatching
import com.ninecraft.booket.core.data.api.repository.RecordRepository
import com.ninecraft.booket.core.data.impl.mapper.toModel
import com.ninecraft.booket.core.model.ReadingRecordModel
import com.ninecraft.booket.core.di.DataScope
import com.ninecraft.booket.core.network.request.RecordRegisterRequest
import com.ninecraft.booket.core.network.service.ReedService
import dev.zacsweers.metro.Inject
import com.ninecraft.booket.core.di.DataScope
import dev.zacsweers.metro.SingleIn

@SingleIn(DataScope::class)
Expand All @@ -17,12 +16,13 @@ class DefaultRecordRepository(
) : RecordRepository {
override suspend fun postRecord(
userBookId: String,
pageNumber: Int,
pageNumber: Int?,
quote: String,
emotionTags: List<String>,
review: String,
primaryEmotion: String,
detailEmotionTagIds: List<String>,
) = runSuspendCatching {
service.postRecord(userBookId, RecordRegisterRequest(pageNumber, quote, emotionTags, review)).toModel()
service.postRecord(userBookId, RecordRegisterRequest(pageNumber, quote, review, primaryEmotion, detailEmotionTagIds)).toModel()
}

override suspend fun getReadingRecords(
Expand All @@ -40,12 +40,13 @@ class DefaultRecordRepository(

override suspend fun editRecord(
readingRecordId: String,
pageNumber: Int,
pageNumber: Int?,
quote: String,
emotionTags: List<String>,
review: String,
): Result<ReadingRecordModel> = runSuspendCatching {
service.editRecord(readingRecordId, RecordRegisterRequest(pageNumber, quote, emotionTags, review)).toModel()
primaryEmotion: String,
detailEmotionTagIds: List<String>,
) = runSuspendCatching {
service.editRecord(readingRecordId, RecordRegisterRequest(pageNumber, quote, review, primaryEmotion, detailEmotionTagIds)).toModel()
}

override suspend fun deleteRecord(readingRecordId: String): Result<Unit> = runSuspendCatching {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ 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
import com.ninecraft.booket.core.model.EmotionCode

val Emotion.bgColor: Color
get() = when (this) {
Expand All @@ -36,15 +37,6 @@ val Emotion.textColor: Color
Emotion.ETC -> EtcTextColor
}

val Emotion.graphicRes: Int
get() = when (this) {
Emotion.WARM -> R.drawable.img_emotion_warmth
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.ratioBarColor: Color
get() = when (this) {
Emotion.WARM -> Yellow300
Expand All @@ -54,20 +46,29 @@ val Emotion.ratioBarColor: Color
Emotion.ETC -> Neutral300
}

val Emotion.graphicResV2: Int?
val EmotionCode.graphicRes: Int
get() = when (this) {
EmotionCode.WARMTH -> R.drawable.img_warmth
EmotionCode.JOY -> R.drawable.img_joy
EmotionCode.SADNESS -> R.drawable.img_sadness
EmotionCode.INSIGHT -> R.drawable.img_insight
EmotionCode.OTHER -> R.drawable.img_other
}

val EmotionCode.categoryGraphicRes: 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
EmotionCode.WARMTH -> R.drawable.img_category_warmth
EmotionCode.JOY -> R.drawable.img_category_joy
EmotionCode.SADNESS -> R.drawable.img_category_sadness
EmotionCode.INSIGHT -> R.drawable.img_category_insight
EmotionCode.OTHER -> null
}

val Emotion.descriptionRes: Int
val EmotionCode.descriptionRes: Int
get() = when (this) {
Emotion.WARM -> R.string.emotion_warm_description
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
EmotionCode.WARMTH -> R.string.emotion_warm_description
EmotionCode.JOY -> R.string.emotion_joy_description
EmotionCode.SADNESS -> R.string.emotion_sad_description
EmotionCode.INSIGHT -> R.string.emotion_insight_description
EmotionCode.OTHER -> R.string.emotion_other_description
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.ninecraft.booket.core.designsystem
enum class RecordStep {
QUOTE,
EMOTION,
IMPRESSION,
;

val value: Int get() = ordinal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fun RecordProgressBar(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(ReedTheme.spacing.spacing1),
) {
repeat(3) { index ->
repeat(2) { index ->
val bgColor = if (index <= currentStep.ordinal) ReedTheme.colors.bgPrimary else ReedTheme.colors.bgDisabled

Box(
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion core/designsystem/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
<string name="emotion_joy_description">흥미롭고 유쾌한 순간</string>
<string name="emotion_sad_description">눈물이 고인 순간</string>
<string name="emotion_insight_description">생각이 깊어지는 순간</string>
<string name="emotion_etc_description">네 가지 감정으로 표현하기 어려울 때</string>
<string name="emotion_other_description">네 가지 감정으로 표현하기 어려울 때</string>
</resources>
Loading
Loading