Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2ada90d
♻️ Refactor: RepeatType -> RepeatCycle로 변경
dogmania Feb 5, 2026
c0aea12
✨ Feat: :core:result 의존성 추가
dogmania Feb 5, 2026
3766e91
♻️ Refactor: androidLibrary -> Java Library로 변경
dogmania Feb 5, 2026
39512e4
✨ Feat: :domain 의존성 추가
dogmania Feb 5, 2026
9cc031d
✨ Feat: :core:result 의존성 추가
dogmania Feb 5, 2026
ada22ae
✨ Feat: GoalService 구현
dogmania Feb 5, 2026
4004540
✨ Feat: fetchGoals API 메서드 연동
dogmania Feb 5, 2026
b5cc305
✨ Feat: 목표 조회 Domain Model 구현
dogmania Feb 5, 2026
3e1baaa
✨ Feat: 목표 조회 DTO 구현
dogmania Feb 5, 2026
5d4fc8a
✨ Feat: 목표 DTO -> Domain Mapper 구현
dogmania Feb 5, 2026
3fa3cc3
✨ Feat: GoalService Koin 모듈 등록
dogmania Feb 5, 2026
9ee1f1b
♻️ Refactor: api/v1 추가
dogmania Feb 5, 2026
130212d
♻️ Refactor: onError 메서드 suspend로 변경
dogmania Feb 5, 2026
357719e
✨ Feat: GoalRepository Koin 모듈 등록
dogmania Feb 5, 2026
1f2d5be
✨ Feat: fromApi 메서드 구현
dogmania Feb 5, 2026
84a796a
✨ Feat: 목표 조회 비즈니스 로직 연결 및 상태 처리
dogmania Feb 5, 2026
868967e
🍱 Chore: string 리소스 추가
dogmania Feb 5, 2026
8d2b98d
♻️ Refactor: DTO icon을 GoalIconType으로 변환
dogmania Feb 5, 2026
1cc01d8
✨ Feat: GoalIconType.toRes 확장 메서드 구현
dogmania Feb 5, 2026
17d4af2
♻️ Refactor: :core:design-system의 toRes를 사용하도록 변경
dogmania Feb 5, 2026
4603db3
🍱 Chore: 아이콘 추가
dogmania Feb 5, 2026
82cfeb7
🔥 Remove: 불필요한 주석 제거
dogmania Feb 5, 2026
0b10ada
🐛 Fix: conflict 해결
dogmania Feb 5, 2026
d5fe299
♻️ Refactor: api/v1/ 추가
dogmania Feb 5, 2026
e5f4de6
♻️ Refactor: import 알바펫 순으로 정렬
dogmania Feb 6, 2026
dc4e6f8
♻️ Refactor: ktlint 적용
dogmania Feb 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class FeatureConventionPlugin : BuildLogicConventionPlugin({
implementation(project(":core:design-system"))
implementation(project(":core:navigation"))
implementation(project(":core:ui"))
implementation(project(":core:result"))
implementation(project(":domain"))
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.twix.designsystem.extension

import com.twix.designsystem.R
import com.twix.domain.model.enums.GoalIconType

fun GoalIconType.toRes(): Int =
when (this) {
GoalIconType.DEFAULT -> R.drawable.ic_default
GoalIconType.CLEAN -> R.drawable.ic_clean
GoalIconType.EXERCISE -> R.drawable.ic_exercise
GoalIconType.BOOK -> R.drawable.ic_book
GoalIconType.PENCIL -> R.drawable.ic_pencil
GoalIconType.HEALTH -> R.drawable.ic_health
GoalIconType.HEART -> R.drawable.ic_heart
GoalIconType.LAPTOP -> R.drawable.ic_laptop
}
18 changes: 18 additions & 0 deletions core/design-system/src/main/res/drawable/ic_checked_me.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<path
android:strokeWidth="1"
android:pathData="M14,14m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0"
android:fillColor="#171717"
android:strokeColor="#171717"/>
<path
android:pathData="M9,12.947L13.167,18L19,10"
android:strokeLineJoin="round"
android:strokeWidth="1.2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</vector>
27 changes: 27 additions & 0 deletions core/design-system/src/main/res/drawable/ic_checked_you.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<group>
<clip-path
android:pathData="M0,0h28v28h-28z"/>
<path
android:pathData="M14,14m-12.7,0a12.7,12.7 0,1 1,25.4 0a12.7,12.7 0,1 1,-25.4 0"
android:strokeWidth="1.4"
android:fillColor="#00000000"
android:strokeColor="#ffffff"/>
<path
android:strokeWidth="1"
android:pathData="M14,14m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0"
android:fillColor="#171717"
android:strokeColor="#171717"/>
<path
android:pathData="M9,12.947L13.167,18L19,10"
android:strokeLineJoin="round"
android:strokeWidth="1.2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</group>
</vector>
27 changes: 27 additions & 0 deletions core/design-system/src/main/res/drawable/ic_unchecked_me.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<group>
<clip-path
android:pathData="M0,0h28v28h-28z"/>
<path
android:pathData="M14,14m-12.7,0a12.7,12.7 0,1 1,25.4 0a12.7,12.7 0,1 1,-25.4 0"
android:strokeWidth="1.4"
android:fillColor="#00000000"
android:strokeColor="#ffffff"/>
<path
android:strokeWidth="1"
android:pathData="M14,14m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0"
android:fillColor="#ffffff"
android:strokeColor="#171717"/>
<path
android:pathData="M9,12.947L13.167,18L19,10"
android:strokeLineJoin="round"
android:strokeWidth="1.2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</group>
</vector>
18 changes: 18 additions & 0 deletions core/design-system/src/main/res/drawable/ic_unchecked_you.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<path
android:strokeWidth="1"
android:pathData="M14,14m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0"
android:fillColor="#ffffff"
android:strokeColor="#C6C6C6"/>
<path
android:pathData="M9,12.947L13.167,18L19,10"
android:strokeLineJoin="round"
android:strokeWidth="1.2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</vector>
1 change: 1 addition & 0 deletions core/design-system/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@

<!-- 토스트 메시지 -->
<string name="toast_end_date_before_start_date">종료 날짜가 시작 날짜보다 이전입니다.</string>
<string name="toast_goal_fetch_failed">목표 조회에 실패했습니다.</string>

</resources>
1 change: 1 addition & 0 deletions core/network/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ android {
dependencies {
implementation(projects.core.token)
implementation(projects.core.result)
implementation(projects.domain)

implementation(libs.bundles.ktor)
implementation(libs.ktorfit.lib)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.twix.network.di

import com.twix.network.service.AuthService
import com.twix.network.service.GoalService
import com.twix.network.service.OnboardingService
import com.twix.network.service.createAuthService
import com.twix.network.service.createGoalService
import com.twix.network.service.createOnboardingService
import de.jensklingenberg.ktorfit.Ktorfit
import org.koin.dsl.module
Expand All @@ -15,4 +17,7 @@ internal val apiServiceModule =
single<AuthService> {
get<Ktorfit>().createAuthService()
}
single<GoalService> {
get<Ktorfit>().createGoalService()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.twix.network.model.response.goal.mapper

import com.twix.domain.model.enums.GoalIconType
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.network.model.response.goal.model.GoalListResponse
import com.twix.network.model.response.goal.model.GoalResponse
import com.twix.network.model.response.goal.model.VerificationResponse

fun GoalListResponse.toDomain(): GoalList =
GoalList(
completedCount = completedCount,
totalCount = totalCount,
goals = goals.map { it.toDomain() },
)

fun GoalResponse.toDomain(): Goal =
Goal(
goalId = goalId,
name = name,
icon = GoalIconType.fromApi(icon),
repeatCycle = RepeatCycle.fromApi(repeatCycle),
myCompleted = myCompleted,
partnerCompleted = partnerCompleted,
myVerification = myVerification?.toDomainOrNull(),
partnerVerification = partnerVerification?.toDomainOrNull(),
)

fun VerificationResponse.toDomainOrNull(): GoalVerification? =
GoalVerification(
photologId = photologId,
imageUrl = imageUrl,
comment = comment,
reaction = reaction,
uploadedAt = uploadedAt,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.twix.network.model.response.goal.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class GoalListResponse(
@SerialName("completedCount") val completedCount: Int,
@SerialName("totalCount") val totalCount: Int,
@SerialName("goals") val goals: List<GoalResponse>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.twix.network.model.response.goal.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class GoalResponse(
@SerialName("goalId") val goalId: Long,
@SerialName("name") val name: String,
@SerialName("icon") val icon: String,
@SerialName("repeatCycle") val repeatCycle: String,
@SerialName("myCompleted") val myCompleted: Boolean,
@SerialName("partnerCompleted") val partnerCompleted: Boolean,
@SerialName("myVerification") val myVerification: VerificationResponse? = null,
@SerialName("partnerVerification") val partnerVerification: VerificationResponse? = null,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.twix.network.model.response.goal.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class VerificationResponse(
@SerialName("photologId") val photologId: Long,
@SerialName("imageUrl") val imageUrl: String,
@SerialName("comment") val comment: String? = null,
@SerialName("reaction") val reaction: String? = null,
@SerialName("uploadedAt") val uploadedAt: String, // yyyy-mm-dd
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import de.jensklingenberg.ktorfit.http.Body
import de.jensklingenberg.ktorfit.http.POST

interface AuthService {
@POST("auth/google/token")
@POST("api/v1/auth/google/token")
suspend fun googleLogin(
@Body request: LoginRequest,
): LoginResponse

@POST("auth/refresh")
@POST("api/v1/auth/refresh")
suspend fun refresh(
@Body request: RefreshRequest,
): RefreshResponse
Expand Down
12 changes: 12 additions & 0 deletions core/network/src/main/java/com/twix/network/service/GoalService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.twix.network.service

import com.twix.network.model.response.goal.model.GoalListResponse
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.Query

interface GoalService {
@GET("api/v1/goals")
suspend fun fetchGoals(
@Query("date") date: String,
): GoalListResponse
}
6 changes: 1 addition & 5 deletions core/result/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
plugins {
alias(libs.plugins.twix.android.library)
}

android {
namespace = "com.twix.result"
alias(libs.plugins.twix.java.library)
}
2 changes: 1 addition & 1 deletion core/ui/src/main/java/com/twix/ui/base/BaseViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ abstract class BaseViewModel<S : State, I : Intent, SE : SideEffect>(
onStart: (() -> Unit)? = null, // 비동기 시작 전 처리해야 할 로직 ex) 로딩
onFinally: (() -> Unit)? = null, // 비동기 종료 후 리소스 정리
onSuccess: (D) -> Unit, // 비동기 메서드 호출이 성공했을 때 처리해야 할 로직
onError: ((AppError) -> Unit)? = null, // 비동기 메서드 호출에 실패했을 때 처리해야 할 로직
onError: (suspend (AppError) -> Unit)? = null, // 비동기 메서드 호출에 실패했을 때 처리해야 할 로직
block: suspend () -> AppResult<D>, // 비동기 메서드 ex) 서버 통신 메서드
): Job =
viewModelScope.launch {
Expand Down
1 change: 1 addition & 0 deletions data/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ android {

dependencies {
implementation(projects.core.datastore)
implementation(projects.core.result)
implementation(projects.core.token)
}
5 changes: 5 additions & 0 deletions data/src/main/java/com/twix/data/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.twix.data.di

import com.twix.data.repository.DefaultAuthRepository
import com.twix.data.repository.DefaultGoalRepository
import com.twix.data.repository.DefaultOnboardingRepository
import com.twix.domain.repository.AuthRepository
import com.twix.domain.repository.GoalRepository
import com.twix.domain.repository.OnBoardingRepository
import org.koin.dsl.module

Expand All @@ -11,6 +13,9 @@ internal val repositoryModule =
single<OnBoardingRepository> {
DefaultOnboardingRepository(get())
}
single<GoalRepository> {
DefaultGoalRepository(get())
}
single<AuthRepository> {
DefaultAuthRepository(get(), get())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.twix.data.repository

import com.twix.domain.model.goal.GoalList
import com.twix.domain.repository.GoalRepository
import com.twix.network.execute.safeApiCall
import com.twix.network.model.response.goal.mapper.toDomain
import com.twix.network.service.GoalService
import com.twix.result.AppResult

class DefaultGoalRepository(
private val service: GoalService,
) : GoalRepository {
override suspend fun fetchGoalList(date: String): AppResult<GoalList> = safeApiCall { service.fetchGoals(date).toDomain() }
}
4 changes: 4 additions & 0 deletions domain/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
plugins {
alias(libs.plugins.twix.java.library)
}

dependencies {
implementation(projects.core.result)
}
16 changes: 16 additions & 0 deletions domain/src/main/java/com/twix/domain/model/enums/GoalIconType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,20 @@ enum class GoalIconType {
HEALTH,
HEART,
LAPTOP,
;

companion object {
fun fromApi(icon: String): GoalIconType =
when (icon) {
"ICON_DEFAULT" -> DEFAULT
"ICON_CLEAN" -> CLEAN
"ICON_EXERCISE" -> EXERCISE
"ICON_BOOK" -> BOOK
"ICON_PENCIL" -> PENCIL
"ICON_HEALTH" -> HEALTH
"ICON_HEART" -> HEART
"ICON_LAPTOP" -> LAPTOP
else -> DEFAULT
}
}
}
12 changes: 12 additions & 0 deletions domain/src/main/java/com/twix/domain/model/enums/RepeatCycle.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.twix.domain.model.enums

enum class RepeatCycle {
DAILY,
WEEKLY,
MONTHLY,
;

companion object {
fun fromApi(value: String): RepeatCycle = runCatching { valueOf(value) }.getOrElse { DAILY }
}
}

This file was deleted.

15 changes: 15 additions & 0 deletions domain/src/main/java/com/twix/domain/model/goal/Goal.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.twix.domain.model.goal

import com.twix.domain.model.enums.GoalIconType
import com.twix.domain.model.enums.RepeatCycle

data class Goal(
val goalId: Long,
val name: String,
val icon: GoalIconType,
val repeatCycle: RepeatCycle,
val myCompleted: Boolean,
val partnerCompleted: Boolean,
val myVerification: GoalVerification?,
val partnerVerification: GoalVerification?,
)
7 changes: 7 additions & 0 deletions domain/src/main/java/com/twix/domain/model/goal/GoalList.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.twix.domain.model.goal

data class GoalList(
val completedCount: Int = 0,
val totalCount: Int = 0,
val goals: List<Goal> = emptyList(),
)
Loading