diff --git a/app/src/main/java/com/yapp/twix/di/InitKoin.kt b/app/src/main/java/com/yapp/twix/di/InitKoin.kt index 54cea66b..2c333cef 100644 --- a/app/src/main/java/com/yapp/twix/di/InitKoin.kt +++ b/app/src/main/java/com/yapp/twix/di/InitKoin.kt @@ -4,6 +4,7 @@ import android.content.Context import com.twix.data.di.dataModule import com.twix.datastore.di.dataStoreModule import com.twix.network.di.networkModule +import com.twix.util.di.utilModule import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin import org.koin.core.module.Module @@ -24,6 +25,7 @@ fun initKoin( add(uiModule) add(dataStoreModule) add(appModule) + add(utilModule) }, ) } diff --git a/app/src/main/java/com/yapp/twix/main/MainActivity.kt b/app/src/main/java/com/yapp/twix/main/MainActivity.kt index 81e672c9..501149bc 100644 --- a/app/src/main/java/com/yapp/twix/main/MainActivity.kt +++ b/app/src/main/java/com/yapp/twix/main/MainActivity.kt @@ -6,6 +6,7 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.safeContentPadding import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.core.view.WindowCompat @@ -30,7 +31,8 @@ class MainActivity : ComponentActivity() { Box( modifier = Modifier - .fillMaxSize(), + .fillMaxSize() + .safeContentPadding(), ) { AppNavHost() diff --git a/build-logic/convention/src/main/kotlin/com/twix/convention/FeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/twix/convention/FeatureConventionPlugin.kt index 8597f405..9d9f2715 100644 --- a/build-logic/convention/src/main/kotlin/com/twix/convention/FeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/com/twix/convention/FeatureConventionPlugin.kt @@ -15,6 +15,7 @@ class FeatureConventionPlugin : BuildLogicConventionPlugin({ implementation(project(":core:design-system")) implementation(project(":core:navigation")) implementation(project(":core:ui")) + implementation(project(":core:util")) implementation(project(":core:result")) implementation(project(":domain")) } diff --git a/core/design-system/src/main/res/values/strings.xml b/core/design-system/src/main/res/values/strings.xml index 0a0434c8..3325a37f 100644 --- a/core/design-system/src/main/res/values/strings.xml +++ b/core/design-system/src/main/res/values/strings.xml @@ -59,6 +59,7 @@ 종료 날짜가 시작 날짜보다 이전입니다. 목표 조회에 실패했습니다. + 목표 생성에 실패했습니다. %s\n목표를 이루셨나요? diff --git a/core/network/src/main/java/com/twix/network/model/request/goal/mapper/GoalMapper.kt b/core/network/src/main/java/com/twix/network/model/request/goal/mapper/GoalMapper.kt new file mode 100644 index 00000000..c93d9a12 --- /dev/null +++ b/core/network/src/main/java/com/twix/network/model/request/goal/mapper/GoalMapper.kt @@ -0,0 +1,14 @@ +package com.twix.network.model.request.goal.mapper + +import com.twix.domain.model.goal.CreateGoalParam +import com.twix.network.model.request.goal.model.CreateGoalRequest + +fun CreateGoalParam.toRequest(): CreateGoalRequest = + CreateGoalRequest( + name = name, + icon = icon.toApi(), + repeatCycle = repeatCycle.toApi(), + repeatCount = repeatCount, + startDate = startDate.toString(), + endDate = endDate?.toString(), + ) diff --git a/core/network/src/main/java/com/twix/network/model/request/goal/model/CreateGoalRequest.kt b/core/network/src/main/java/com/twix/network/model/request/goal/model/CreateGoalRequest.kt new file mode 100644 index 00000000..f5c8c602 --- /dev/null +++ b/core/network/src/main/java/com/twix/network/model/request/goal/model/CreateGoalRequest.kt @@ -0,0 +1,14 @@ +package com.twix.network.model.request.goal.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class CreateGoalRequest( + @SerialName("name") val name: String, + @SerialName("icon") val icon: String, + @SerialName("repeatCycle") val repeatCycle: String, + @SerialName("repeatCount") val repeatCount: Int, + @SerialName("startDate") val startDate: String, + @SerialName("endDate") val endDate: String?, +) diff --git a/core/network/src/main/java/com/twix/network/model/response/goal/mapper/GoalMapper.kt b/core/network/src/main/java/com/twix/network/model/response/goal/mapper/GoalMapper.kt index ee46b98e..6c62c5de 100644 --- a/core/network/src/main/java/com/twix/network/model/response/goal/mapper/GoalMapper.kt +++ b/core/network/src/main/java/com/twix/network/model/response/goal/mapper/GoalMapper.kt @@ -3,12 +3,15 @@ package com.twix.network.model.response.goal.mapper import com.twix.domain.model.enums.GoalIconType import com.twix.domain.model.enums.GoalReactionType import com.twix.domain.model.enums.RepeatCycle +import com.twix.domain.model.goal.CreatedGoal import com.twix.domain.model.goal.Goal import com.twix.domain.model.goal.GoalList import com.twix.domain.model.goal.GoalVerification +import com.twix.network.model.response.goal.model.CreateGoalResponse import com.twix.network.model.response.goal.model.GoalListResponse import com.twix.network.model.response.goal.model.GoalResponse import com.twix.network.model.response.goal.model.VerificationResponse +import java.time.LocalDate fun GoalListResponse.toDomain(): GoalList = GoalList( @@ -37,3 +40,15 @@ fun VerificationResponse.toDomainOrNull(): GoalVerification? = reaction = GoalReactionType.fromApi(reaction), uploadedAt = uploadedAt, ) + +fun CreateGoalResponse.toDomain(): CreatedGoal = + CreatedGoal( + goalId = goalId, + name = name, + icon = GoalIconType.fromApi(icon), + repeatCycle = RepeatCycle.fromApi(repeatCycle), + repeatCount = repeatCount, + startDate = LocalDate.parse(startDate), + endDate = endDate?.let(LocalDate::parse), + createdAt = createdAt, + ) diff --git a/core/network/src/main/java/com/twix/network/model/response/goal/model/CreateGoalResponse.kt b/core/network/src/main/java/com/twix/network/model/response/goal/model/CreateGoalResponse.kt new file mode 100644 index 00000000..7150b5a6 --- /dev/null +++ b/core/network/src/main/java/com/twix/network/model/response/goal/model/CreateGoalResponse.kt @@ -0,0 +1,17 @@ +package com.twix.network.model.response.goal.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class CreateGoalResponse( + @SerialName("goalId") val goalId: Long, + @SerialName("name") val name: String, + @SerialName("icon") val icon: String, + @SerialName("repeatCycle") val repeatCycle: String, + @SerialName("repeatCount") val repeatCount: Int, + @SerialName("startDate") val startDate: String, + @SerialName("endDate") val endDate: String?, + @SerialName("goalStatus") val goalStatus: String, + @SerialName("createdAt") val createdAt: String, +) diff --git a/core/network/src/main/java/com/twix/network/service/GoalService.kt b/core/network/src/main/java/com/twix/network/service/GoalService.kt index 8ff116e7..3a46205d 100644 --- a/core/network/src/main/java/com/twix/network/service/GoalService.kt +++ b/core/network/src/main/java/com/twix/network/service/GoalService.kt @@ -1,7 +1,11 @@ package com.twix.network.service +import com.twix.network.model.request.goal.model.CreateGoalRequest +import com.twix.network.model.response.goal.model.CreateGoalResponse import com.twix.network.model.response.goal.model.GoalListResponse +import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.Query interface GoalService { @@ -9,4 +13,9 @@ interface GoalService { suspend fun fetchGoals( @Query("date") date: String, ): GoalListResponse + + @POST("api/v1/goals") + suspend fun createGoal( + @Body body: CreateGoalRequest, + ): CreateGoalResponse } diff --git a/core/ui/src/main/java/com/twix/ui/base/BaseViewModel.kt b/core/ui/src/main/java/com/twix/ui/base/BaseViewModel.kt index 09b49864..8334db70 100644 --- a/core/ui/src/main/java/com/twix/ui/base/BaseViewModel.kt +++ b/core/ui/src/main/java/com/twix/ui/base/BaseViewModel.kt @@ -69,6 +69,10 @@ abstract class BaseViewModel( sideEffectHolder.emit(effect) } + protected fun tryEmitSideEffect(effect: SE) { + sideEffectHolder.tryEmit(effect) + } + /** * Intent를 처리하는 메서드 * */ diff --git a/core/ui/src/main/java/com/twix/ui/base/SideEffectHolder.kt b/core/ui/src/main/java/com/twix/ui/base/SideEffectHolder.kt index 83d09440..8db5436a 100644 --- a/core/ui/src/main/java/com/twix/ui/base/SideEffectHolder.kt +++ b/core/ui/src/main/java/com/twix/ui/base/SideEffectHolder.kt @@ -10,4 +10,8 @@ class SideEffectHolder { suspend fun emit(effect: S) { channel.send(effect) } + + fun tryEmit(effect: S) { + channel.trySend(effect) + } } diff --git a/core/util/build.gradle.kts b/core/util/build.gradle.kts index 03c85182..53267b6b 100644 --- a/core/util/build.gradle.kts +++ b/core/util/build.gradle.kts @@ -1,5 +1,6 @@ plugins { alias(libs.plugins.twix.android.library) + alias(libs.plugins.twix.koin) } android { diff --git a/core/util/src/main/java/com/twix/util/bus/GoalRefreshBus.kt b/core/util/src/main/java/com/twix/util/bus/GoalRefreshBus.kt new file mode 100644 index 00000000..c2fd72a6 --- /dev/null +++ b/core/util/src/main/java/com/twix/util/bus/GoalRefreshBus.kt @@ -0,0 +1,15 @@ +package com.twix.util.bus + +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow + +class GoalRefreshBus { + private val _events = + MutableSharedFlow( + replay = 0, + extraBufferCapacity = 1, + ) + val events: SharedFlow = _events + + fun notifyChanged() = _events.tryEmit(Unit) +} diff --git a/core/util/src/main/java/com/twix/util/di/UtilModule.kt b/core/util/src/main/java/com/twix/util/di/UtilModule.kt new file mode 100644 index 00000000..0ad75b92 --- /dev/null +++ b/core/util/src/main/java/com/twix/util/di/UtilModule.kt @@ -0,0 +1,9 @@ +package com.twix.util.di + +import com.twix.util.bus.GoalRefreshBus +import org.koin.dsl.module + +val utilModule = + module { + single { GoalRefreshBus() } + } diff --git a/data/src/main/java/com/twix/data/repository/DefaultGoalRepository.kt b/data/src/main/java/com/twix/data/repository/DefaultGoalRepository.kt index f145b393..1cf57d01 100644 --- a/data/src/main/java/com/twix/data/repository/DefaultGoalRepository.kt +++ b/data/src/main/java/com/twix/data/repository/DefaultGoalRepository.kt @@ -1,8 +1,11 @@ package com.twix.data.repository +import com.twix.domain.model.goal.CreateGoalParam +import com.twix.domain.model.goal.CreatedGoal import com.twix.domain.model.goal.GoalList import com.twix.domain.repository.GoalRepository import com.twix.network.execute.safeApiCall +import com.twix.network.model.request.goal.mapper.toRequest import com.twix.network.model.response.goal.mapper.toDomain import com.twix.network.service.GoalService import com.twix.result.AppResult @@ -11,4 +14,9 @@ class DefaultGoalRepository( private val service: GoalService, ) : GoalRepository { override suspend fun fetchGoalList(date: String): AppResult = safeApiCall { service.fetchGoals(date).toDomain() } + + override suspend fun createGoal(param: CreateGoalParam): AppResult = + safeApiCall { + service.createGoal(param.toRequest()).toDomain() + } } diff --git a/domain/src/main/java/com/twix/domain/model/enums/GoalIconType.kt b/domain/src/main/java/com/twix/domain/model/enums/GoalIconType.kt index 0f4870e4..7e5a84bc 100644 --- a/domain/src/main/java/com/twix/domain/model/enums/GoalIconType.kt +++ b/domain/src/main/java/com/twix/domain/model/enums/GoalIconType.kt @@ -11,6 +11,18 @@ enum class GoalIconType { LAPTOP, ; + fun toApi(): String = + when (this) { + DEFAULT -> "ICON_DEFAULT" + CLEAN -> "ICON_CLEAN" + EXERCISE -> "ICON_EXERCISE" + BOOK -> "ICON_BOOK" + PENCIL -> "ICON_PENCIL" + HEALTH -> "ICON_HEALTH" + HEART -> "ICON_HEART" + LAPTOP -> "ICON_LAPTOP" + } + companion object { fun fromApi(icon: String): GoalIconType = when (icon) { diff --git a/domain/src/main/java/com/twix/domain/model/enums/RepeatCycle.kt b/domain/src/main/java/com/twix/domain/model/enums/RepeatCycle.kt index 2931eaf9..5948f781 100644 --- a/domain/src/main/java/com/twix/domain/model/enums/RepeatCycle.kt +++ b/domain/src/main/java/com/twix/domain/model/enums/RepeatCycle.kt @@ -6,6 +6,8 @@ enum class RepeatCycle { MONTHLY, ; + fun toApi(): String = name + companion object { fun fromApi(value: String): RepeatCycle = runCatching { valueOf(value) }.getOrElse { DAILY } } diff --git a/domain/src/main/java/com/twix/domain/model/goal/CreateGoalParam.kt b/domain/src/main/java/com/twix/domain/model/goal/CreateGoalParam.kt new file mode 100644 index 00000000..b4a0bee7 --- /dev/null +++ b/domain/src/main/java/com/twix/domain/model/goal/CreateGoalParam.kt @@ -0,0 +1,14 @@ +package com.twix.domain.model.goal + +import com.twix.domain.model.enums.GoalIconType +import com.twix.domain.model.enums.RepeatCycle +import java.time.LocalDate + +data class CreateGoalParam( + val name: String, + val icon: GoalIconType, + val repeatCycle: RepeatCycle, + val repeatCount: Int, + val startDate: LocalDate, + val endDate: LocalDate?, +) diff --git a/domain/src/main/java/com/twix/domain/model/goal/CreatedGoal.kt b/domain/src/main/java/com/twix/domain/model/goal/CreatedGoal.kt new file mode 100644 index 00000000..fdb95343 --- /dev/null +++ b/domain/src/main/java/com/twix/domain/model/goal/CreatedGoal.kt @@ -0,0 +1,16 @@ +package com.twix.domain.model.goal + +import com.twix.domain.model.enums.GoalIconType +import com.twix.domain.model.enums.RepeatCycle +import java.time.LocalDate + +data class CreatedGoal( + val goalId: Long, + val name: String, + val icon: GoalIconType, + val repeatCycle: RepeatCycle, + val repeatCount: Int, + val startDate: LocalDate, + val endDate: LocalDate?, + val createdAt: String, +) diff --git a/domain/src/main/java/com/twix/domain/repository/GoalRepository.kt b/domain/src/main/java/com/twix/domain/repository/GoalRepository.kt index be0958f9..c79b7732 100644 --- a/domain/src/main/java/com/twix/domain/repository/GoalRepository.kt +++ b/domain/src/main/java/com/twix/domain/repository/GoalRepository.kt @@ -1,8 +1,12 @@ package com.twix.domain.repository +import com.twix.domain.model.goal.CreateGoalParam +import com.twix.domain.model.goal.CreatedGoal import com.twix.domain.model.goal.GoalList import com.twix.result.AppResult interface GoalRepository { suspend fun fetchGoalList(date: String): AppResult + + suspend fun createGoal(param: CreateGoalParam): AppResult } diff --git a/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorScreen.kt b/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorScreen.kt index 3e59a370..89e116e4 100644 --- a/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorScreen.kt +++ b/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorScreen.kt @@ -85,6 +85,7 @@ fun GoalEditorRoute( viewModel.sideEffect.collect { effect -> when (effect) { is GoalEditorSideEffect.ShowToast -> toastManager.tryShow(ToastData(currentContext.getString(effect.resId), effect.type)) + is GoalEditorSideEffect.NavigateToHome -> navigateToBack() } } } @@ -332,7 +333,7 @@ private fun RepeatCountBottomSheetContent( .padding(horizontal = 12.dp, vertical = 5.5.dp) .noRippleClickable(onClick = { internalSelectedRepeatType = RepeatCycle.WEEKLY - internalRepeatCount = 0 + internalRepeatCount = 1 }), ) @@ -348,7 +349,7 @@ private fun RepeatCountBottomSheetContent( .padding(horizontal = 12.dp, vertical = 5.5.dp) .noRippleClickable(onClick = { internalSelectedRepeatType = RepeatCycle.MONTHLY - internalRepeatCount = 0 + internalRepeatCount = 1 }), ) } diff --git a/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorSideEffect.kt b/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorSideEffect.kt index 6e2fcd2a..0594cdb3 100644 --- a/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorSideEffect.kt +++ b/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorSideEffect.kt @@ -9,4 +9,6 @@ interface GoalEditorSideEffect : SideEffect { @param:StringRes val resId: Int, val type: ToastType, ) : GoalEditorSideEffect + + object NavigateToHome : GoalEditorSideEffect } diff --git a/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorViewModel.kt b/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorViewModel.kt index c0c7a7e8..8958f0e4 100644 --- a/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorViewModel.kt +++ b/feature/goal-editor/src/main/java/com/twix/goal_editor/GoalEditorViewModel.kt @@ -6,15 +6,20 @@ import com.twix.designsystem.components.toast.model.ToastType import com.twix.domain.model.enums.GoalIconType import com.twix.domain.model.enums.GoalReactionType import com.twix.domain.model.enums.RepeatCycle +import com.twix.domain.model.goal.CreateGoalParam import com.twix.domain.model.goal.Goal import com.twix.domain.model.goal.GoalVerification +import com.twix.domain.repository.GoalRepository import com.twix.goal_editor.model.GoalEditorUiState import com.twix.ui.base.BaseViewModel +import com.twix.util.bus.GoalRefreshBus import kotlinx.coroutines.launch import java.time.LocalDate -class GoalEditorViewModel : - BaseViewModel( +class GoalEditorViewModel( + private val goalRepository: GoalRepository, + private val goalRefreshBus: GoalRefreshBus, +) : BaseViewModel( GoalEditorUiState(), ) { override suspend fun handleIntent(intent: GoalEditorIntent) { @@ -42,7 +47,7 @@ class GoalEditorViewModel : } private fun setRepeatType(repeatCycle: RepeatCycle) { - reduce { copy(selectedRepeatCycle = repeatCycle) } + reduce { copy(selectedRepeatCycle = repeatCycle, repeatCount = 1) } } private fun setRepeatCount(repeatCount: Int) { @@ -72,6 +77,15 @@ class GoalEditorViewModel : } return } + + launchResult( + block = { goalRepository.createGoal(currentState.toCreateParam()) }, + onSuccess = { + goalRefreshBus.notifyChanged() + tryEmitSideEffect(GoalEditorSideEffect.NavigateToHome) + }, + onError = { emitSideEffect(GoalEditorSideEffect.ShowToast(R.string.toast_create_goal_failed, ToastType.ERROR)) }, + ) } private fun initGoal(id: Long) { @@ -113,4 +127,14 @@ class GoalEditorViewModel : ) } } + + private fun GoalEditorUiState.toCreateParam(): CreateGoalParam = + CreateGoalParam( + name = goalTitle.trim(), + icon = selectedIcon, + repeatCycle = selectedRepeatCycle, + repeatCount = repeatCount, + startDate = startDate, + endDate = if (endDateEnabled) endDate else null, + ) } diff --git a/feature/goal-editor/src/main/java/com/twix/goal_editor/model/GoalEditorUiState.kt b/feature/goal-editor/src/main/java/com/twix/goal_editor/model/GoalEditorUiState.kt index 7cc8ca7b..8add180f 100644 --- a/feature/goal-editor/src/main/java/com/twix/goal_editor/model/GoalEditorUiState.kt +++ b/feature/goal-editor/src/main/java/com/twix/goal_editor/model/GoalEditorUiState.kt @@ -11,11 +11,11 @@ data class GoalEditorUiState( val selectedIcon: GoalIconType = GoalIconType.DEFAULT, val goalTitle: String = "", val selectedRepeatCycle: RepeatCycle = RepeatCycle.DAILY, - val repeatCount: Int = 0, + val repeatCount: Int = 1, val startDate: LocalDate = LocalDate.now(), val endDateEnabled: Boolean = false, val endDate: LocalDate = LocalDate.now(), ) : State { val isEnabled: Boolean - get() = goalTitle.isNotBlank() && repeatCount > 0 + get() = goalTitle.isNotBlank() && (selectedRepeatCycle == RepeatCycle.DAILY || repeatCount > 0) } diff --git a/feature/main/src/main/java/com/twix/home/HomeViewModel.kt b/feature/main/src/main/java/com/twix/home/HomeViewModel.kt index 66465446..db68185d 100644 --- a/feature/main/src/main/java/com/twix/home/HomeViewModel.kt +++ b/feature/main/src/main/java/com/twix/home/HomeViewModel.kt @@ -8,18 +8,31 @@ import com.twix.domain.repository.GoalRepository import com.twix.home.model.CalendarState import com.twix.home.model.HomeUiState import com.twix.ui.base.BaseViewModel +import com.twix.util.bus.GoalRefreshBus import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import java.time.LocalDate class HomeViewModel( private val goalRepository: GoalRepository, + private val goalRefreshBus: GoalRefreshBus, ) : BaseViewModel( HomeUiState(), ) { + init { + fetchGoalList() + + viewModelScope.launch { + goalRefreshBus.events.collect { + fetchGoalList() + } + } + } + val calendarState: StateFlow = uiState .map { state -> @@ -40,10 +53,6 @@ class HomeViewModel( ), ) - init { - fetchGoalList() - } - override suspend fun handleIntent(intent: HomeIntent) { when (intent) { is HomeIntent.SelectDate -> updateDate(intent.date) diff --git a/feature/main/src/main/java/com/twix/home/model/HomeUiState.kt b/feature/main/src/main/java/com/twix/home/model/HomeUiState.kt index 90b34936..a411ad27 100644 --- a/feature/main/src/main/java/com/twix/home/model/HomeUiState.kt +++ b/feature/main/src/main/java/com/twix/home/model/HomeUiState.kt @@ -1,12 +1,7 @@ package com.twix.home.model import androidx.compose.runtime.Immutable -import com.twix.domain.model.enums.GoalIconType -import com.twix.domain.model.enums.GoalReactionType -import com.twix.domain.model.enums.RepeatCycle -import com.twix.domain.model.goal.Goal import com.twix.domain.model.goal.GoalList -import com.twix.domain.model.goal.GoalVerification import com.twix.ui.base.State import java.time.LocalDate import java.time.YearMonth @@ -17,80 +12,7 @@ data class HomeUiState( val visibleDate: LocalDate = LocalDate.now(), // 홈 화면 상단에 존재하는 월, 년 텍스트를 위한 상태 변수 val selectedDate: LocalDate = LocalDate.now(), val referenceDate: LocalDate = LocalDate.now(), // 7일 달력을 생성하기 위한 레퍼런스 날짜 - val goalList: GoalList = - GoalList( - goals = - listOf( - Goal( - goalId = 1, - name = "운동", - icon = GoalIconType.EXERCISE, - repeatCycle = RepeatCycle.WEEKLY, - myCompleted = true, - partnerCompleted = false, - myVerification = null, - partnerVerification = null, - ), - Goal( - goalId = 2, - name = "운동", - icon = GoalIconType.EXERCISE, - repeatCycle = RepeatCycle.WEEKLY, - myCompleted = true, - partnerCompleted = false, - myVerification = - GoalVerification( - photologId = 1, - imageUrl = "https://picsum.photos/400/300", - comment = null, - reaction = GoalReactionType.LOVE, - uploadedAt = "2023-05-05", - ), - partnerVerification = null, - ), - Goal( - goalId = 3, - name = "잠자기", - icon = GoalIconType.HEART, - repeatCycle = RepeatCycle.WEEKLY, - myCompleted = false, - partnerCompleted = true, - myVerification = null, - partnerVerification = - GoalVerification( - photologId = 1, - imageUrl = "https://picsum.photos/400/300", - comment = null, - reaction = GoalReactionType.LOVE, - uploadedAt = "2023-05-05", - ), - ), - Goal( - goalId = 4, - name = "밥무라", - icon = GoalIconType.DEFAULT, - repeatCycle = RepeatCycle.WEEKLY, - myCompleted = true, - partnerCompleted = true, - myVerification = - GoalVerification( - photologId = 1, - imageUrl = "https://picsum.photos/400/300", - comment = null, - reaction = GoalReactionType.LOVE, - uploadedAt = "2023-05-05", - ), - partnerVerification = - GoalVerification( - photologId = 1, - imageUrl = "https://picsum.photos/400/300", - comment = null, - reaction = GoalReactionType.LOVE, - uploadedAt = "2023-05-05", - ), - ), - ), - ), + val goalList: GoalList = GoalList(), ) : State { val monthYear: String get() = "${visibleDate.month.value}월 ${visibleDate.year}"