Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 10 additions & 11 deletions app/src/main/java/kr/co/call/callfromai/AppScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
Expand All @@ -28,6 +26,7 @@ import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
import androidx.navigation3.ui.NavDisplay
import kr.co.call.api.CallRecordNavKey
import kr.co.call.api.CharacterManagementNavKey
import kr.co.call.api.ChatRoomNavKey
import kr.co.call.api.ChattingNavKey
import kr.co.call.api.FaqNavKey
Expand All @@ -37,13 +36,13 @@ import kr.co.call.api.MyPageNavKey
import kr.co.call.api.TermNavKey
import kr.co.call.callfromai.ui.MainBottomBar
import kr.co.call.callfromai.ui.MainTab
import kr.co.call.callfromai.util.toMainTab
import kr.co.call.designsystem.component.LocalBottomBarPadding
import kr.co.call.impl.entry.chattingEntry
import kr.co.call.impl.entry.homeEntry
import kr.co.call.impl.entry.loginEntry
import kr.co.call.impl.entry.myPageEntry
import kr.co.call.impl.entry.onboardingEntry
import kr.co.call.callfromai.util.toMainTab

/**
* 애플리케이션 화면 내비게이션의 메인 진입점입니다.
Expand Down Expand Up @@ -89,20 +88,19 @@ fun AppScreen(modifier: Modifier = Modifier) {
modifier = modifier.fillMaxSize(),
bottomBar = {
if (showBottomBar) {
MainBottomBar(
currentTab = currentTab,
onTabSelected = appNavigator::navigateToTab,
modifier = Modifier
.onSizeChanged { bottomBarHeightPx = it.height },
)
MainBottomBar(
currentTab = currentTab,
onTabSelected = appNavigator::navigateToTab,
modifier = Modifier
.onSizeChanged { bottomBarHeightPx = it.height },
)
}
},
contentWindowInsets = WindowInsets.safeDrawing
.only(WindowInsetsSides.Bottom + WindowInsetsSides.Horizontal)
.exclude(WindowInsets.ime),

) {
padding ->
) { padding ->
CompositionLocalProvider(
LocalBottomBarPadding provides if (showBottomBar) bottomBarPadding else 0.dp,
) {
Expand Down Expand Up @@ -138,6 +136,7 @@ fun AppScreen(modifier: Modifier = Modifier) {
myPageEntry(
navigateToFaq = { appNavigator.navigate(FaqNavKey) },
navigateToTerms = { appNavigator.navigate(TermNavKey) },
navigateToCharacterManagement = { appNavigator.navigate(CharacterManagementNavKey) },
onBack = { appNavigator.popBackStack() },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kr.co.call.data.repositoryImpl.AICharacterRepositoryImpl
import javax.inject.Singleton
import kr.co.call.data.repositoryImpl.CallRecordMockRepository
import kr.co.call.data.repositoryImpl.FaqRepositoryImpl
import kr.co.call.data.repositoryImpl.ChatRepositoryImpl
import kr.co.call.data.repositoryImpl.HomeMockRepository
import kr.co.call.data.repositoryImpl.MyPageRepositoryImpl
import kr.co.call.domain.repository.AICharacterRepository
import kr.co.call.domain.repository.CallRecordRepository
import kr.co.call.domain.repository.ChatRepository
import kr.co.call.domain.repository.HomeRepository
import kr.co.call.domain.repository.FaqRepository
import kr.co.call.domain.repository.MyPageRepository


@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
Expand Down Expand Up @@ -44,6 +47,12 @@ abstract class RepositoryModule {
impl: MyPageRepositoryImpl
): MyPageRepository

@Binds
@Singleton
abstract fun bindCharacterRepository(
impl: AICharacterRepositoryImpl
): AICharacterRepository
Comment thread
coderabbitai[bot] marked this conversation as resolved.

@Binds
@Singleton
abstract fun bindFaqRepository(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package kr.co.call.data.repositoryImpl

import kr.co.call.domain.model.mypage.AiCharacter
import kr.co.call.domain.repository.AICharacterRepository
import javax.inject.Inject

// TODO: API 연동 전 임시 구현체
class AICharacterRepositoryImpl @Inject constructor() : AICharacterRepository {

private val aiCharacters = mutableListOf(
AiCharacter(
id = "1", name = "김민준", profileImageUrl = "", isMain = true,
createdAtLabel = "2025.05.26", daysTogetherLabel = "35일 째", lastConversationLabel = "오늘 21:42",
summary = "아이스크림을 커피보다 좋아하며, 늦은 저녁 시간에 대화하는 것을 선호해요. 디자인과 여행 이야기에 관심이 많고, 반말대를 편하게 여겨요.",
),
AiCharacter(
id = "2", name = "박동휘", profileImageUrl = "", isMain = false,
createdAtLabel = "2025.06.19", daysTogetherLabel = "11일 째", lastConversationLabel = "6/29 12:30",
summary = "운동과 액티비티를 좋아하고, 아침 시간대 대화를 선호해요.",
),
AiCharacter(
id = "3", name = "정유나", profileImageUrl = "", isMain = false,
createdAtLabel = "2025.06.25", daysTogetherLabel = "5일 째", lastConversationLabel = "6/28 09:04",
summary = "잔잔한 음악과 독서를 좋아하고, 차분한 대화를 선호해요.",
),
)

override suspend fun getCharacters(): Result<List<AiCharacter>>{
return runCatching {
aiCharacters.toList()
}
}

override suspend fun deleteCharacter(characterId: String): Result<Unit> {
return runCatching {
aiCharacters.removeAll { it.id == characterId }
Unit
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

override suspend fun canAddCharacter(): Result<Boolean> {
// TODO: 마지막 캐릭터 생성 시각 기준 24시간 경과 여부를 판단(백엔드)
return runCatching { false }
Comment on lines +41 to +43

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 5 \
  'canAddCharacter|NavigateToAddCharacter|ShowAddCharacterBlocked' \
  core/data feature

Repository: call-from-ai/CallFromAi_Android

Length of output: 6747


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== repository interface/call sites =="
rg -n -C 3 'fun canAddCharacter\(|suspend fun canAddCharacter|canAddCharacter' --glob '*.kt' .

echo "== repository provider/binding snippets =="
rg -n -C 4 'AICharacterRepository|AIC|RepositoryImpl|Hilt|Provides|Inject' --glob '*.kt' . | sed -n '1,220p'

echo "== module/build dependency hints =="
fd 'build.gradle|build.gradle.kts|settings.gradle|settings.gradle.kts' . -t f -x sh -c 'echo "--- $1"; cat "$1"' sh {}

Repository: call-from-ai/CallFromAi_Android

Length of output: 44761


캐릭터 추가 eligibility 판정한 뒤 반환하도록 수정하세요.

AICharacterRepositoryImpl.canAddCharacter()가 항상 false를 반환하고, 이 구현체가 Hilt Binding을 통해 주입되어 CharacterManagementViewModel.checkAddCharacter()에서 실제 판단 로직 없이 항상 ShowAddCharacterBlocked만 발생시킵니다. 24시간 제한을 실제 데이터/API로 판정하거나, API 연동 전 임시 구현체를 프로덕션 바인딩에서 제외해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/data/src/main/java/kr/co/call/data/repositoryImpl/AICharacterRepositoryImpl.kt`
around lines 40 - 42, Update AICharacterRepositoryImpl.canAddCharacter() to
determine eligibility using the actual character-creation timestamp data or
backend API and return that result instead of always returning false; if
integration is unavailable, remove this placeholder implementation from the
production Hilt binding until a real eligibility check is provided.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
Expand All @@ -19,6 +24,8 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kr.co.call.designsystem.theme.CallFromAiTheme
Expand All @@ -33,6 +40,7 @@ fun SecondaryButton(
text: String,
onClick: () -> Unit,
enabled: Boolean = true,
iconRes: Int? = null,
containerColor: Color = CallTheme.colors.mainVariant4,
contentColor: Color = CallTheme.colors.white,
pressedContainerColor: Color = CallTheme.colors.subPressed3,
Expand Down Expand Up @@ -60,11 +68,22 @@ fun SecondaryButton(
),
contentAlignment = Alignment.Center,
) {
Text(
text = text,
style = CallTheme.typography.bodyMediumMedium,
color = if (enabled) contentColor else contentColor.copy(alpha = 0.38f),
)
val contentTint = if (enabled) contentColor else contentColor.copy(alpha = 0.38f)

if (iconRes != null) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,
tint = contentTint,
modifier = Modifier.size(16.dp),
)
Spacer(modifier = Modifier.width(6.dp))
Text(text = text, style = CallTheme.typography.bodyMediumMedium, color = contentTint)
}
} else {
Text(text = text, style = CallTheme.typography.bodyMediumMedium, color = contentTint)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import kr.co.call.designsystem.theme.CallTheme
fun OneButtonPopup(
modifier: Modifier = Modifier,
label: String,
title: String,
title: String? = null,
buttonText: String,
onButtonClick: () -> Unit,
description: AnnotatedString? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import kr.co.call.designsystem.theme.CallTheme
internal fun PopupCard(
modifier: Modifier = Modifier,
label: String,
title: String,
title: String?,
description: AnnotatedString? = null,
labelSpacerHeight: Dp = 8.dp,
descriptionSpacerHeight: Dp = 8.dp,
Expand All @@ -59,13 +59,16 @@ internal fun PopupCard(
textAlign = TextAlign.Center,
)
Spacer(modifier = Modifier.height(labelSpacerHeight))
Text(
text = title,
style = CallTheme.typography.bodyLargeBold,
color = CallTheme.colors.black,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
if (title != null) {
Spacer(modifier = Modifier.height(labelSpacerHeight))
Text(
text = title,
style = CallTheme.typography.bodyLargeBold,
color = CallTheme.colors.black,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
}
Comment on lines 33 to +71

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 수정한 이유 있나영?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 공통 컴포넌트 PopupCard에서는 title을 강제하고 있는데, [마이페이지>캐릭터 관리] 화면에 아래와 같이 title이 없는 팝업 화면이 존재해서 title을 nullable 하게 변경했었습니당! 혹시 이것두 공통에서는 따로 빼서 컴포넌트 제작하는 편이 더 나을까요?

  • image
  • 참고로 PopupCard에서 title은 아래 보이는 이미지 속 굵은 글자("아직 캐릭터를 수정할 수 없어요") 부분입니다!

  • image

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 코멘트 와 동일합니다!

if (description != null) {
Spacer(modifier = Modifier.height(descriptionSpacerHeight))
Text(
Expand Down
21 changes: 21 additions & 0 deletions core/designsystem/src/main/res/drawable/ic_mypage_edit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:pathData="M20,1.5L20,1.5A18.5,18.5 0,0 1,38.5 20L38.5,20A18.5,18.5 0,0 1,20 38.5L20,38.5A18.5,18.5 0,0 1,1.5 20L1.5,20A18.5,18.5 0,0 1,20 1.5z"
android:fillColor="#FFDCE2"/>
<path
android:pathData="M20,1.5L20,1.5A18.5,18.5 0,0 1,38.5 20L38.5,20A18.5,18.5 0,0 1,20 38.5L20,38.5A18.5,18.5 0,0 1,1.5 20L1.5,20A18.5,18.5 0,0 1,20 1.5z"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#FFFCFC"/>
<path
android:pathData="M12,28.026L16.607,26.273C16.902,26.16 17.049,26.104 17.187,26.031C17.31,25.966 17.427,25.89 17.537,25.806C17.66,25.71 17.772,25.599 17.996,25.377L27.382,16.058C28.301,15.145 28.306,13.66 27.393,12.741C26.481,11.822 24.996,11.817 24.077,12.729L14.691,22.049C14.467,22.271 14.356,22.382 14.259,22.505C14.174,22.615 14.098,22.731 14.032,22.853C13.957,22.99 13.9,23.137 13.786,23.431L12,28.026ZM12,28.026L13.722,23.595C13.845,23.278 13.907,23.12 14.012,23.047C14.104,22.984 14.217,22.961 14.326,22.982C14.452,23.006 14.571,23.127 14.811,23.368L16.678,25.248C16.917,25.489 17.037,25.61 17.061,25.735C17.081,25.845 17.057,25.958 16.993,26.049C16.92,26.154 16.761,26.214 16.443,26.335L12,28.026Z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#FF8AAF"
android:strokeLineCap="round"/>
</vector>
25 changes: 25 additions & 0 deletions core/designsystem/src/main/res/drawable/ic_mypage_trash.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M9,3.5L9.6,2.4C9.783,2.062 10.135,1.85 10.519,1.85H13.481C13.865,1.85 14.217,2.062 14.4,2.4L15,3.5H19C19.414,3.5 19.75,3.836 19.75,4.25C19.75,4.664 19.414,5 19,5H5C4.586,5 4.25,4.664 4.25,4.25C4.25,3.836 4.586,3.5 5,3.5H9Z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M5.7,7H18.3L17.53,19.19C17.443,20.6 16.273,21.7 14.859,21.7H9.141C7.727,21.7 6.557,20.6 6.47,19.19L5.7,7Z"
android:fillColor="#00000000"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.5"
android:strokeLineJoin="round"/>
<path
android:pathData="M9.75,10.5V18"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.5"
android:strokeLineCap="round"/>
<path
android:pathData="M14.25,10.5V18"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.5"
android:strokeLineCap="round"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package kr.co.call.domain.model.mypage

data class AiCharacter(
val id: String= "",
val name: String= "",
val profileImageUrl: String= "",
val isMain: Boolean,
val createdAtLabel: String= "",
val daysTogetherLabel: String= "",
val lastConversationLabel: String= "",
val summary: String= "",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kr.co.call.domain.repository

import kr.co.call.domain.model.mypage.AiCharacter

interface AICharacterRepository {
suspend fun getCharacters(): Result<List<AiCharacter>>
suspend fun deleteCharacter(characterId: String): Result<Unit>
suspend fun canAddCharacter(): Result<Boolean>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import kotlinx.serialization.Serializable
@Serializable
data object MyPageNavKey: NavKey

@Serializable
data object CharacterManagementNavKey: NavKey

@Serializable
data object FaqNavKey : NavKey

Expand Down
Loading