diff --git a/app/src/main/java/com/threegap/bitnagil/di/data/DataSourceModule.kt b/app/src/main/java/com/threegap/bitnagil/di/data/DataSourceModule.kt index d23380b1..c702c824 100644 --- a/app/src/main/java/com/threegap/bitnagil/di/data/DataSourceModule.kt +++ b/app/src/main/java/com/threegap/bitnagil/di/data/DataSourceModule.kt @@ -12,6 +12,8 @@ import com.threegap.bitnagil.data.recommendroutine.datasource.RecommendRoutineDa import com.threegap.bitnagil.data.recommendroutine.datasourceImpl.RecommendRoutineDataSourceImpl import com.threegap.bitnagil.data.routine.datasource.RoutineRemoteDataSource import com.threegap.bitnagil.data.routine.datasourceImpl.RoutineRemoteDataSourceImpl +import com.threegap.bitnagil.data.user.datasource.UserDataSource +import com.threegap.bitnagil.data.user.datasourceImpl.UserDataSourceImpl import com.threegap.bitnagil.data.writeroutine.datasource.WriteRoutineDataSource import com.threegap.bitnagil.data.writeroutine.datasourceImpl.WriteRoutineDataSourceImpl import dagger.Binds @@ -48,6 +50,10 @@ abstract class DataSourceModule { @Singleton abstract fun bindWriteRoutineDataSource(writeRoutineDataSourceImpl: WriteRoutineDataSourceImpl): WriteRoutineDataSource + @Binds + @Singleton + abstract fun bindUserDataSource(userDataSourceImpl: UserDataSourceImpl): UserDataSource + @Binds @Singleton abstract fun bindRecommendRoutineDataSource(recommendRoutineDataSourceImpl: RecommendRoutineDataSourceImpl): RecommendRoutineDataSource diff --git a/app/src/main/java/com/threegap/bitnagil/di/data/RepositoryModule.kt b/app/src/main/java/com/threegap/bitnagil/di/data/RepositoryModule.kt index 10bc4e0e..073dd0e1 100644 --- a/app/src/main/java/com/threegap/bitnagil/di/data/RepositoryModule.kt +++ b/app/src/main/java/com/threegap/bitnagil/di/data/RepositoryModule.kt @@ -5,12 +5,14 @@ import com.threegap.bitnagil.data.emotion.repositoryImpl.EmotionRepositoryImpl import com.threegap.bitnagil.data.onboarding.repositoryImpl.OnBoardingRepositoryImpl import com.threegap.bitnagil.data.recommendroutine.repositoryImpl.RecommendRoutineRepositoryImpl import com.threegap.bitnagil.data.routine.repositoryImpl.RoutineRepositoryImpl +import com.threegap.bitnagil.data.user.repositoryImpl.UserRepositoryImpl import com.threegap.bitnagil.data.writeroutine.repositoryImpl.WriteRoutineRepositoryImpl import com.threegap.bitnagil.domain.auth.repository.AuthRepository import com.threegap.bitnagil.domain.emotion.repository.EmotionRepository import com.threegap.bitnagil.domain.onboarding.repository.OnBoardingRepository import com.threegap.bitnagil.domain.recommendroutine.repository.RecommendRoutineRepository import com.threegap.bitnagil.domain.routine.repository.RoutineRepository +import com.threegap.bitnagil.domain.user.repository.UserRepository import com.threegap.bitnagil.domain.writeroutine.repository.WriteRoutineRepository import dagger.Binds import dagger.Module @@ -42,6 +44,10 @@ abstract class RepositoryModule { @Singleton abstract fun bindWriteRoutineRepository(writeRoutineRepositoryImpl: WriteRoutineRepositoryImpl): WriteRoutineRepository + @Binds + @Singleton + abstract fun bindUserRepository(userRepositoryImpl: UserRepositoryImpl): UserRepository + @Binds @Singleton abstract fun bindRecommendRoutineRepository(recommendRoutineRepositoryImpl: RecommendRoutineRepositoryImpl): RecommendRoutineRepository diff --git a/app/src/main/java/com/threegap/bitnagil/di/data/ServiceModule.kt b/app/src/main/java/com/threegap/bitnagil/di/data/ServiceModule.kt index dcb68f9c..a5d8bbe1 100644 --- a/app/src/main/java/com/threegap/bitnagil/di/data/ServiceModule.kt +++ b/app/src/main/java/com/threegap/bitnagil/di/data/ServiceModule.kt @@ -5,6 +5,7 @@ import com.threegap.bitnagil.data.emotion.service.EmotionService import com.threegap.bitnagil.data.onboarding.service.OnBoardingService import com.threegap.bitnagil.data.recommendroutine.service.RecommendRoutineService import com.threegap.bitnagil.data.routine.service.RoutineService +import com.threegap.bitnagil.data.user.service.UserService import com.threegap.bitnagil.data.writeroutine.service.WriteRoutineService import com.threegap.bitnagil.di.core.Auth import com.threegap.bitnagil.di.core.NoneAuth @@ -50,6 +51,11 @@ object ServiceModule { fun provideReissueService(@NoneAuth retrofit: Retrofit): ReissueService = retrofit.create(ReissueService::class.java) + @Provides + @Singleton + fun provideUserService(@Auth retrofit: Retrofit): UserService = + retrofit.create(UserService::class.java) + @Provides @Singleton fun provideRecommendRoutineService(@Auth retrofit: Retrofit): RecommendRoutineService = diff --git a/core/network/src/main/java/com/threegap/bitnagil/network/model/AuthToken.kt b/core/network/src/main/java/com/threegap/bitnagil/network/model/AuthToken.kt index 4cb68dae..33afb790 100644 --- a/core/network/src/main/java/com/threegap/bitnagil/network/model/AuthToken.kt +++ b/core/network/src/main/java/com/threegap/bitnagil/network/model/AuthToken.kt @@ -9,6 +9,4 @@ data class AuthToken( val accessToken: String, @SerialName("refreshToken") val refreshToken: String, - @SerialName("role") // todo: 제거 예정 - val role: String, ) diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/datasource/EmotionDataSource.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/datasource/EmotionDataSource.kt index 4129c2b6..1267dd6a 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/emotion/datasource/EmotionDataSource.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/datasource/EmotionDataSource.kt @@ -1,9 +1,11 @@ package com.threegap.bitnagil.data.emotion.datasource import com.threegap.bitnagil.data.emotion.model.response.GetEmotionsResponse +import com.threegap.bitnagil.data.emotion.model.response.MyEmotionResponseDto import com.threegap.bitnagil.data.emotion.model.response.RegisterEmotionResponse interface EmotionDataSource { suspend fun getEmotions(): Result suspend fun registerEmotion(emotion: String): Result + suspend fun getMyEmotionMarble(currentDate: String): Result } diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/datasourceImpl/EmotionDataSourceImpl.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/datasourceImpl/EmotionDataSourceImpl.kt index 0337c003..674c25ea 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/emotion/datasourceImpl/EmotionDataSourceImpl.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/datasourceImpl/EmotionDataSourceImpl.kt @@ -4,6 +4,7 @@ import com.threegap.bitnagil.data.common.safeApiCall import com.threegap.bitnagil.data.emotion.datasource.EmotionDataSource import com.threegap.bitnagil.data.emotion.model.request.RegisterEmotionRequest import com.threegap.bitnagil.data.emotion.model.response.GetEmotionsResponse +import com.threegap.bitnagil.data.emotion.model.response.MyEmotionResponseDto import com.threegap.bitnagil.data.emotion.model.response.RegisterEmotionResponse import com.threegap.bitnagil.data.emotion.service.EmotionService import javax.inject.Inject @@ -23,4 +24,9 @@ class EmotionDataSourceImpl @Inject constructor( emotionService.postEmotions(registerEmotionRequest) } } + + override suspend fun getMyEmotionMarble(currentDate: String): Result = + safeApiCall { + emotionService.getMyEmotionMarble(currentDate) + } } diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/model/response/MyEmotionResponseDto.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/model/response/MyEmotionResponseDto.kt new file mode 100644 index 00000000..77243076 --- /dev/null +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/model/response/MyEmotionResponseDto.kt @@ -0,0 +1,23 @@ +package com.threegap.bitnagil.data.emotion.model.response + +import com.threegap.bitnagil.domain.emotion.model.Emotion +import com.threegap.bitnagil.domain.emotion.model.MyEmotion +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class MyEmotionResponseDto( + @SerialName("emotionMarbleType") + val emotionMarbleType: String?, + @SerialName("emotionMarbleName") + val emotionMarbleName: String?, + @SerialName("imageUrl") + val imageUrl: String?, +) + +fun MyEmotionResponseDto.toDomain(): MyEmotion = + MyEmotion( + emotionMarbleType = emotionMarbleType?.let { Emotion.valueOf(it) }, + emotionMarbleName = emotionMarbleName, + imageUrl = imageUrl, + ) diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt index 1c27ee61..740a6274 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt @@ -1,7 +1,9 @@ package com.threegap.bitnagil.data.emotion.repositoryImpl import com.threegap.bitnagil.data.emotion.datasource.EmotionDataSource +import com.threegap.bitnagil.data.emotion.model.response.toDomain import com.threegap.bitnagil.domain.emotion.model.Emotion +import com.threegap.bitnagil.domain.emotion.model.MyEmotion import com.threegap.bitnagil.domain.emotion.repository.EmotionRepository import javax.inject.Inject @@ -36,4 +38,7 @@ class EmotionRepositoryImpl @Inject constructor( return emotionDataSource.registerEmotion(selectedEmotion).map { _ -> } } + + override suspend fun getMyEmotionMarble(currentDate: String): Result = + emotionDataSource.getMyEmotionMarble(currentDate).map { it.toDomain() } } diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/service/EmotionService.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/service/EmotionService.kt index 61b18264..82eb3dcb 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/emotion/service/EmotionService.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/service/EmotionService.kt @@ -2,11 +2,13 @@ package com.threegap.bitnagil.data.emotion.service import com.threegap.bitnagil.data.emotion.model.request.RegisterEmotionRequest import com.threegap.bitnagil.data.emotion.model.response.GetEmotionsResponse +import com.threegap.bitnagil.data.emotion.model.response.MyEmotionResponseDto import com.threegap.bitnagil.data.emotion.model.response.RegisterEmotionResponse import com.threegap.bitnagil.network.model.BaseResponse import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST +import retrofit2.http.Query interface EmotionService { @GET("/api/v1/emotion-marbles") @@ -16,4 +18,9 @@ interface EmotionService { suspend fun postEmotions( @Body request: RegisterEmotionRequest, ): BaseResponse + + @GET("/api/v1/emotion-marbles/me") + suspend fun getMyEmotionMarble( + @Query("searchDate") date: String, + ): BaseResponse } diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/datasource/RoutineRemoteDataSource.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/datasource/RoutineRemoteDataSource.kt index f21e8b93..daaae4f0 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/routine/datasource/RoutineRemoteDataSource.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/datasource/RoutineRemoteDataSource.kt @@ -1,5 +1,6 @@ package com.threegap.bitnagil.data.routine.datasource +import com.threegap.bitnagil.data.routine.model.request.RoutineByDayDeletionRequestDto import com.threegap.bitnagil.data.routine.model.request.RoutineCompletionRequestDto import com.threegap.bitnagil.data.routine.model.response.RoutinesResponseDto @@ -7,4 +8,5 @@ interface RoutineRemoteDataSource { suspend fun fetchWeeklyRoutines(startDate: String, endDate: String): Result suspend fun syncRoutineCompletion(routineCompletionRequestDto: RoutineCompletionRequestDto): Result suspend fun deleteRoutine(routineId: String): Result + suspend fun deleteRoutineByDay(routineByDayDeletionRequestDto: RoutineByDayDeletionRequestDto): Result } diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/datasourceImpl/RoutineRemoteDataSourceImpl.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/datasourceImpl/RoutineRemoteDataSourceImpl.kt index 02340651..9e263f27 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/routine/datasourceImpl/RoutineRemoteDataSourceImpl.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/datasourceImpl/RoutineRemoteDataSourceImpl.kt @@ -3,6 +3,7 @@ package com.threegap.bitnagil.data.routine.datasourceImpl import com.threegap.bitnagil.data.common.safeApiCall import com.threegap.bitnagil.data.common.safeUnitApiCall import com.threegap.bitnagil.data.routine.datasource.RoutineRemoteDataSource +import com.threegap.bitnagil.data.routine.model.request.RoutineByDayDeletionRequestDto import com.threegap.bitnagil.data.routine.model.request.RoutineCompletionRequestDto import com.threegap.bitnagil.data.routine.model.response.RoutinesResponseDto import com.threegap.bitnagil.data.routine.service.RoutineService @@ -25,4 +26,9 @@ class RoutineRemoteDataSourceImpl @Inject constructor( safeUnitApiCall { routineService.deleteRoutine(routineId) } + + override suspend fun deleteRoutineByDay(routineByDayDeletionRequestDto: RoutineByDayDeletionRequestDto): Result = + safeUnitApiCall { + routineService.deleteRoutineByDay(routineByDayDeletionRequestDto) + } } diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/mapper/RoutineMapper.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/mapper/RoutineMapper.kt index 593cb6ec..be747e8e 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/routine/mapper/RoutineMapper.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/mapper/RoutineMapper.kt @@ -29,6 +29,7 @@ internal fun RoutineDto.toDomain() = executionTime = this.executionTime, subRoutines = this.subRoutines.map { it.toDomain() }, isModified = this.isModified, + routineCompletionId = this.routineCompletionId, isCompleted = this.isCompleted, repeatDay = this.repeatDay.map { DayOfWeek.fromString(it) }, routineType = RoutineType.fromString(this.routineType), @@ -41,6 +42,7 @@ internal fun SubRoutineDto.toDomain() = subRoutineName = this.subRoutineName, isModified = this.isModified, sortOrder = this.sortOrder, + routineCompletionId = this.routineCompletionId, isCompleted = this.isCompleted, routineType = RoutineType.fromString(this.routineType), ) diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/model/request/RoutineByDayDeletionRequestDto.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/model/request/RoutineByDayDeletionRequestDto.kt new file mode 100644 index 00000000..b4ce96d2 --- /dev/null +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/model/request/RoutineByDayDeletionRequestDto.kt @@ -0,0 +1,28 @@ +package com.threegap.bitnagil.data.routine.model.request + +import com.threegap.bitnagil.domain.routine.model.RoutineByDayDeletion +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class RoutineByDayDeletionRequestDto( + @SerialName("routineCompletionId") + val routineCompletionId: Int?, + @SerialName("routineId") + val routineId: String, + @SerialName("subRoutineInfosForDelete") + val subRoutineInfosForDelete: List, + @SerialName("performedDate") + val performedDate: String, + @SerialName("historySeq") + val historySeq: Int, +) + +fun RoutineByDayDeletion.toDto() = + RoutineByDayDeletionRequestDto( + routineCompletionId = this.routineCompletionId, + routineId = this.routineId, + subRoutineInfosForDelete = this.subRoutineInfosForDelete.map { it.toDto() }, + performedDate = this.performedDate, + historySeq = this.historySeq, + ) diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/model/request/SubRoutineDeletionInfoDto.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/model/request/SubRoutineDeletionInfoDto.kt new file mode 100644 index 00000000..f10463ec --- /dev/null +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/model/request/SubRoutineDeletionInfoDto.kt @@ -0,0 +1,19 @@ +package com.threegap.bitnagil.data.routine.model.request + +import com.threegap.bitnagil.domain.routine.model.SubRoutineDeletionInfo +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class SubRoutineDeletionInfoDto( + @SerialName("routineCompletionId") + val routineCompletionId: Int?, + @SerialName("subRoutineId") + val subRoutineId: String, +) + +fun SubRoutineDeletionInfo.toDto() = + SubRoutineDeletionInfoDto( + routineCompletionId = this.routineCompletionId, + subRoutineId = this.subRoutineId, + ) diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/model/response/RoutineDto.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/model/response/RoutineDto.kt index f4ccc2ae..5b93cfff 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/routine/model/response/RoutineDto.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/model/response/RoutineDto.kt @@ -19,6 +19,8 @@ data class RoutineDto( val subRoutines: List, @SerialName("modifiedYn") val isModified: Boolean, + @SerialName("routineCompletionId") + val routineCompletionId: Int?, @SerialName("completeYn") val isCompleted: Boolean, @SerialName("routineType") diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/model/response/SubRoutineDto.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/model/response/SubRoutineDto.kt index 61f79d73..ba573a9b 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/routine/model/response/SubRoutineDto.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/model/response/SubRoutineDto.kt @@ -15,6 +15,8 @@ data class SubRoutineDto( val isModified: Boolean, @SerialName("sortOrder") val sortOrder: Int, + @SerialName("routineCompletionId") + val routineCompletionId: Int?, @SerialName("completeYn") val isCompleted: Boolean, @SerialName("routineType") diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/repositoryImpl/RoutineRepositoryImpl.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/repositoryImpl/RoutineRepositoryImpl.kt index 81f7f23c..d38e89c5 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/routine/repositoryImpl/RoutineRepositoryImpl.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/repositoryImpl/RoutineRepositoryImpl.kt @@ -3,6 +3,8 @@ package com.threegap.bitnagil.data.routine.repositoryImpl import com.threegap.bitnagil.data.routine.datasource.RoutineRemoteDataSource import com.threegap.bitnagil.data.routine.mapper.toDomain import com.threegap.bitnagil.data.routine.mapper.toDto +import com.threegap.bitnagil.data.routine.model.request.toDto +import com.threegap.bitnagil.domain.routine.model.RoutineByDayDeletion import com.threegap.bitnagil.domain.routine.model.RoutineCompletion import com.threegap.bitnagil.domain.routine.model.Routines import com.threegap.bitnagil.domain.routine.repository.RoutineRepository @@ -20,4 +22,7 @@ class RoutineRepositoryImpl @Inject constructor( override suspend fun deleteRoutine(routineId: String): Result = routineRemoteDataSource.deleteRoutine(routineId) + + override suspend fun deleteRoutineByDay(routineByDayDeletion: RoutineByDayDeletion): Result = + routineRemoteDataSource.deleteRoutineByDay(routineByDayDeletion.toDto()) } diff --git a/data/src/main/java/com/threegap/bitnagil/data/routine/service/RoutineService.kt b/data/src/main/java/com/threegap/bitnagil/data/routine/service/RoutineService.kt index 122e36bc..9d567e93 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/routine/service/RoutineService.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/routine/service/RoutineService.kt @@ -1,11 +1,13 @@ package com.threegap.bitnagil.data.routine.service +import com.threegap.bitnagil.data.routine.model.request.RoutineByDayDeletionRequestDto import com.threegap.bitnagil.data.routine.model.request.RoutineCompletionRequestDto import com.threegap.bitnagil.data.routine.model.response.RoutinesResponseDto import com.threegap.bitnagil.network.model.BaseResponse import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.GET +import retrofit2.http.HTTP import retrofit2.http.POST import retrofit2.http.Path import retrofit2.http.Query @@ -26,4 +28,9 @@ interface RoutineService { suspend fun deleteRoutine( @Path("routineId") routineId: String, ): BaseResponse + + @HTTP(method = "DELETE", path = "/api/v1/routines/day", hasBody = true) + suspend fun deleteRoutineByDay( + @Body request: RoutineByDayDeletionRequestDto, + ): BaseResponse } diff --git a/data/src/main/java/com/threegap/bitnagil/data/user/datasource/UserDataSource.kt b/data/src/main/java/com/threegap/bitnagil/data/user/datasource/UserDataSource.kt new file mode 100644 index 00000000..55cac914 --- /dev/null +++ b/data/src/main/java/com/threegap/bitnagil/data/user/datasource/UserDataSource.kt @@ -0,0 +1,7 @@ +package com.threegap.bitnagil.data.user.datasource + +import com.threegap.bitnagil.data.user.model.response.UserProfileResponseDto + +interface UserDataSource { + suspend fun fetchUserProfile(): Result +} diff --git a/data/src/main/java/com/threegap/bitnagil/data/user/datasourceImpl/UserDataSourceImpl.kt b/data/src/main/java/com/threegap/bitnagil/data/user/datasourceImpl/UserDataSourceImpl.kt new file mode 100644 index 00000000..dbde8d74 --- /dev/null +++ b/data/src/main/java/com/threegap/bitnagil/data/user/datasourceImpl/UserDataSourceImpl.kt @@ -0,0 +1,16 @@ +package com.threegap.bitnagil.data.user.datasourceImpl + +import com.threegap.bitnagil.data.common.safeApiCall +import com.threegap.bitnagil.data.user.datasource.UserDataSource +import com.threegap.bitnagil.data.user.model.response.UserProfileResponseDto +import com.threegap.bitnagil.data.user.service.UserService +import javax.inject.Inject + +class UserDataSourceImpl @Inject constructor( + private val userService: UserService, +) : UserDataSource { + override suspend fun fetchUserProfile(): Result = + safeApiCall { + userService.fetchUserProfile() + } +} diff --git a/data/src/main/java/com/threegap/bitnagil/data/user/model/response/UserProfileResponseDto.kt b/data/src/main/java/com/threegap/bitnagil/data/user/model/response/UserProfileResponseDto.kt new file mode 100644 index 00000000..5f3749d2 --- /dev/null +++ b/data/src/main/java/com/threegap/bitnagil/data/user/model/response/UserProfileResponseDto.kt @@ -0,0 +1,16 @@ +package com.threegap.bitnagil.data.user.model.response + +import com.threegap.bitnagil.domain.user.model.UserProfile +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class UserProfileResponseDto( + @SerialName("nickname") + val nickname: String, +) + +fun UserProfileResponseDto.toDomain() = + UserProfile( + nickname = this.nickname, + ) diff --git a/data/src/main/java/com/threegap/bitnagil/data/user/repositoryImpl/UserRepositoryImpl.kt b/data/src/main/java/com/threegap/bitnagil/data/user/repositoryImpl/UserRepositoryImpl.kt new file mode 100644 index 00000000..e0506f24 --- /dev/null +++ b/data/src/main/java/com/threegap/bitnagil/data/user/repositoryImpl/UserRepositoryImpl.kt @@ -0,0 +1,14 @@ +package com.threegap.bitnagil.data.user.repositoryImpl + +import com.threegap.bitnagil.data.user.datasource.UserDataSource +import com.threegap.bitnagil.data.user.model.response.toDomain +import com.threegap.bitnagil.domain.user.model.UserProfile +import com.threegap.bitnagil.domain.user.repository.UserRepository +import javax.inject.Inject + +class UserRepositoryImpl @Inject constructor( + private val userDataSource: UserDataSource, +) : UserRepository { + override suspend fun fetchUserProfile(): Result = + userDataSource.fetchUserProfile().map { it.toDomain() } +} diff --git a/data/src/main/java/com/threegap/bitnagil/data/user/service/UserService.kt b/data/src/main/java/com/threegap/bitnagil/data/user/service/UserService.kt new file mode 100644 index 00000000..76b4823e --- /dev/null +++ b/data/src/main/java/com/threegap/bitnagil/data/user/service/UserService.kt @@ -0,0 +1,10 @@ +package com.threegap.bitnagil.data.user.service + +import com.threegap.bitnagil.data.user.model.response.UserProfileResponseDto +import com.threegap.bitnagil.network.model.BaseResponse +import retrofit2.http.GET + +interface UserService { + @GET("/api/v1/users/nickname") + suspend fun fetchUserProfile(): BaseResponse +} diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/model/MyEmotion.kt b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/model/MyEmotion.kt new file mode 100644 index 00000000..36e226a9 --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/model/MyEmotion.kt @@ -0,0 +1,7 @@ +package com.threegap.bitnagil.domain.emotion.model + +data class MyEmotion( + val emotionMarbleType: Emotion?, + val emotionMarbleName: String?, + val imageUrl: String?, +) diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/repository/EmotionRepository.kt b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/repository/EmotionRepository.kt index 5935aab9..a47ca36b 100644 --- a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/repository/EmotionRepository.kt +++ b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/repository/EmotionRepository.kt @@ -1,8 +1,10 @@ package com.threegap.bitnagil.domain.emotion.repository import com.threegap.bitnagil.domain.emotion.model.Emotion +import com.threegap.bitnagil.domain.emotion.model.MyEmotion interface EmotionRepository { suspend fun getEmotions(): Result> suspend fun registerEmotion(emotion: Emotion): Result + suspend fun getMyEmotionMarble(currentDate: String): Result } diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/usecase/GetMyEmotionUseCase.kt b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/usecase/GetMyEmotionUseCase.kt new file mode 100644 index 00000000..a72157c9 --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/usecase/GetMyEmotionUseCase.kt @@ -0,0 +1,12 @@ +package com.threegap.bitnagil.domain.emotion.usecase + +import com.threegap.bitnagil.domain.emotion.model.MyEmotion +import com.threegap.bitnagil.domain.emotion.repository.EmotionRepository +import javax.inject.Inject + +class GetMyEmotionUseCase @Inject constructor( + private val emotionRepository: EmotionRepository, +) { + suspend operator fun invoke(currentDate: String): Result = + emotionRepository.getMyEmotionMarble(currentDate) +} diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/Routine.kt b/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/Routine.kt index ed64aaa2..808ba180 100644 --- a/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/Routine.kt +++ b/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/Routine.kt @@ -8,6 +8,7 @@ data class Routine( val executionTime: String, val subRoutines: List, val isModified: Boolean, + val routineCompletionId: Int?, val isCompleted: Boolean, val routineType: RoutineType, ) { diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/RoutineByDayDeletion.kt b/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/RoutineByDayDeletion.kt new file mode 100644 index 00000000..a5b7c7cb --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/RoutineByDayDeletion.kt @@ -0,0 +1,9 @@ +package com.threegap.bitnagil.domain.routine.model + +data class RoutineByDayDeletion( + val routineCompletionId: Int?, + val routineId: String, + val subRoutineInfosForDelete: List, + val performedDate: String, + val historySeq: Int, +) diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/SubRoutine.kt b/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/SubRoutine.kt index 03dd8b9d..3101b38c 100644 --- a/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/SubRoutine.kt +++ b/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/SubRoutine.kt @@ -6,6 +6,7 @@ data class SubRoutine( val subRoutineName: String, val isModified: Boolean, val sortOrder: Int, + val routineCompletionId: Int?, val isCompleted: Boolean, val routineType: RoutineType, ) diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/SubRoutineDeletionInfo.kt b/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/SubRoutineDeletionInfo.kt new file mode 100644 index 00000000..24289e58 --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/routine/model/SubRoutineDeletionInfo.kt @@ -0,0 +1,6 @@ +package com.threegap.bitnagil.domain.routine.model + +data class SubRoutineDeletionInfo( + val routineCompletionId: Int?, + val subRoutineId: String, +) diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/routine/repository/RoutineRepository.kt b/domain/src/main/java/com/threegap/bitnagil/domain/routine/repository/RoutineRepository.kt index dfb917bb..8cb09cfc 100644 --- a/domain/src/main/java/com/threegap/bitnagil/domain/routine/repository/RoutineRepository.kt +++ b/domain/src/main/java/com/threegap/bitnagil/domain/routine/repository/RoutineRepository.kt @@ -1,5 +1,6 @@ package com.threegap.bitnagil.domain.routine.repository +import com.threegap.bitnagil.domain.routine.model.RoutineByDayDeletion import com.threegap.bitnagil.domain.routine.model.RoutineCompletion import com.threegap.bitnagil.domain.routine.model.Routines @@ -7,4 +8,5 @@ interface RoutineRepository { suspend fun fetchWeeklyRoutines(startDate: String, endDate: String): Result suspend fun syncRoutineCompletion(routineCompletion: RoutineCompletion): Result suspend fun deleteRoutine(routineId: String): Result + suspend fun deleteRoutineByDay(routineByDayDeletion: RoutineByDayDeletion): Result } diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/routine/usecase/DeleteRoutineByDayUseCase.kt b/domain/src/main/java/com/threegap/bitnagil/domain/routine/usecase/DeleteRoutineByDayUseCase.kt new file mode 100644 index 00000000..01df72f1 --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/routine/usecase/DeleteRoutineByDayUseCase.kt @@ -0,0 +1,12 @@ +package com.threegap.bitnagil.domain.routine.usecase + +import com.threegap.bitnagil.domain.routine.model.RoutineByDayDeletion +import com.threegap.bitnagil.domain.routine.repository.RoutineRepository +import javax.inject.Inject + +class DeleteRoutineByDayUseCase @Inject constructor( + private val routineRepository: RoutineRepository, +) { + suspend operator fun invoke(routineByDayDeletion: RoutineByDayDeletion) = + routineRepository.deleteRoutineByDay(routineByDayDeletion) +} diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/user/model/UserProfile.kt b/domain/src/main/java/com/threegap/bitnagil/domain/user/model/UserProfile.kt new file mode 100644 index 00000000..b02eadb6 --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/user/model/UserProfile.kt @@ -0,0 +1,5 @@ +package com.threegap.bitnagil.domain.user.model + +data class UserProfile( + val nickname: String, +) diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/user/repository/UserRepository.kt b/domain/src/main/java/com/threegap/bitnagil/domain/user/repository/UserRepository.kt new file mode 100644 index 00000000..de352843 --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/user/repository/UserRepository.kt @@ -0,0 +1,7 @@ +package com.threegap.bitnagil.domain.user.repository + +import com.threegap.bitnagil.domain.user.model.UserProfile + +interface UserRepository { + suspend fun fetchUserProfile(): Result +} diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/user/usecase/FetchUserProfileUseCase.kt b/domain/src/main/java/com/threegap/bitnagil/domain/user/usecase/FetchUserProfileUseCase.kt new file mode 100644 index 00000000..baee4a20 --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/user/usecase/FetchUserProfileUseCase.kt @@ -0,0 +1,12 @@ +package com.threegap.bitnagil.domain.user.usecase + +import com.threegap.bitnagil.domain.user.model.UserProfile +import com.threegap.bitnagil.domain.user.repository.UserRepository +import javax.inject.Inject + +class FetchUserProfileUseCase @Inject constructor( + private val userRepository: UserRepository, +) { + suspend operator fun invoke(): Result = + userRepository.fetchUserProfile() +} diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/HomeScreen.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/HomeScreen.kt index a6630a0a..5e574b19 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/HomeScreen.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/HomeScreen.kt @@ -81,6 +81,7 @@ fun HomeScreenContainer( if (uiState.showDeleteConfirmDialog) { DeleteConfirmDialog( onDeleteToday = { + viewModel.deleteRoutineByDay(routine) viewModel.sendIntent(HomeIntent.HideDeleteConfirmDialog) }, onDeleteAll = { @@ -239,7 +240,8 @@ private fun HomeScreen( } CollapsibleHomeHeader( - userName = "대현", + userName = uiState.userNickname, + emotionBallType = uiState.myEmotion, collapsibleHeaderState = collapsibleHeaderState, onEmotionRecordClick = onRegisterEmotionClick, ) diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/HomeViewModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/HomeViewModel.kt index 05c1384f..ee88201d 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/HomeViewModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/HomeViewModel.kt @@ -3,18 +3,23 @@ package com.threegap.bitnagil.presentation.home import android.util.Log import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope +import com.threegap.bitnagil.domain.emotion.usecase.GetMyEmotionUseCase import com.threegap.bitnagil.domain.routine.model.RoutineCompletion import com.threegap.bitnagil.domain.routine.model.RoutineCompletionInfo +import com.threegap.bitnagil.domain.routine.usecase.DeleteRoutineByDayUseCase import com.threegap.bitnagil.domain.routine.usecase.DeleteRoutineUseCase import com.threegap.bitnagil.domain.routine.usecase.FetchWeeklyRoutinesUseCase import com.threegap.bitnagil.domain.routine.usecase.RoutineCompletionUseCase +import com.threegap.bitnagil.domain.user.usecase.FetchUserProfileUseCase import com.threegap.bitnagil.presentation.common.mviviewmodel.MviViewModel +import com.threegap.bitnagil.presentation.home.model.EmotionBallType import com.threegap.bitnagil.presentation.home.model.HomeIntent import com.threegap.bitnagil.presentation.home.model.HomeSideEffect import com.threegap.bitnagil.presentation.home.model.HomeState import com.threegap.bitnagil.presentation.home.model.RoutineSortType import com.threegap.bitnagil.presentation.home.model.RoutineUiModel import com.threegap.bitnagil.presentation.home.model.RoutinesUiModel +import com.threegap.bitnagil.presentation.home.model.toRoutineByDayDeletion import com.threegap.bitnagil.presentation.home.model.toUiModel import com.threegap.bitnagil.presentation.home.util.getCurrentWeekDays import dagger.hilt.android.lifecycle.HiltViewModel @@ -33,8 +38,11 @@ import javax.inject.Inject class HomeViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val fetchWeeklyRoutinesUseCase: FetchWeeklyRoutinesUseCase, + private val fetchUserProfileUseCase: FetchUserProfileUseCase, + private val getMyEmotionUseCase: GetMyEmotionUseCase, private val routineCompletionUseCase: RoutineCompletionUseCase, private val deleteRoutineUseCase: DeleteRoutineUseCase, + private val deleteRoutineByDayUseCase: DeleteRoutineByDayUseCase, ) : MviViewModel( initState = HomeState(), savedStateHandle = savedStateHandle, @@ -47,6 +55,8 @@ class HomeViewModel @Inject constructor( observeWeekChanges() observeRoutineUpdates() fetchWeeklyRoutines(container.stateFlow.value.currentWeeks) + fetchUserProfile() + getMyEmotion(container.stateFlow.value.selectedDate) } override suspend fun SimpleSyntax.reduceState( @@ -58,6 +68,10 @@ class HomeViewModel @Inject constructor( state.copy(isLoading = intent.isLoading) } + is HomeIntent.LoadUserProfile -> { + state.copy(userNickname = intent.nickname) + } + is HomeIntent.LoadWeeklyRoutines -> { state.copy(routines = intent.routines) } @@ -110,6 +124,8 @@ class HomeViewModel @Inject constructor( routines = RoutinesUiModel(routinesByDate = updatedRoutinesByDate), showDeleteConfirmDialog = false, deletingRoutine = null, + routineDetailsBottomSheetVisible = false, + selectedRoutine = null, ) } @@ -154,6 +170,36 @@ class HomeViewModel @Inject constructor( deletingRoutine = null, ) } + + is HomeIntent.DeleteRoutineByDayOptimistically -> { + val dateKey = intent.performedDate + val updatedRoutinesByDate = state.routines.routinesByDate.toMutableMap() + val routinesForDate = updatedRoutinesByDate[dateKey]?.toMutableList() + + if (routinesForDate != null) { + updatedRoutinesByDate[dateKey] = routinesForDate.filterNot { + it.routineId == intent.routineId + } + } + + state.copy( + routines = RoutinesUiModel(routinesByDate = updatedRoutinesByDate), + showDeleteConfirmDialog = false, + deletingRoutine = null, + routineDetailsBottomSheetVisible = false, + selectedRoutine = null, + ) + } + + is HomeIntent.RestoreRoutinesAfterDeleteByDayFailure -> { + state.copy(routines = intent.backupRoutines) + } + + is HomeIntent.ConfirmRoutineByDayDeletion -> null + + is HomeIntent.LoadMyEmotion -> { + state.copy(myEmotion = intent.emotion) + } } return newState } @@ -183,6 +229,22 @@ class HomeViewModel @Inject constructor( } } + private fun fetchUserProfile() { + sendIntent(HomeIntent.UpdateLoading(true)) + viewModelScope.launch { + fetchUserProfileUseCase().fold( + onSuccess = { + sendIntent(HomeIntent.LoadUserProfile(it.nickname)) + sendIntent(HomeIntent.UpdateLoading(false)) + }, + onFailure = { error -> + Log.e("HomeViewModel", "유저 정보 가져오기 실패: ${error.message}") + sendIntent(HomeIntent.UpdateLoading(false)) + }, + ) + } + } + private fun fetchWeeklyRoutines(currentWeeks: List) { sendIntent(HomeIntent.UpdateLoading(true)) val startDate = currentWeeks.first().toString() @@ -202,6 +264,23 @@ class HomeViewModel @Inject constructor( } } + private fun getMyEmotion(currentDate: LocalDate) { + sendIntent(HomeIntent.UpdateLoading(true)) + viewModelScope.launch { + getMyEmotionUseCase(currentDate.toString()).fold( + onSuccess = { emotion -> + val ballType = EmotionBallType.fromDomainEmotion(emotion.emotionMarbleType) + sendIntent(HomeIntent.LoadMyEmotion(ballType)) + sendIntent(HomeIntent.UpdateLoading(false)) + }, + onFailure = { error -> + Log.e("HomeViewModel", "나의 감정 실패: ${error.message}") + sendIntent(HomeIntent.UpdateLoading(false)) + }, + ) + } + } + fun toggleRoutineCompletion(routineId: String, isCompleted: Boolean) { val originalState = container.stateFlow.value sendIntent(HomeIntent.OnRoutineCompletionToggle(routineId, isCompleted)) @@ -395,4 +474,35 @@ class HomeViewModel @Inject constructor( ) } } + + fun deleteRoutineByDay(routineUiModel: RoutineUiModel) { + val currentRoutines = container.stateFlow.value.routines + val performedDate = container.stateFlow.value.selectedDate.toString() + + sendIntent( + HomeIntent.DeleteRoutineByDayOptimistically( + routineId = routineUiModel.routineId, + performedDate = performedDate, + ), + ) + + viewModelScope.launch { + val routineByDayDeletion = routineUiModel.toRoutineByDayDeletion(performedDate) + + deleteRoutineByDayUseCase(routineByDayDeletion).fold( + onSuccess = { + sendIntent( + HomeIntent.ConfirmRoutineByDayDeletion( + routineId = routineUiModel.routineId, + performedDate = performedDate, + ), + ) + }, + onFailure = { + Log.e("HomeViewModel", "루틴 삭제 실패: ${it.message}") + sendIntent(HomeIntent.RestoreRoutinesAfterDeleteByDayFailure(currentRoutines)) + }, + ) + } + } } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/block/RoutineItem.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/block/RoutineItem.kt index d1b90329..7fa94129 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/block/RoutineItem.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/block/RoutineItem.kt @@ -78,6 +78,7 @@ private fun RoutineItemPreview() { routineName = "개운하게 일어나기", executionTime = "20:30:00", isCompleted = false, + routineCompletionId = 1, isModified = false, subRoutines = listOf( SubRoutineUiModel( @@ -85,6 +86,7 @@ private fun RoutineItemPreview() { historySeq = 1, subRoutineName = "물 마시기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -94,6 +96,7 @@ private fun RoutineItemPreview() { historySeq = 1, subRoutineName = "스트레칭하기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -103,6 +106,7 @@ private fun RoutineItemPreview() { historySeq = 1, subRoutineName = "심호흡하기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/block/SubRoutinesItem.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/block/SubRoutinesItem.kt index 64e96c3e..5f787836 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/block/SubRoutinesItem.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/block/SubRoutinesItem.kt @@ -86,6 +86,7 @@ private fun SubRoutinesItemPreview() { historySeq = 1, subRoutineName = "물 마시기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -95,6 +96,7 @@ private fun SubRoutinesItemPreview() { historySeq = 1, subRoutineName = "스트레칭하기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -104,6 +106,7 @@ private fun SubRoutinesItemPreview() { historySeq = 1, subRoutineName = "심호흡하기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/CollapsibleHomeHeader.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/CollapsibleHomeHeader.kt index 207ec100..e0e741ab 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/CollapsibleHomeHeader.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/CollapsibleHomeHeader.kt @@ -26,12 +26,14 @@ import com.threegap.bitnagil.designsystem.component.atom.BitnagilIcon import com.threegap.bitnagil.designsystem.modifier.clickableWithoutRipple import com.threegap.bitnagil.presentation.home.component.atom.EmotionBall import com.threegap.bitnagil.presentation.home.component.block.SpeechBubbleTooltip +import com.threegap.bitnagil.presentation.home.model.EmotionBallType import com.threegap.bitnagil.presentation.home.util.CollapsibleHeaderState import com.threegap.bitnagil.presentation.home.util.rememberCollapsibleHeaderState @Composable fun CollapsibleHomeHeader( userName: String, + emotionBallType: EmotionBallType?, collapsibleHeaderState: CollapsibleHeaderState, onEmotionRecordClick: () -> Unit, modifier: Modifier = Modifier, @@ -96,7 +98,7 @@ fun CollapsibleHomeHeader( .align(Alignment.BottomEnd), ) { EmotionBall( - emotionType = null, + emotionType = emotionBallType, onClick = {}, ) } @@ -149,6 +151,7 @@ private fun GreetingMessage( private fun HomeTopBarPreview() { CollapsibleHomeHeader( userName = "대현", + emotionBallType = null, collapsibleHeaderState = rememberCollapsibleHeaderState(), onEmotionRecordClick = {}, ) diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/RoutineDetailsBottomSheet.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/RoutineDetailsBottomSheet.kt index b79a7bb0..c841ce1d 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/RoutineDetailsBottomSheet.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/RoutineDetailsBottomSheet.kt @@ -266,6 +266,7 @@ private fun RoutineInfoContentPreview() { routineName = "개운하게 일어나기", executionTime = "20:30:00", isCompleted = false, + routineCompletionId = 1, isModified = false, subRoutines = listOf( SubRoutineUiModel( @@ -273,6 +274,7 @@ private fun RoutineInfoContentPreview() { historySeq = 1, subRoutineName = "물 마시기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -282,6 +284,7 @@ private fun RoutineInfoContentPreview() { historySeq = 1, subRoutineName = "스트레칭하기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -291,6 +294,7 @@ private fun RoutineInfoContentPreview() { historySeq = 1, subRoutineName = "심호흡하기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -313,6 +317,7 @@ private fun RoutineInfoContentSinglePreview() { routineName = "개운하게 일어나기", executionTime = "20:30:00", isCompleted = false, + routineCompletionId = 1, isModified = false, subRoutines = emptyList(), repeatDay = emptyList(), diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/RoutineSection.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/RoutineSection.kt index 5d9bf07d..7e35b987 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/RoutineSection.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/component/template/RoutineSection.kt @@ -107,6 +107,7 @@ private fun RoutineTemplatePreview() { routineId = "uuid1", routineName = "개운하게 일어나기", executionTime = "20:30:00", + routineCompletionId = 1, isCompleted = false, isModified = false, subRoutines = listOf( @@ -115,6 +116,7 @@ private fun RoutineTemplatePreview() { historySeq = 1, subRoutineName = "물 마시기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -124,6 +126,7 @@ private fun RoutineTemplatePreview() { historySeq = 1, subRoutineName = "스트레칭하기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, @@ -133,6 +136,7 @@ private fun RoutineTemplatePreview() { historySeq = 1, subRoutineName = "심호흡하기", sortOrder = 1, + routineCompletionId = 1, isCompleted = false, isModified = false, routineType = RoutineType.SUB_ROUTINE, diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/EmotionBallType.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/EmotionBallType.kt index 0e319db9..6e4fbfd0 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/EmotionBallType.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/EmotionBallType.kt @@ -3,6 +3,7 @@ package com.threegap.bitnagil.presentation.home.model import androidx.annotation.DrawableRes import androidx.compose.ui.graphics.Color import com.threegap.bitnagil.designsystem.R +import com.threegap.bitnagil.domain.emotion.model.Emotion enum class EmotionBallType( @DrawableRes val drawableId: Int, @@ -39,4 +40,10 @@ enum class EmotionBallType( ambientColor = Color(0xFFC71A1A).copy(alpha = 0.28f), spotColor = Color(0xFFC71A1A), ), + ; + + companion object { + fun fromDomainEmotion(emotion: Emotion?): EmotionBallType? = + emotion?.let { valueOf(it.name) } + } } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/HomeIntent.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/HomeIntent.kt index b6cd986a..f93ad5af 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/HomeIntent.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/HomeIntent.kt @@ -5,6 +5,8 @@ import java.time.LocalDate sealed class HomeIntent : MviIntent { data class UpdateLoading(val isLoading: Boolean) : HomeIntent() + data class LoadUserProfile(val nickname: String) : HomeIntent() + data class LoadMyEmotion(val emotion: EmotionBallType?) : HomeIntent() data class LoadWeeklyRoutines(val routines: RoutinesUiModel) : HomeIntent() data class OnDateSelect(val date: LocalDate) : HomeIntent() data class OnRoutineCompletionToggle(val routineId: String, val isCompleted: Boolean) : HomeIntent() @@ -13,6 +15,9 @@ sealed class HomeIntent : MviIntent { data class DeleteRoutineOptimistically(val routineId: String) : HomeIntent() data class ConfirmRoutineDeletion(val routineId: String) : HomeIntent() data class RestoreRoutinesAfterDeleteFailure(val backupRoutines: RoutinesUiModel) : HomeIntent() + data class DeleteRoutineByDayOptimistically(val routineId: String, val performedDate: String) : HomeIntent() + data class ConfirmRoutineByDayDeletion(val routineId: String, val performedDate: String) : HomeIntent() + data class RestoreRoutinesAfterDeleteByDayFailure(val backupRoutines: RoutinesUiModel) : HomeIntent() data class ShowRoutineDetailsBottomSheet(val routine: RoutineUiModel) : HomeIntent() data class ShowDeleteConfirmDialog(val routine: RoutineUiModel) : HomeIntent() data object OnPreviousWeekClick : HomeIntent() diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/HomeState.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/HomeState.kt index bb28206a..c7f6b0a1 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/HomeState.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/HomeState.kt @@ -8,6 +8,8 @@ import java.time.LocalDate @Parcelize data class HomeState( val isLoading: Boolean = false, + val userNickname: String = "", + val myEmotion: EmotionBallType? = null, val selectedDate: LocalDate = LocalDate.now(), val currentWeeks: List = LocalDate.now().getCurrentWeekDays(), val routines: RoutinesUiModel = RoutinesUiModel(), diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/RoutineUiModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/RoutineUiModel.kt index 8c613f1d..9db3aa49 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/RoutineUiModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/RoutineUiModel.kt @@ -3,6 +3,7 @@ package com.threegap.bitnagil.presentation.home.model import android.os.Parcelable import com.threegap.bitnagil.domain.routine.model.DayOfWeek import com.threegap.bitnagil.domain.routine.model.Routine +import com.threegap.bitnagil.domain.routine.model.RoutineByDayDeletion import com.threegap.bitnagil.domain.routine.model.RoutineType import kotlinx.parcelize.Parcelize @@ -15,6 +16,7 @@ data class RoutineUiModel( val executionTime: String, val subRoutines: List, val isModified: Boolean = false, + val routineCompletionId: Int?, val isCompleted: Boolean = false, val routineType: RoutineType, ) : Parcelable @@ -28,6 +30,16 @@ fun Routine.toUiModel(): RoutineUiModel = executionTime = this.executionTime, subRoutines = this.subRoutines.map { it.toUiModel() }, isModified = this.isModified, + routineCompletionId = this.routineCompletionId, isCompleted = this.isCompleted, routineType = this.routineType, ) + +fun RoutineUiModel.toRoutineByDayDeletion(performedDate: String): RoutineByDayDeletion = + RoutineByDayDeletion( + routineCompletionId = this.routineCompletionId, + routineId = this.routineId, + subRoutineInfosForDelete = this.subRoutines.map { it.toSubRoutineDeletionInfo() }, + performedDate = performedDate, + historySeq = this.historySeq, + ) diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/SubRoutineUiModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/SubRoutineUiModel.kt index 766cb702..ca442a40 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/SubRoutineUiModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/home/model/SubRoutineUiModel.kt @@ -3,6 +3,7 @@ package com.threegap.bitnagil.presentation.home.model import android.os.Parcelable import com.threegap.bitnagil.domain.routine.model.RoutineType import com.threegap.bitnagil.domain.routine.model.SubRoutine +import com.threegap.bitnagil.domain.routine.model.SubRoutineDeletionInfo import kotlinx.parcelize.Parcelize @Parcelize @@ -11,6 +12,7 @@ data class SubRoutineUiModel( val historySeq: Int, val subRoutineName: String, val sortOrder: Int, + val routineCompletionId: Int?, val isCompleted: Boolean = false, val isModified: Boolean = false, val routineType: RoutineType, @@ -21,8 +23,15 @@ fun SubRoutine.toUiModel(): SubRoutineUiModel = subRoutineId = this.subRoutineId, historySeq = this.historySeq, subRoutineName = this.subRoutineName, + routineCompletionId = this.routineCompletionId, sortOrder = this.sortOrder, isCompleted = this.isCompleted, isModified = this.isModified, routineType = this.routineType, ) + +fun SubRoutineUiModel.toSubRoutineDeletionInfo(): SubRoutineDeletionInfo = + SubRoutineDeletionInfo( + routineCompletionId = this.routineCompletionId, + subRoutineId = this.subRoutineId, + )