Skip to content
Open
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
16 changes: 16 additions & 0 deletions app/src/main/java/umc/OnAirMate/data/api/NicknameService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package umc.onairmate.data.api
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

패키지-디렉터리 대소문자 불일치: OnAirMate vs onairmate

서비스 인터페이스 파일 경로 또한 umc/OnAirMate/...로 보입니다. 패키지 선언(umc.onairmate...)과 일치하도록 디렉터리를 umc/onairmate/...로 이동해 주세요.


아래 스크립트를 실행하여 실제 디렉터리 명칭이 패키지 선언과 일치하는지 확인해주세요.


🏁 Script executed:

#!/bin/bash
# NicknameService.kt 파일 위치 확인
echo "🔍 NicknameService.kt 위치:"
find app/src/main/java -type f -name "NicknameService.kt"
echo ""

# umc 디렉터리 하위 구조 및 대소문자 확인
echo "📂 app/src/main/java/umc 하위 디렉터리 목록:"
find app/src/main/java/umc -maxdepth 3 -type d | sort

Length of output: 1528


파일 경로 대소문자 불일치 수정 필요

현재 app/src/main/java/umc/OnAirMate/data/api/NicknameService.kt 파일의 패키지 선언은

package umc.onairmate.data.api

로, 디렉터리 이름(OnAirMate)과 맞지 않습니다.

  • 이동 대상 파일
    • 기존 경로: app/src/main/java/umc/OnAirMate/data/api/NicknameService.kt
    • 수정 경로: app/src/main/java/umc/onairmate/data/api/NicknameService.kt

위와 같이 디렉터리 이름을 모두 소문자(onairmate)로 변경해 패키지 선언과 일치하도록 조치해주세요.

🤖 Prompt for AI Agents
In app/src/main/java/umc/OnAirMate/data/api/NicknameService.kt around line 1,
the package declaration uses all-lowercase "umc.onairmate.data.api" but the
directory is named "OnAirMate"; rename the filesystem directory
app/src/main/java/umc/OnAirMate to app/src/main/java/umc/onairmate (or move the
file into that all-lowercase path) so the package declaration and directory
structure match, then verify imports/build run; do not change the package line
if you perform the directory rename.


import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.PUT
import retrofit2.http.Path
import umc.onairmate.data.model.response.NicknameResponse
import umc.onairmate.data.model.response.RawDefaultResponse

interface NicknameService {
@GET("auth/check-nickname/{nickname}")
suspend fun checkNickname(
@Path("nickname") nickname: String
): NicknameResponse
}
11 changes: 11 additions & 0 deletions app/src/main/java/umc/OnAirMate/data/model/entity/NicknameData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package umc.onairmate.data.model.entity
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

패키지-디렉터리 대소문자 불일치: OnAirMate vs onairmate

현재 파일 경로가 app/src/main/java/umc/OnAirMate/... 형태인데, 패키지는 umc.onairmate...입니다. 대소문자 불일치가 CI/리눅스(대소문자 구분 파일시스템)에서 컴파일 실패, 중복 패키지 생성, IDE 인덱싱 문제를 야기합니다. 동일한 소스셋 내 모든 경로를 umc/onairmate/...로 통일해 주세요(필요 시 git mv로 경로 정정).


다음 스크립트를 실행하여 디렉터리 경로와 패키지 선언의 대소문자 불일치 여부를 확인해 주세요.


🏁 Script executed:

#!/bin/bash
# umc 디렉터리 하위 구조 확인
find app/src/main/java/umc -maxdepth 4 -type d
echo "-----"
# 해당 파일의 패키지 선언 확인
head -n 5 app/src/main/java/umc/OnAirMate/data/model/entity/NicknameData.kt || true

Length of output: 2598


패키지 경로 대소문자 통일 필요

app/src/main/java/umc/OnAirMate/... 디렉터리 구조가 패키지 선언(umc.onairmate…)과 불일치하여 CI/리눅스 환경에서 컴파일 오류를 유발합니다. 모든 소스셋 경로를 소문자 umc/onairmate/...로 변경해야 합니다.

수정 안내:

  • 현재 위치:
    • app/src/main/java/umc/OnAirMate/...
    • package 선언: umc.onairmate…
  • 변경 대상:
    • 디렉터리명 OnAirMateonairmate
    • 하위 모든 경로(data, ui, module 등)
  • 작업 예시:
    git mv app/src/main/java/umc/OnAirMate app/src/main/java/umc/onairmate
  • 변경 후, IDE나 빌드 스크립트에서 import 경로가 모두 소문자 패키지로 참조되는지 확인 바랍니다.
