Skip to content

Commit

Permalink
Merge pull request #68 from YAPP-Github/feature/TNT-178
Browse files Browse the repository at this point in the history
[TNT-178] ํŠธ๋ ˆ์ด๋„ˆ ํ™ˆํ™”๋ฉด ์บ˜๋ฆฐ๋” ๊ตฌํ˜„
  • Loading branch information
hoyahozz authored Feb 8, 2025
2 parents c3ca0ff + 397b573 commit d3e67a9
Show file tree
Hide file tree
Showing 16 changed files with 303 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package co.kr.tnt.designsystem.component.calendar

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import co.kr.tnt.designsystem.component.calendar.composable.CalendarCell
import co.kr.tnt.designsystem.component.calendar.composable.CalendarCellWithIndicator
import co.kr.tnt.designsystem.component.calendar.composable.WeekLabels
Expand All @@ -13,9 +17,11 @@ import co.kr.tnt.designsystem.theme.TnTTheme
import com.kizitonwose.calendar.compose.CalendarState
import com.kizitonwose.calendar.compose.HorizontalCalendar
import com.kizitonwose.calendar.compose.rememberCalendarState
import com.kizitonwose.calendar.core.CalendarDay
import com.kizitonwose.calendar.core.DayPosition
import com.kizitonwose.calendar.core.daysOfWeek
import com.kizitonwose.calendar.core.yearMonth
import java.time.DayOfWeek
import java.time.LocalDate

@Composable
Expand All @@ -35,11 +41,16 @@ fun TnTMonthCalendar(
},
dayContent = { day ->
if (day.position == DayPosition.MonthDate) {
CalendarCell(
date = day.date,
state = dayState(day.date),
onClick = { onClickDay?.invoke(day.date) },
)
Column {
if (isFirstWeekOfMonth(day, state.firstDayOfWeek).not()) {
Spacer(modifier = Modifier.height(12.dp))
}
CalendarCell(
date = day.date,
state = dayState(day.date),
onClick = { onClickDay?.invoke(day.date) },
)
}
}
},
)
Expand All @@ -63,17 +74,40 @@ fun TnTIndicatorMonthCalendar(
},
dayContent = { day ->
if (day.position == DayPosition.MonthDate) {
CalendarCellWithIndicator(
date = day.date,
dayState = dayState(day.date),
indicatorState = indicatorState(day.date),
onClick = { onClickDay?.invoke(day.date) },
)
Column {
if (isFirstWeekOfMonth(day, state.firstDayOfWeek).not()) {
Spacer(modifier = Modifier.height(12.dp))
}
CalendarCellWithIndicator(
date = day.date,
dayState = dayState(day.date),
indicatorState = indicatorState(day.date),
onClick = { onClickDay?.invoke(day.date) },
)
}
}
},
)
}

private fun isFirstWeekOfMonth(
day: CalendarDay,
firstDayOfWeek: DayOfWeek,
): Boolean {
val startOfMonth = day.date.withDayOfMonth(1)
val firstDayOfStartWeek = startOfMonth.minusDays(
(startOfMonth.dayOfWeek.value % firstDayOfWeek.value).toLong(),
)

val firstWeekDays = buildList<LocalDate> {
repeat(7) { day ->
add(firstDayOfStartWeek.plusDays(day.toLong()))
}
}

return firstWeekDays.contains(day.date)
}

