Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TNT-181] 트레이니 홈 화면 일별 기록 UI 구현 #71

Merged
merged 19 commits into from
Feb 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
29157f1
[TNT-181] refactor: RecordChip에 ChipStyle 추가
SeonJeongk Feb 7, 2025
a8f4659
[TNT-181] feat: 선택된 날짜의 PT수업과 기록 UI 구현
SeonJeongk Feb 7, 2025
04f8216
[TNT-181] fix: 기록/일정 있는 날짜에 icon 보이도록 수정
SeonJeongk Feb 8, 2025
49f681d
[TNT-181] fix: 배경색 수정
SeonJeongk Feb 8, 2025
6a1f84e
[TNT-181] fix: lint 오류 해결
SeonJeongk Feb 8, 2025
6f6d237
[TNT-181] refactor: Scaffold 대신 LazyColumn으로 구현
SeonJeongk Feb 8, 2025
73e1705
[TNT-181] feat: 트레이니 홈화면 기록 관련 data class 구현
SeonJeongk Feb 8, 2025
517dd69
[TNT-181] feat: TraineeRepository 생성
SeonJeongk Feb 8, 2025
e3c2e6a
[TNT-181] fix: Repository에서 UI 데이터 받아오도록 수정
SeonJeongk Feb 8, 2025
aa7d45f
[TNT-181] refactor: 변수명 수정
SeonJeongk Feb 8, 2025
bb70441
[TNT-181] fix: 선택된 날짜 관리 state로 통일
SeonJeongk Feb 8, 2025
07fce7d
[TNT-181] fix: import 순서 변경
SeonJeongk Feb 8, 2025
9c5913d
[TNT-181] refactor: composable 분리
SeonJeongk Feb 8, 2025
5928b51
[TNT-181] refactor: 화면 간격 수정
SeonJeongk Feb 8, 2025
7f7bb7a
[TNT-181] fix: 기록 데이터 null 허용 제거
SeonJeongk Feb 8, 2025
d2cde4c
[TNT-181] fix: 주간 이동 시 선택된 날짜 변경되지 않도록 수정
SeonJeongk Feb 8, 2025
ca33ad3
[TNT-181] feat: develop branch DataFormatter 코드 추가
SeonJeongk Feb 9, 2025
896295e
[TNT-181] feat: 데이터 클래스 리팩토링 및 도메인 변환 구현
SeonJeongk Feb 9, 2025
0514a9f
[TNT-181] refactor: 변수명 변경
SeonJeongk Feb 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ private fun TnTTrainerSessionRecordCardPreview() {
TnTTheme {
TnTSessionRecordCard(
name = "김회원",
tagText = "8회차 수업",
tagText = "8",
startTime = "오후 17:00",
endTime = "오후 18:00",
defaultImage = painterResource(R.drawable.img_default),
Expand All @@ -382,7 +382,7 @@ private fun TnTTraineeSessionRecordCardPreview() {
TnTTheme {
TnTSessionRecordCard(
name = "김민수 트레이너",
tagText = "6회차 수업",
tagText = "6",
startTime = "오후 17:00",
endTime = "오후 18:00",
defaultImage = painterResource(R.drawable.img_default),
Expand Down
1 change: 1 addition & 0 deletions core/designsystem/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<string name="received_feedback">받은 피드백</string>
<string name="make_pt_session_record">PT 수업 기록 남기기</string>
<string name="see_pt_session_record">수업 기록 보기</string>
<string name="lesson_count">%s회차 수업</string>

<!-- Calendar -->
<string name="year_month_format">yyyy년 M월</string>
Expand Down
14 changes: 11 additions & 3 deletions core/ui/src/main/java/co/kr/tnt/ui/model/RecordChip.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,29 @@ package co.kr.tnt.ui.model
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import co.kr.tnt.core.ui.R
import co.kr.tnt.designsystem.component.chip.model.ChipStyle
import co.kr.tnt.domain.model.RecordType

sealed interface RecordChip {
val title: String
val emoji: String?
val chipStyle: ChipStyle

data class MealChip(
override val title: String,
override val emoji: String,
override val chipStyle: ChipStyle,
) : RecordChip
data class ExerciseChip(
override val title: String,
override val emoji: String? = null,
override val chipStyle: ChipStyle,
) : RecordChip
data class PTSessionChip(
override val title: String,
val sessionCount: Int,
override val emoji: String,
override val chipStyle: ChipStyle,
) : RecordChip

companion object {
Expand All @@ -40,7 +45,7 @@ sealed interface RecordChip {
RecordType.MealType.DINNER -> "🌙"
RecordType.MealType.SNACK -> "🍰"
}
MealChip(title, emoji)
MealChip(title, emoji, ChipStyle.PINK)
}

is RecordType.ExerciseType -> {
Expand All @@ -51,13 +56,16 @@ sealed interface RecordChip {
RecordType.ExerciseType.SHOULDER -> stringResource(R.string.exercise_shoulder)
RecordType.ExerciseType.CARDIO -> stringResource(R.string.exercise_cardio)
}
ExerciseChip(title)
ExerciseChip(
title = title,
chipStyle = ChipStyle.BLUE,
)
}

is RecordType.PTSessionType -> {
val title = stringResource(R.string.pt_session, type.sessionCount)
val emoji = "💪"
PTSessionChip(title, type.sessionCount, emoji)
PTSessionChip(title, type.sessionCount, emoji, ChipStyle.BLUE)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package co.kr.data.network.model.trainee

import co.kr.tnt.domain.model.RecordType
import co.kr.tnt.domain.model.RecordType.ExerciseType
import co.kr.tnt.domain.model.RecordType.MealType
import co.kr.tnt.domain.model.trainee.DailyRecord
import co.kr.tnt.domain.model.trainee.PtSession
import co.kr.tnt.domain.model.trainee.TraineeDailyRecord
import co.kr.tnt.domain.utils.DateFormatter
import kotlinx.serialization.Serializable

@Serializable
data class DailyRecordsResponse(
val date: String,
val lessons: PtSessionResponse?,
val records: List<RecordResponse>,
)

@Serializable
data class PtSessionResponse(
val ptSessionId: String,
val trainerName: String,
val trainerImage: String?,
val session: Int,
val startTime: String,
val endTime: String,
val hasRecord: Boolean,
)

@Serializable
data class RecordResponse(
val recordId: String,
val recordType: String,
val recordTime: String,
val recordImage: String?,
val recordContents: String,
val feedbackCount: Int,
)

fun DailyRecordsResponse.toDomain(dateFormatter: DateFormatter) =
TraineeDailyRecord(
date = dateFormatter.parse(date),
ptSession = lessons?.toDomain(dateFormatter),
record = records.map { it.toDomain(dateFormatter) },
)

fun PtSessionResponse.toDomain(dateFormatter: DateFormatter) = PtSession(
ptSessionId = ptSessionId,
trainerName = trainerName,
trainerImage = trainerImage,
session = session,
startTime = dateFormatter.parseDateTime(startTime),
endTime = dateFormatter.parseDateTime(endTime),
hasRecord = hasRecord,
)

fun RecordResponse.toDomain(dateFormatter: DateFormatter) = DailyRecord(
recordId = recordId,
recordType = recordType.toRecordType() ?: MealType.BREAKFAST,
recordTime = dateFormatter.parseDateTime(recordTime),
recordImage = recordImage,
recordContents = recordContents,
feedbackCount = feedbackCount,
)

// TODO : 수정
fun String.toRecordType(): RecordType? {
return when (this.uppercase()) {
"BREAKFAST" -> MealType.BREAKFAST
"LUNCH" -> MealType.LUNCH
"DINNER" -> MealType.DINNER
"SNACK" -> MealType.SNACK

"UPPER_BODY" -> ExerciseType.UPPER_BODY
"LOWER_BODY" -> ExerciseType.LOWER_BODY
"BACK" -> ExerciseType.BACK
"SHOULDER" -> ExerciseType.SHOULDER
"CARDIO" -> ExerciseType.CARDIO

else -> null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package co.kr.data.network.model.trainee

import co.kr.tnt.domain.model.trainee.TraineeDailyRecordStatus
import co.kr.tnt.domain.utils.DateFormatter
import kotlinx.serialization.Serializable

@Serializable
data class MonthlyRecordedDatesResponse(
val calendarRecordInfo: List<RecordedDateResponse>,
)

@Serializable
data class RecordedDateResponse(
val date: String,
)

fun RecordedDateResponse.toDomain(dateFormatter: DateFormatter) =
TraineeDailyRecordStatus(
date = dateFormatter.parse(date),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package co.kr.data.repository

import co.kr.data.network.model.trainee.DailyRecordsResponse
import co.kr.data.network.model.trainee.MonthlyRecordedDatesResponse
import co.kr.data.network.model.trainee.PtSessionResponse
import co.kr.data.network.model.trainee.RecordResponse
import co.kr.data.network.model.trainee.RecordedDateResponse
import co.kr.data.network.model.trainee.toDomain
import co.kr.tnt.domain.model.trainee.TraineeDailyRecord
import co.kr.tnt.domain.model.trainee.TraineeDailyRecordStatus
import co.kr.tnt.domain.repository.TraineeRepository
import co.kr.tnt.domain.utils.DateFormatter
import java.time.LocalDate
import java.time.YearMonth
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
internal class TraineeRepositoryImpl @Inject constructor(
private val dateFormatter: DateFormatter,
) : TraineeRepository {
// TODO : API에 맞춰 수정
override suspend fun getDailyDataStatus(yearMonth: YearMonth): List<TraineeDailyRecordStatus> {
val result = MonthlyRecordedDatesResponse(
listOf(
RecordedDateResponse(date = "2025-02-03"),
RecordedDateResponse(date = "2025-02-08"),
RecordedDateResponse(date = "2025-02-10"),
RecordedDateResponse(date = "2025-02-15"),
RecordedDateResponse(date = "2025-02-23"),
),
).calendarRecordInfo.map { response ->
response.toDomain(dateFormatter)
}

return result
}

override suspend fun getTraineeDailyRecord(day: LocalDate): TraineeDailyRecord {
val result = listOf(
DailyRecordsResponse(
date = "2025-02-03",
lessons = PtSessionResponse(
ptSessionId = "CDE35K32",
trainerName = "김헬스",
trainerImage = "https://buly.kr/44x6xFN",
session = 12,
startTime = "2025-02-03T08:00:00.000Z",
endTime = "2025-02-03T09:00:00.000Z",
hasRecord = true,
),
records = listOf(
RecordResponse(
recordId = "VDF1D907",
recordType = "BREAKFAST",
recordTime = "2025-02-03T08:00:00.000Z",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "아침으로 계란 2개 먹었습니다.",
feedbackCount = 1,
),
RecordResponse(
recordId = "VDF1D907",
recordType = "LUNCH",
recordTime = "2025-02-03T13:00:00.000Z",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "점심으로 계란 5개 먹었습니다.",
feedbackCount = 0,
),
),
),
DailyRecordsResponse(
date = "2025-02-08",
lessons = null,
records = listOf(
RecordResponse(
recordId = "VDF1D907",
recordType = "BREAKFAST",
recordTime = "2025-02-08T13:00:00.000Z",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "계란 2개 먹었습니다.",
feedbackCount = 1,
),
RecordResponse(
recordId = "VDF1D907",
recordType = "SNACK",
recordTime = "2025-02-08T15:00:00.000Z",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "계란 반개 먹었습니다.",
feedbackCount = 0,
),
RecordResponse(
recordId = "VDF1D907",
recordType = "DINNER",
recordTime = "2025-02-08T18:40:00.000Z",
recordImage = null,
recordContents = "저녁으로 소고기 먹었습니다.",
feedbackCount = 2,
),
),
),
DailyRecordsResponse(
date = "2025-02-15",
lessons = PtSessionResponse(
ptSessionId = "OSI93DG1",
trainerName = "이강사",
trainerImage = null,
session = 15,
startTime = "2025-02-15T18:00:00.000Z",
endTime = "2025-02-15T19:00:00.000Z",
hasRecord = true,
),
records = listOf(
RecordResponse(
recordId = "VDF1D907",
recordType = "LUNCH",
recordTime = "2025-02-15T13:00:00.000Z",
recordImage = null,
recordContents = "비빔밥, 바나나 1개",
feedbackCount = 1,
),
RecordResponse(
recordId = "VDF1D907",
recordType = "DINNER",
recordTime = "2025-02-03T20:00:00.000Z",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "계란 5개 먹었습니다.",
feedbackCount = 0,
),
),
),
DailyRecordsResponse(
date = "2025-02-10",
lessons = PtSessionResponse(
ptSessionId = "CDK392DF",
trainerName = "박트레이너",
trainerImage = null,
session = 10,
startTime = "2025-02-10T14:30:00.000Z",
endTime = "2025-02-10T15:30:00.000Z",
hasRecord = false,
),
records = emptyList(),
),
DailyRecordsResponse(
date = "2025-02-23",
lessons = PtSessionResponse(
ptSessionId = "CDE35K32",
trainerName = "정트레이너",
trainerImage = "https://buly.kr/44x6xFN",
session = 25,
startTime = "2025-02-23T06:00:00.000Z",
endTime = "2025-02-23T06:50:00.000Z",
hasRecord = true,
),
records = emptyList(),
),
).map { response ->
response.toDomain(dateFormatter)
}.firstOrNull { it.date == day }

val noData = TraineeDailyRecord(
date = day,
ptSession = null,
record = emptyList(),
)

return result ?: noData
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package co.kr.data.repository.di
import co.kr.data.repository.ConnectRepositoryImpl
import co.kr.data.repository.LoginRepositoryImpl
import co.kr.data.repository.SignUpRepositoryImpl
import co.kr.data.repository.TraineeRepositoryImpl
import co.kr.data.repository.TrainerRepositoryImpl
import co.kr.tnt.domain.repository.ConnectRepository
import co.kr.tnt.domain.repository.LoginRepository
import co.kr.tnt.domain.repository.SignUpRepository
import co.kr.tnt.domain.repository.TraineeRepository
import co.kr.tnt.domain.repository.TrainerRepository
import dagger.Binds
import dagger.Module
Expand Down Expand Up @@ -35,4 +37,9 @@ internal abstract class RepositoryModule {
abstract fun bindTrainerRepository(
repository: TrainerRepositoryImpl,
): TrainerRepository

@Binds
abstract fun bindTraineeRepository(
repository: TraineeRepositoryImpl,
): TraineeRepository
}
Loading