🤖 Prompt for AI Agents
app/src/main/java/umc/OnAirMate around lines 1-1: the filesystem path uses
"OnAirMate" while the package declaration is "umc.onairmate", causing
case-mismatch compile errors on CI/Linux; rename the top-level directory to
lowercase (onairmate) and apply the same lowercase change recursively to all
subdirectories (data, ui, module, etc.), update any affected import/package
references in source files and build scripts/IDE settings if necessary, refresh
the project/IDE and run a build to confirm fixes, then commit the renamed paths.


import com.google.gson.annotations.SerializedName

data class NicknameData(
@SerializedName("available")
val available: Boolean,

@SerializedName("message")
val message: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package umc.onairmate.data.model.response
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

패키지-디렉터리 대소문자 불일치: OnAirMate vs onairmate

이 파일도 경로가 umc/OnAirMate/...로 올라와 있습니다. 패키지와 디렉터리 경로를 모두 umc/onairmate/...로 정렬하지 않으면 플랫폼에 따라 빌드가 깨질 수 있습니다.


아래 스크립트를 실행해서 app/src/main/java/umc 하위 디렉터리 구조 및 NicknameResponse.kt 파일 경로를 확인해주세요.


🏁 Script executed:

#!/bin/bash
echo "📂 app/src/main/java/umc 하위 디렉터리 리스트:"
find app/src/main/java/umc -type d | sed 's/^/ - /'

echo ""
echo "📄 NicknameResponse.kt 위치 확인:"
find app/src/main/java/umc -type f -name "NicknameResponse.kt" -print

Length of output: 2852


경로·패키지 대소문자 불일치 수정 필요

Linux 등 대소문자를 구분하는 파일시스템에서 빌드가 깨질 수 있습니다.
아래 작업을 통해 디렉터리 경로와 package 선언을 모두 소문자(umc/onairmate/...)로統一하세요.

• 디렉터리명 변경

  • app/src/main/java/umc/OnAirMate/…app/src/main/java/umc/onairmate/…
    • Kotlin 파일 위치 이동
  • app/src/main/java/umc/OnAirMate/data/model/response/NicknameResponse.kt
    app/src/main/java/umc/onairmate/data/model/response/NicknameResponse.kt
    package 선언 및 임포트 경로 수정
- package umc.onairmate.data.model.response
+ package umc.onairmate.data.model.response

(이외 관련된 모든 파일의 경로 및 패키지 선언도 함께 정렬)

위 변경 후 반드시 전체 빌드 및 의존 관계를 확인해주세요.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In app/src/main/java/umc/OnAirMate/data/model/response/NicknameResponse.kt
around line 1, the package path uses mixed case ("umc.OnAirMate") which will
break builds on case-sensitive filesystems; rename the directory
app/src/main/java/umc/OnAirMate to app/src/main/java/umc/onairmate, move this
Kotlin file to the new lowercase path, update the package declaration at the top
of the file to "package umc.onairmate.data.model.response", and update any
import statements and other files referencing the old package to the new
lowercase package; after changes run a full clean build to verify and fix any
remaining references.


import com.google.gson.annotations.SerializedName
import umc.onairmate.data.model.entity.NicknameData

class NicknameResponse (
@SerializedName("success")
val success: Boolean,

@SerializedName("data")
val data: NicknameData
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package umc.onairmate.data.repository

interface NicknameRepository {
suspend fun isNicknameDuplicated(nickname: String): Boolean
}
Comment on lines +1 to +5
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

패키지/디렉터리 구조 불일치 가능성(가독성 및 유지보수 관점).

파일 경로가 .../OnAirMate/.../repository/repository/NicknameRepository.kt처럼 보이는데, 패키지는 umc.onairmate.data.repository입니다. 디렉터리 대소문자/중복(segment: repository/repository) 불일치는 IDE 네비게이션과 팀 컨벤션 면에서 혼란을 야기할 수 있습니다. 패키지 구조와 폴더 구조를 일치시키는 것을 권장합니다.

검증 스크립트:


🏁 Script executed:

#!/bin/bash
# Kotlin 소스의 패키지 선언과 실제 디렉토리 구조 불일치 의심 지점 탐색
echo "== Package declarations vs path hints =="
fd -e kt | rg -n 'package\\s+umc\\.onairmate\\.' -N

Length of output: 144


🏁 Script executed:

#!/bin/bash
echo "== NicknameRepository.kt 파일 위치 확인 =="
fd -e kt NicknameRepository.kt

echo ""
echo "== 패키지 선언 확인 (파일 상단 5줄) =="
fd -e kt NicknameRepository.kt -x sed -n '1,5p' {}

echo ""
echo "== 디렉터리 구조 확인 =="
fd -e kt NicknameRepository.kt -x dirname {}

Length of output: 622


패키지 경로와 디렉터리 구조 불일치 수정 필요

현재 app/src/main/java/umc/OnAirMate/data/repository/repository/NicknameRepository.kt 경로가
package umc.onairmate.data.repository 선언과 맞지 않습니다. Java/Kotlin 패키지 네이밍 컨벤션에 따라:

  • 디렉터리명은 모두 소문자여야 합니다 (OnAirMateonairmate).
  • 중복된 repository 디렉터리를 제거해 패키지 구조를 일치시켜야 합니다.

수정 제안:

  • app/src/main/java/umc/OnAirMate 폴더명 → app/src/main/java/umc/onairmate
  • .../repository/repository/NicknameRepository.kt 파일을 .../repository/NicknameRepository.kt로 이동
🤖 Prompt for AI Agents
In
app/src/main/java/umc/OnAirMate/data/repository/repository/NicknameRepository.kt
(lines 1-5) the declared package "umc.onairmate.data.repository" does not match
the filesystem path (contains "OnAirMate" with uppercase and a duplicated
"repository" directory); move the file to
app/src/main/java/umc/onairmate/data/repository/NicknameRepository.kt (rename
the OnAirMate folder to onairmate and remove the extra repository directory) so
the directory structure matches the package declaration, and verify the package
line remains "package umc.onairmate.data.repository" after the move.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package umc.onairmate.data.repository.repositoryImpl

import android.util.Log
import umc.onairmate.data.api.NicknameService
import umc.onairmate.data.repository.NicknameRepository
import javax.inject.Inject

class NicknameRepositoryImpl @Inject constructor(
private val api: NicknameService
): NicknameRepository {

override suspend fun isNicknameDuplicated(nickname: String): Boolean {
return try {
val response = api.checkNickname(nickname)
// available == true 면 사용 가능한 닉네임, 중복 아님 → 따라서 중복 여부는 반대(!)
!response.data.available
} catch (e: Exception) {
Log.e("NicknameRepository", "닉네임 중복 검사 실패", e)
// 실패 시 기본값 false 또는 true 선택 가능 (보통 실패는 중복 아님 false로 처리)
false
}
Comment on lines +17 to +21
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

예외 처리 로직 검토 필요

네트워크 오류나 서버 응답 파싱 실패 시 false를 반환하여 "중복 아님"으로 처리하는 것은 보안상 위험할 수 있습니다. 사용자가 이미 사용 중인 닉네임을 사용할 수 있게 되는 경우가 발생할 수 있습니다.

다음과 같이 예외를 상위로 전파하거나 명확한 오류 상태를 반환하는 것을 권장합니다:

 override suspend fun isNicknameDuplicated(nickname: String): Boolean {
-    return try {
+    try {
         val response = api.checkNickname(nickname)
         // available == true 면 사용 가능한 닉네임, 중복 아님 → 따라서 중복 여부는 반대(!)
-        !response.data.available
+        return !response.data.available
     } catch (e: Exception) {
         Log.e("NicknameRepository", "닉네임 중복 검사 실패", e)
-        // 실패 시 기본값 false 또는 true 선택 가능 (보통 실패는 중복 아님 false로 처리)
-        false
+        throw e // 상위에서 처리하도록 전파
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (e: Exception) {
Log.e("NicknameRepository", "닉네임 중복 검사 실패", e)
// 실패 시 기본값 false 또는 true 선택 가능 (보통 실패는 중복 아님 false로 처리)
false
}
override suspend fun isNicknameDuplicated(nickname: String): Boolean {
try {
val response = api.checkNickname(nickname)
// available == true 면 사용 가능한 닉네임, 중복 아님 → 따라서 중복 여부는 반대(!)
return !response.data.available
} catch (e: Exception) {
Log.e("NicknameRepository", "닉네임 중복 검사 실패", e)
throw e // 상위에서 처리하도록 전파
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class ChatRoomFragment : Fragment() {
lifecycle.addObserver(youtubePlayer)

youtubePlayer.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
override fun onReady(youTubePlayer: YouTubePlayer) {\
override fun onReady(youTubePlayer: YouTubePlayer) {
val videoId = roomData.videoId ?: "CgCVZdcKcqY"
youTubePlayer.loadVideo(videoId, 0f) // todo: RoomData duration 연동
}
Expand Down
119 changes: 119 additions & 0 deletions app/src/main/java/umc/OnAirMate/ui/pop_up/ChangeNicknamePopup.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package umc.onairmate.ui.pop_up

import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import umc.onairmate.R
import umc.onairmate.data.repository.NicknameRepository
import umc.onairmate.databinding.PopupChangeNicknameBinding
import javax.inject.Inject

@AndroidEntryPoint
class ChangeNicknamePopup : BottomSheetDialogFragment() {

private var _binding: PopupChangeNicknameBinding? = null
private val binding get() = _binding!!

// 외부에서 중복 체크를 처리하기 위한 콜백 람다 추가
var onCheckNickname: ((String, (Boolean) -> Unit) -> Unit)? = null

// @Inject
// lateinit var repository: NicknameRepository
Comment on lines +30 to +31
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

주석 처리된 핵심 기능 활성화 필요

닉네임 중복 확인의 핵심 기능인 NicknameRepository 주입이 주석 처리되어 있어 실제 중복 확인이 불가능한 상태입니다. 이는 PR 목표에서 언급된 Hilt 바인딩 오류와 관련이 있을 수 있습니다.

다음 스크립트로 Hilt 모듈 구성을 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# Description: Hilt 모듈 구성 및 NicknameRepository 바인딩 확인

echo "=== ServiceModule에서 NicknameService 제공 확인 ==="
rg -A 5 "fun.*nicknameApi|fun.*NicknameService" --type kt

echo "=== RepositoryModule에서 NicknameRepository 제공 확인 ==="
rg -A 5 "fun.*providesNicknameRepository" --type kt

echo "=== Application 클래스 Hilt 어노테이션 확인 ==="
rg -A 3 "@HiltAndroidApp" --type kt

echo "=== NicknameRepository 인터페이스 정의 확인 ==="
rg -A 5 "interface NicknameRepository" --type kt

Length of output: 694


다음 스크립트로 Hilt 모듈 구성과 NicknameRepository 바인딩을 재확인해보겠습니다.


🏁 Script executed:

#!/usr/bin/env bash
# Hilt 모듈 및 리포지토리 정의 확인

echo "=== NicknameRepository 인터페이스 정의 ==="
rg -n "interface NicknameRepository" --glob "*.kt"

echo "=== provides.*NicknameRepository 바인딩 ==="
rg -n "provides.*NicknameRepository" --glob "*.kt"

echo "=== nicknameApi 또는 NicknameService 제공 ==="
rg -n "nicknameApi" --glob "*.kt"
rg -n "NicknameService" --glob "*.kt"

echo "=== Application 클래스 @HiltAndroidApp 어노테이션 ==="
rg -n "@HiltAndroidApp" --glob "*.kt"

Length of output: 1832


ChangeNicknamePopup에 NicknameRepository 주입 복원 필요

현재 ChangeNicknamePopup.kt에서 핵심 기능인 NicknameRepository 주입이 주석 처리되어 있어 중복 확인 API 호출이 불가능합니다. Hilt 모듈(ServiceModule, RepositoryModule), @HiltAndroidApp 애노테이션, NicknameRepository 인터페이스 및 구현은 모두 정상적으로 설정되어 있으므로, 아래와 같이 주석을 해제하고 의존성 주입을 활성화해야 합니다.

• 대상 파일:

  • app/src/main/java/umc/OnAirMate/ui/pop_up/ChangeNicknamePopup.kt

• 수정 예시:

@@ ChangeNicknamePopup.kt (27-28)
-//    @Inject
-//    lateinit var repository: NicknameRepository
+    @Inject
+    lateinit var repository: NicknameRepository

위 변경 후 ChangeNicknamePopup 클래스에 @AndroidEntryPoint(또는 팝업을 띄우는 컴포넌트에) 애노테이션이 올바르게 적용되었는지 재확인해 주세요.

🤖 Prompt for AI Agents
In app/src/main/java/umc/OnAirMate/ui/pop_up/ChangeNicknamePopup.kt around lines
27-28, the NicknameRepository injection is commented out so the popup cannot
call the duplicate-check API; restore the dependency injection by uncommenting
the @Inject lateinit var repository: NicknameRepository line (or re-add
equivalent constructor/property injection), ensure the class (or the hosting
Activity/Fragment that shows the popup) is annotated with @AndroidEntryPoint,
and confirm Hilt modules/providers remain registered so the repository is
injected at runtime.



override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = PopupChangeNicknameBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.editNickname.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
val input = s.toString()
val isValid = input.length in 3..10

binding.checkNickname.setBackgroundResource(
if (isValid) R.drawable.bg_btn_main
else R.drawable.bg_btn_disabled
)
binding.checkNickname.isEnabled = isValid
}

override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})

binding.checkNickname.setOnClickListener {
val nickname = binding.editNickname.text.toString()

if (nickname.length !in 3..10) {
Toast.makeText(requireContext(), "닉네임은 3자 이상 10자 이하여야 합니다.", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}

// 외부 콜백 호출해서 중복 검사 요청
onCheckNickname?.invoke(nickname) { isDuplicated ->
if (isDuplicated) {
Toast.makeText(requireContext(), "이미 사용 중인 닉네임입니다.", Toast.LENGTH_SHORT).show()
binding.editNickname.text?.clear()
binding.checkNickname.setBackgroundResource(R.drawable.bg_btn_disabled)
binding.checkNickname.isEnabled = false
} else {
Toast.makeText(requireContext(), "사용 가능한 닉네임입니다!", Toast.LENGTH_SHORT).show()
}
}

/*
viewLifecycleOwner.lifecycleScope.launch {
val isDuplicated = withContext(Dispatchers.IO) {
repository.isNicknameDuplicated(nickname)
}

if (isDuplicated) {
Toast.makeText(requireContext(), "이미 사용 중인 닉네임입니다.", Toast.LENGTH_SHORT).show()
binding.editNickname.text.clear()
binding.checkNickname.setBackgroundResource(R.drawable.bg_btn_disabled)
binding.checkNickname.isEnabled = false
} else {
Toast.makeText(requireContext(), "사용 가능한 닉네임입니다!", Toast.LENGTH_SHORT).show()
}
}
*/

// viewLifecycleOwner.lifecycleScope.launch {
// val isDuplicated = withContext(Dispatchers.IO) {
// repository.isNicknameDuplicated(nickname)
// }
//
// if (isDuplicated) {
// Toast.makeText(requireContext(), "이미 사용 중인 닉네임입니다.", Toast.LENGTH_SHORT).show()
// binding.editNickname.text.clear()
// binding.checkNickname.setBackgroundResource(R.drawable.bg_btn_disabled)
// binding.checkNickname.isEnabled = false
// } else {
// Toast.makeText(requireContext(), "사용 가능한 닉네임입니다!", Toast.LENGTH_SHORT).show()
// }
// }
}
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package umc.onairmate.ui.pop_up

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
import umc.onairmate.data.repository.NicknameRepository

@HiltViewModel
class ChangeNicknameViewModel @Inject constructor(
private val nicknameRepository: NicknameRepository
) : ViewModel() {

// 닉네임 중복 확인 결과를 콜백으로 전달하거나 LiveData로 관리 가능
fun checkNickname(
nickname: String,
onResult: (Boolean) -> Unit
) {
viewModelScope.launch {
try {
val isDuplicated = nicknameRepository.isNicknameDuplicated(nickname)
onResult(isDuplicated)
} catch (e: Exception) {
// 에러 처리 필요하면 여기서
onResult(false) // 중복 아님으로 처리하거나 별도 처리
}
Comment on lines +24 to +27
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

예외 처리 개선 필요

현재 예외 발생 시 false를 반환하여 "중복 아님"으로 처리하고 있는데, 이는 사용자에게 잘못된 정보를 제공할 수 있습니다. 네트워크 오류나 서버 오류 시 사용자가 적절한 피드백을 받을 수 있도록 개선이 필요합니다.

다음과 같이 개선하는 것을 권장합니다:

 fun checkNickname(
     nickname: String,
-    onResult: (Boolean) -> Unit
+    onResult: (Boolean?, String?) -> Unit
 ) {
     viewModelScope.launch {
         try {
             val isDuplicated = nicknameRepository.isNicknameDuplicated(nickname)
-            onResult(isDuplicated)
+            onResult(isDuplicated, null)
         } catch (e: Exception) {
-            // 에러 처리 필요하면 여기서
-            onResult(false) // 중복 아님으로 처리하거나 별도 처리
+            Log.e("ChangeNicknameViewModel", "닉네임 중복 확인 실패", e)
+            onResult(null, "네트워크 오류가 발생했습니다. 다시 시도해주세요.")
         }
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (e: Exception) {
// 에러 처리 필요하면 여기서
onResult(false) // 중복 아님으로 처리하거나 별도 처리
}
fun checkNickname(
nickname: String,
onResult: (Boolean?, String?) -> Unit
) {
viewModelScope.launch {
try {
val isDuplicated = nicknameRepository.isNicknameDuplicated(nickname)
onResult(isDuplicated, null)
} catch (e: Exception) {
Log.e("ChangeNicknameViewModel", "닉네임 중복 확인 실패", e)
onResult(null, "네트워크 오류가 발생했습니다. 다시 시도해주세요.")
}
}
}
🧰 Tools
🪛 detekt (1.23.8)

[warning] 24-24: The caught exception is swallowed. The original exception could be lost.

(detekt.exceptions.SwallowedException)

🤖 Prompt for AI Agents
In app/src/main/java/umc/OnAirMate/ui/pop_up/ChangeNicknameViewModel.kt around
lines 24 to 27, the catch block currently treats any exception as "not
duplicate" by calling onResult(false); change it to surface real errors instead:
catch specific exceptions (e.g., IOException, HttpException) and handle them by
logging the exception and calling an error reporting path (either call a new
onError callback or pass a distinct error/result value instead of false), and
only return false when the server response explicitly indicates "not duplicate";
ensure you do not swallow exceptions silently so the UI can show proper
network/server error feedback.

}
}
}
20 changes: 15 additions & 5 deletions app/src/main/java/umc/onairmate/module/RepositoryModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ import dagger.hilt.android.scopes.ViewModelScoped
import umc.onairmate.data.api.FriendService
import umc.onairmate.data.api.ChatRoomService
import umc.onairmate.data.api.HomeService
import umc.onairmate.data.api.NicknameService
import umc.onairmate.data.api.TestService
import umc.onairmate.data.repository.NicknameRepository
Comment on lines +11 to +13
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

패키지 경로 불일치로 인한 Hilt 바인딩 오류 가능성

NicknameServiceNicknameRepository의 import 패키지 경로가 다른 패키지 구조를 따르고 있습니다. 이는 PR 목표에서 언급된 Hilt 바인딩 오류의 원인일 수 있습니다.

다음 스크립트를 실행하여 패키지 구조 일관성을 확인해보겠습니다:

#!/bin/bash
# Description: 닉네임 관련 클래스들의 패키지 구조 일관성 확인

echo "=== NicknameService 클래스 위치 확인 ==="
fd -t f "NicknameService.kt"

echo "=== NicknameRepository 인터페이스 위치 확인 ==="
fd -t f "NicknameRepository.kt"

echo "=== NicknameRepositoryImpl 구현체 위치 확인 ==="
fd -t f "NicknameRepositoryImpl.kt"

echo "=== 각 파일의 패키지 선언 확인 ==="
fd -t f -e kt -x grep -H "^package" {} \; | grep -E "(NicknameService|NicknameRepository)"

Also applies to: 21-21

🤖 Prompt for AI Agents
In app/src/main/java/umc/onairmate/module/RepositoryModule.kt around lines 11-13
(and also check line 21), the imports for NicknameService and NicknameRepository
reference different package paths which can break Hilt bindings; make package
paths consistent by either updating the import statements to match the actual
package declarations of those classes, or by moving/adjusting the package
declarations of the classes so they share the expected package, then rebuild to
ensure Hilt can find the bindings; run the provided shell checks to confirm file
locations and package declarations and update RepositoryModule.kt imports
accordingly.

import umc.onairmate.data.repository.repository.FriendRepository
import umc.onairmate.data.repository.repository.ChatRoomRepository
import umc.onairmate.data.repository.repository.HomeRepository
import umc.onairmate.data.repository.repository.TestRepository
import umc.onairmate.data.repository.repositoryImpl.FriendRepositoryImpl
import umc.onairmate.data.repository.repositoryImpl.ChatRoomRepositoryImpl
import umc.onairmate.data.repository.repositoryImpl.HomeRepositoryImpl
import umc.onairmate.data.repository.repositoryImpl.NicknameRepositoryImpl
import umc.onairmate.data.repository.repositoryImpl.TestRepositoryImpl

@Module
Expand All @@ -26,22 +29,29 @@ object RepositoryModule {
@Provides
fun providesHomeRepository(
homeService: HomeService
) : HomeRepository = HomeRepositoryImpl(homeService)
): HomeRepository = HomeRepositoryImpl(homeService)

@ViewModelScoped
@Provides
fun providesTestRepository(
testService: TestService
) : TestRepository = TestRepositoryImpl(testService)
): TestRepository = TestRepositoryImpl(testService)

@ViewModelScoped
@Provides
fun providesFriendRepository(
friendService: FriendService
) : FriendRepository = FriendRepositoryImpl(friendService)
): FriendRepository = FriendRepositoryImpl(friendService)

@ViewModelScoped
@Provides
fun providesChatRoomRepository(
chatRoomService: ChatRoomService
) : ChatRoomRepository = ChatRoomRepositoryImpl(chatRoomService)
}
): ChatRoomRepository = ChatRoomRepositoryImpl(chatRoomService)

@ViewModelScoped
@Provides
fun providesNicknameRepository(
nicknameService: NicknameService
): NicknameRepository = NicknameRepositoryImpl(nicknameService)
}
7 changes: 7 additions & 0 deletions app/src/main/java/umc/onairmate/module/ServiceModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import retrofit2.Retrofit
import umc.onairmate.data.api.ChatRoomService
import umc.onairmate.data.api.FriendService
import umc.onairmate.data.api.HomeService
import umc.onairmate.data.api.NicknameService
import umc.onairmate.data.api.TestService
import javax.inject.Singleton

Expand Down Expand Up @@ -44,4 +45,10 @@ object ServiceModule {
fun friendApi(@NetworkModule.BaseRetrofit retrofit: Retrofit): FriendService{
return retrofit.buildService()
}

@Provides
@Singleton
fun nicknameApi(@NetworkModule.BaseRetrofit retrofit: Retrofit): NicknameService {
return retrofit.buildService()
}
Comment on lines +49 to +53
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Hilt MissingBinding 에러 원인 가능성 정리 및 제안 수정

보고된 에러([Dagger/MissingBinding] umc.onairmate.data.repository.NicknameRepository cannot be provided)는 다음 두 가지 중 하나일 가능성이 높습니다:

  1. Repository 모듈의 설치 컴포넌트 불일치
  • NicknameRepository 바인딩이 @InstallIn(ViewModelComponent::class) 등 하위 컴포넌트에만 설치되어 있고, 상위 컴포넌트(SingletonComponent)에서 요구되어 실패했을 수 있습니다.
  • 해결: RepositoryModule@InstallIn(SingletonComponent::class)로 변경하고, @Binds @Singleton 바인딩을 사용하세요.
  1. 패키지 경로/이름 불일치
  • 에러가 가리키는 타입: umc.onairmate.data.repository.NicknameRepository
  • PR 구조상 인터페이스/구현이 data/repository/repository, data/repository/repositoryImpl 등 중첩된 패키지에 위치할 수 있습니다.
  • 주입 지점이 umc.onairmate.data.repository.NicknameRepository를 import하는데, 모듈 바인딩/구현 클래스가 umc.onairmate.data.repository.repository.NicknameRepository를 대상으로 하면 바인딩이 성립하지 않습니다.
  • 해결: 인터페이스/구현/모듈 모두 동일한 패키지 선언(예: umc.onairmate.data.repository)로 정렬.

권장 바인딩 예시:

// RepositoryModule.kt
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
    @Binds
    @Singleton
    abstract fun bindNicknameRepository(
        impl: NicknameRepositoryImpl
    ): NicknameRepository
}

또한, Fragment/Popup 등 UI 레이어에서 NicknameRepository를 직접 주입하지 말고, @HiltViewModel에만 주입하도록 경로를 단순화하면 컴포넌트 경계 문제를 줄일 수 있습니다.

다음 스크립트로 실제 패키지/컴포넌트 불일치 여부를 확인해 보세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate NicknameRepository interface =="
fd -a 'NicknameRepository.kt' | sed 's/^/ - /'
echo

echo "== Packages of NicknameRepository =="
fd -a 'NicknameRepository.kt' | xargs -I{} sh -c 'echo "{}"; rg -n "^package " "{}"; echo'
echo

echo "== Locate NicknameRepositoryImpl and annotations =="
fd -a 'NicknameRepositoryImpl.kt' | xargs -I{} sh -c 'echo "{}"; rg -n "^package |@Inject|class\\s+NicknameRepositoryImpl" "{}"; echo' || true
echo

echo "== RepositoryModule @InstallIn target and bindings =="
fd -a 'RepositoryModule.kt' | xargs -I{} sh -c 'echo "{}"; rg -n "@InstallIn\\(|@Module|@Binds|@Provides|@Singleton" "{}"; echo' || true
echo

echo "== Import sites for NicknameRepository (check for mismatched packages) =="
rg -n "import\\s+umc\\.onairmate\\.data\\.repository\\.NicknameRepository" || true
rg -n "import\\s+umc\\.onairmate\\.data\\.repository\\.repository\\.NicknameRepository" || true
echo

echo "== Check directory case mismatch under java/ =="
fd -t d 'OnAirMate' ./app/src/main/java || true
fd -t d 'onairmate' ./app/src/main/java || true
echo

echo "== Confirm ServiceModule provides NicknameService with BaseRetrofit =="
fd -a 'ServiceModule.kt' | xargs -I{} sh -c 'echo "{}"; rg -n "NicknameService|BaseRetrofit" "{}"; echo' || true
echo

echo "== ChangeNicknamePopup usage (ensure repository not injected directly) =="
fd -a 'ChangeNicknamePopup.kt' | xargs -I{} sh -c 'echo "{}"; rg -n "@AndroidEntryPoint|NicknameRepository|by\\s+viewModels|@HiltViewModel" "{}"; echo' || true

Length of output: 4033


UI 레이어에서 Repository 직접 주입 제거 및 ViewModelComponent 유지

현재 RepositoryModule@InstallIn(ViewModelComponent::class)로 ViewModel 범위 내에서 NicknameRepository 바인딩을 정상 제공하고 있으므로, 모듈 설치 컴포넌트를 변경할 필요는 없습니다. MissingBinding 에러는 UI 팝업(ChangeNicknamePopup.kt)에서 직접 Repository를 주입하려 시도했기 때문입니다. 다음과 같이 수정하세요.

  • app/src/main/java/umc/onairmate/module/RepositoryModule.kt
    @InstallIn(ViewModelComponent::class) 유지 (ViewModelComponent 내에서만 바인딩됨)

  • app/src/main/java/umc/OnAirMate/ui/pop_up/ChangeNicknamePopup.kt
    import umc.onairmate.data.repository.NicknameRepository 삭제
    • 주석 처리된 lateinit var repository: NicknameRepository 블록 완전히 제거
    • 팝업에서는 by viewModels<ChangeNicknameViewModel>() 로 ViewModel을 얻어 사용

  • app/src/main/java/umc/OnAirMate/ui/pop_up/ChangeNicknameViewModel.kt
    @HiltViewModel 애노테이션 클래스에
    @Inject constructor(private val repository: NicknameRepository) 추가
    • ViewModel 내부 메서드로 Notification 로직 및 Repository 호출 처리

(선택) Repository를 앱 전역 싱글톤으로 사용하려면, 위 RepositoryModule

@InstallIn(SingletonComponent::class)
@Module
abstract class RepositoryModule {
  @Binds @Singleton abstract fun bindNicknameRepository(
    impl: NicknameRepositoryImpl
  ): NicknameRepository
}

처럼 SingletonComponent + @Binds/@Singleton으로 변경할 수 있습니다.

🤖 Prompt for AI Agents
In app/src/main/java/umc/onairmate/module/ServiceModule.kt around lines 49-53
and related UI files: the MissingBinding error is caused by injecting the
Repository directly into the popup UI instead of using a ViewModel; keep
RepositoryModule installed in ViewModelComponent, remove the direct import of
NicknameRepository and delete the commented/lateinit repository field from
ChangeNicknamePopup, obtain the ViewModel in the popup via by
viewModels<ChangeNicknameViewModel>() and call its methods for
notification/repository operations, and update ChangeNicknameViewModel by
annotating with @HiltViewModel and adding an @Inject constructor(private val
repository: NicknameRepository) so the repository is provided into the
ViewModel; optionally, if you want a global singleton repository instead, change
RepositoryModule to @InstallIn(SingletonComponent::class) and bind it with
@Binds @Singleton.

}
Loading