@Preview(showBackground = true)
@Preview(showBackground = true, widthDp = 500)
@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
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.res.painterResource
Expand Down Expand Up @@ -94,13 +95,22 @@ private fun CalendarDay(
isSelected: Boolean,
modifier: Modifier = Modifier,
) {
val today = remember { LocalDate.now() }
val isToday = date == today

val backgroundColor = when {
isSelected -> TnTTheme.colors.neutralColors.Neutral900
isToday -> TnTTheme.colors.neutralColors.Neutral200
else -> null
}

Box(
modifier = modifier
.size(32.dp)
.then(
if (isSelected) {
if (backgroundColor != null) {
Modifier.background(
color = TnTTheme.colors.neutralColors.Neutral900,
color = backgroundColor,
shape = RoundedCornerShape(8.dp),
)
} else {
Expand Down Expand Up @@ -154,6 +164,19 @@ private fun CalendarIndicator(
@Preview(showBackground = true)
@Composable
private fun CalendarCellPreview() {
TnTTheme {
CalendarCell(
date = LocalDate.now().minusDays(1),
state = DayState(
isSelected = false,
),
)
}
}

@Preview(showBackground = true)
@Composable
private fun CalendarTodayCellPreview() {
TnTTheme {
CalendarCell(
date = LocalDate.now(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fun TnTHomeTopBar(
onClickSelectorPrevious: () -> Unit = { },
onClickSelectorNext: () -> Unit = { },
onClickNotification: () -> Unit = { },
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
windowInsets: WindowInsets = WindowInsets(0.dp, 0.dp, 0.dp, 0.dp),
) {
Column {
CenterAlignedTopAppBar(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package co.kr.data.network.model.trainer

import co.kr.tnt.domain.model.trainer.DailyPtSessionCount
import co.kr.tnt.domain.utils.DateFormatter
import kotlinx.serialization.Serializable

@Serializable
data class MonthlyPtSessionCountsResponse(
val calendarPtLessonCounts: List<PtSessionCountsResponse>,
)

@Serializable
data class PtSessionCountsResponse(
val date: String,
val count: Int,
)

fun PtSessionCountsResponse.toDomain(dateFormatter: DateFormatter) =
DailyPtSessionCount(
date = dateFormatter.parse(date),
count = count,
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import co.kr.data.network.model.LoginRequest
import co.kr.data.network.model.LoginResponse
import co.kr.data.network.model.SignUpResponse
import co.kr.data.network.model.VerifyCodeResponse
import co.kr.data.network.model.trainer.MonthlyPtSessionCountsResponse
import co.kr.data.network.util.WithoutSessionCheckPath.CHECK_SESSION_PATH
import okhttp3.MultipartBody
import okhttp3.RequestBody
Expand Down Expand Up @@ -61,4 +62,10 @@ interface ApiService {
@Query("trainerId") trainerId: String,
@Query("traineeId") traineeId: String,
): ConnectedTraineeResponse

@GET("/trainers/lessons/calendar")
suspend fun getMonthlyPtSessionCounts(
@Query("year") year: Int,
@Query("month") month: Int,
): MonthlyPtSessionCountsResponse
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package co.kr.data.network.source

import co.kr.data.network.model.trainer.MonthlyPtSessionCountsResponse
import co.kr.data.network.service.ApiService
import co.kr.data.network.util.networkHandler
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class TrainerRemoteDataSource @Inject constructor(
private val apiService: ApiService,
) {
suspend fun getMonthlyPtSessionCounts(
year: Int,
month: Int,
): MonthlyPtSessionCountsResponse = networkHandler {
apiService.getMonthlyPtSessionCounts(
year = year,
month = month,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import co.kr.tnt.domain.model.ConnectedResult
import co.kr.tnt.domain.model.InviteCodeResult
import co.kr.tnt.domain.repository.ConnectRepository
import javax.inject.Inject
import javax.inject.Singleton

class ConnectRepositoryImpl @Inject constructor(
@Singleton
internal class ConnectRepositoryImpl @Inject constructor(
private val connectRemoteDataSource: ConnectRemoteDataSource,
) : ConnectRepository {
override suspend fun getInviteCode(): InviteCodeResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import javax.inject.Inject
import javax.inject.Singleton

class SignUpRepositoryImpl @Inject constructor(
@Singleton
internal class SignUpRepositoryImpl @Inject constructor(
private val signupRemoteDataSource: SignUpRemoteDataSource,
private val sessionLocalDataSource: SessionLocalDataSource,
private val json: Json,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package co.kr.data.repository

import co.kr.data.network.model.trainer.toDomain
import co.kr.data.network.source.TrainerRemoteDataSource
import co.kr.tnt.domain.model.trainer.DailyPtSessionCount
import co.kr.tnt.domain.repository.TrainerRepository
import co.kr.tnt.domain.utils.DateFormatter
import java.time.YearMonth
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
internal class TrainerRepositoryImpl @Inject constructor(
private val trainerRemoteDataSource: TrainerRemoteDataSource,
private val dateFormatter: DateFormatter,
) : TrainerRepository {
override suspend fun getMonthlyPtSessionCounts(yearMonth: YearMonth): List<DailyPtSessionCount> =
trainerRemoteDataSource.getMonthlyPtSessionCounts(
year = yearMonth.year,
month = yearMonth.monthValue,
).calendarPtLessonCounts.map { response ->
response.toDomain(dateFormatter)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ 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.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.TrainerRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand All @@ -28,4 +30,9 @@ internal abstract class RepositoryModule {
abstract fun bindConnectRepository(
repository: ConnectRepositoryImpl,
): ConnectRepository

@Binds
abstract fun bindTrainerRepository(
repository: TrainerRepositoryImpl,
): TrainerRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package co.kr.tnt.domain.model.trainer

import java.time.LocalDate

data class DailyPtSessionCount(
val date: LocalDate,
val count: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package co.kr.tnt.domain.repository

import co.kr.tnt.domain.model.trainer.DailyPtSessionCount
import java.time.YearMonth

interface TrainerRepository {
suspend fun getMonthlyPtSessionCounts(yearMonth: YearMonth): List<DailyPtSessionCount>
}
27 changes: 27 additions & 0 deletions domain/src/main/java/co/kr/tnt/domain/utils/DateFormatter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package co.kr.tnt.domain.utils

import java.time.LocalDate
import java.time.format.DateTimeFormatter
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class DateFormatter @Inject constructor() {
fun parse(
rawDate: String,
formatter: DateTimeFormatter = DEFAULT_DATE_FORMAT,
): LocalDate {
require(rawDate.isNotBlank())

return LocalDate.parse(rawDate, formatter)
}

fun format(
date: LocalDate,
formatter: DateTimeFormatter = DEFAULT_DATE_FORMAT,
): String = formatter.format(date)

companion object {
private val DEFAULT_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import java.time.YearMonth
internal class TrainerHomeContract {
data class TrainerHomeUiState(
val selectedDay: LocalDate = LocalDate.now(),
val dailyPtSessionCount: Map<LocalDate, Int> = mapOf(),
) : UiState

sealed interface TrainerHomeUiEvent : UiEvent {
Expand All @@ -19,5 +20,6 @@ internal class TrainerHomeContract {

sealed interface TrainerHomeSideEffect : UiSideEffect {
data object NavigateToNotification : TrainerHomeSideEffect
data class ShowToast(val message: String) : TrainerHomeSideEffect
}
}
Loading

0 comments on commit d3e67a9

Please sign in to comment.