Skip to content

Conversation

@mark77234
Copy link
Collaborator

@mark77234 mark77234 commented Jan 4, 2026

작업내용

기타 작업

  • 스플래시화면(영상) 추가
  • 신토 종교 매핑 에러 수정

홈화면 작업

  • 여자버전 남자 매칭 화면 api 추가 및 연동완료
  • 네비게이션 아이콘 filled 아이콘 추가하기
  • 홈화면 라우터 추가하기
  • 설정 페이지 추가하기
  • 채팅 페이지 추가하기
  • 내정보 페이지 추가하기
  • 홈화면 리팩토링 및 폴더구조 개선
  • 홈화면 UI 업데이트
  • 매칭중입니다 화면 업데이트
  • 남자버전 작업
  • 번역작업

  • 내정보 페이지 추가 -> 예람
  • 채팅 페이지 (매칭을 기다려주세요..) -> 예람
  • 설정 페이지 작업 -> 예람

참고

스크린샷 2026-01-04 오후 4 36 12
  • main/chat/ChatScreen.kt, main/mypage/MypageScreen.kt, main/setting/SettingScreen.kt 작업해주시면 됩니다~

Copilot AI review requested due to automatic review settings January 4, 2026 07:35
@mark77234 mark77234 linked an issue Jan 4, 2026 that may be closed by this pull request
13 tasks
@mark77234 mark77234 self-assigned this Jan 4, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements the female user version of the matching feature with comprehensive navigation and UI updates. The changes introduce a splash screen with video, a complete home screen with carousel-based matching display, and placeholder screens for chat, profile, and settings.

Key changes include:

  • Video splash screen implementation with custom fullscreen video view
  • Complete matching flow with carousel UI and detail views
  • Bottom navigation with home, chat, and profile tabs
  • Logout functionality with proper cleanup

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
app/src/main/res/values/themes.xml Adds splash screen theme with black background
app/src/main/res/layout/activity_splash.xml Layout for splash screen with fullscreen video view
app/src/main/res/drawable/*.xml Navigation icons (filled and outline versions) for user, chat, settings, and home
app/src/main/java/com/apptive/japkor/widget/FullscreenVideoView.kt Custom VideoView that scales video to fill screen while maintaining aspect ratio
app/src/main/java/com/apptive/japkor/utils/required_info/RequiredInfoMapper.kt Updates religion mapping (SHINTO → TOISM)
app/src/main/java/com/apptive/japkor/ui/main/setting/SettingScreen.kt Settings screen with logout button
app/src/main/java/com/apptive/japkor/ui/main/mypage/MypageScreen.kt Placeholder profile page
app/src/main/java/com/apptive/japkor/ui/main/home/HomeViewModel.kt Business logic for fetching and selecting matchings
app/src/main/java/com/apptive/japkor/ui/main/home/HomeScreen.kt Matching carousel UI with detail view
app/src/main/java/com/apptive/japkor/ui/main/chat/ChattingScreen.kt Placeholder chat screen
app/src/main/java/com/apptive/japkor/ui/main/MainRouteScreen.kt Main navigation coordinator with bottom navigation
app/src/main/java/com/apptive/japkor/ui/login/LoginScreen.kt Routes CONNECTING users to home screen
app/src/main/java/com/apptive/japkor/ui/localization/Localization.kt Adds Japanese translations for logout dialog
app/src/main/java/com/apptive/japkor/navigation/AppNavHost.kt Registers home route in navigation graph
app/src/main/java/com/apptive/japkor/data/model/Matching.kt Data model for matching response
app/src/main/java/com/apptive/japkor/data/local/DataStoreManager.kt Adds clearUserInfo method for logout
app/src/main/java/com/apptive/japkor/data/api/ServiceFactory.kt Registers matching service
app/src/main/java/com/apptive/japkor/data/api/MatchingService.kt API interface for matching operations
app/src/main/java/com/apptive/japkor/SplashActivity.kt Activity that plays splash video and navigates to main
app/src/main/java/com/apptive/japkor/LoginCallbackActivity.kt Routes CONNECTING users to home screen
app/src/main/AndroidManifest.xml Sets SplashActivity as launcher activity
app/build.gradle.kts Configures mp4 files as non-compressed resources

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +149 to +166
Button(
onClick = { currentMatching?.let { onShowDetails(it) } },
enabled = currentMatching != null,
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
colors = ButtonDefaults.buttonColors(
containerColor = CustomColor.primary600,
disabledContainerColor = CustomColor.primary300
),
shape = RoundedCornerShape(16.dp)
) {
CustomText(
text = "이 분 프로필이 궁금해요",
type = CustomTextType.body,
color = Color.White
)
}
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The button is enabled based on currentMatching being non-null, but currentMatching is derived from matchings.getOrNull(pagerState.currentPage). If the pager is animating or the state is inconsistent, this could result in the button being enabled when it shouldn't be. Consider checking both conditions explicitly.

Copilot uses AI. Check for mistakes.
if (hasNavigated) return
hasNavigated = true
val intent = Intent(this, MainActivity::class.java)
intent.putExtras(this.intent)
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

Using Intent.putExtras with this.intent could propagate any extras from the original intent. If the SplashActivity is launched with specific extras, they will be passed to MainActivity. Consider explicitly handling which extras should be forwarded or document this behavior.

Suggested change
intent.putExtras(this.intent)

Copilot uses AI. Check for mistakes.
"기독교" -> "CHRISTIANITY"
"천주교" -> "CATHOLICISM"
"신토" -> "SHINTO"
"신토" -> "TOISM"
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The mapping for "신토" (Shinto) has been changed from "SHINTO" to "TOISM", which appears to be a typo. "TOISM" is not a recognized term. This should likely remain as "SHINTO" or be "SHINTOISM" if following a consistent naming pattern for religions.

Suggested change
"신토" -> "TOISM"
"신토" -> "SHINTO"

Copilot uses AI. Check for mistakes.
videoView.stopPlayback()
navigateToMain()
}
videoView.setOnErrorListener { _, _, _ ->
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The error handler for the video view returns true, which indicates the error was handled. However, the video is not properly cleaned up before navigating. Consider calling stopPlayback() before navigating to ensure resources are released properly.

Suggested change
videoView.setOnErrorListener { _, _, _ ->
videoView.setOnErrorListener { _, _, _ ->
videoView.stopPlayback()

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +46
private fun navigateToMain() {
if (hasNavigated) return
hasNavigated = true
val intent = Intent(this, MainActivity::class.java)
intent.putExtras(this.intent)
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
startActivity(intent)
overridePendingTransition(0, 0)
finish()
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The navigateToMain() function can be called from multiple sources (completion listener and error listener) without proper synchronization. Although hasNavigated flag is checked, this is not thread-safe and could lead to race conditions if both callbacks are triggered simultaneously.

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +59
val data = response.body().orEmpty()
if (data.isEmpty()) {
_uiState.value = HomeUiState(isWaiting = true)
} else {
_uiState.value = HomeUiState(matchings = data)
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The response.body().orEmpty() call assumes that a null body should be treated as an empty list. However, a null body from a successful response typically indicates a server error or unexpected response format. Consider explicitly handling this case with an error message rather than treating it as an empty matching list.

Suggested change
val data = response.body().orEmpty()
if (data.isEmpty()) {
_uiState.value = HomeUiState(isWaiting = true)
} else {
_uiState.value = HomeUiState(matchings = data)
val body = response.body()
if (body == null) {
Log.e(TAG, "getFemaleMatchings failed: response body is null on success")
_uiState.value = HomeUiState(isWaiting = true)
_events.tryEmit(HomeUiEvent.ShowToast("매칭 목록을 불러오지 못했습니다."))
} else {
if (body.isEmpty()) {
_uiState.value = HomeUiState(isWaiting = true)
} else {
_uiState.value = HomeUiState(matchings = body)
}

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +39
val scaledWidth = (viewHeight * videoRatio).toInt()
setMeasuredDimension(scaledWidth, viewHeight)
} else {
val scaledHeight = (viewWidth / videoRatio).toInt()
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The onMeasure method calculates scaled dimensions but doesn't account for potential integer overflow when multiplying viewHeight by videoRatio or dividing viewWidth by videoRatio. For very large dimensions or extreme aspect ratios, this could cause crashes or incorrect layout.

Suggested change
val scaledWidth = (viewHeight * videoRatio).toInt()
setMeasuredDimension(scaledWidth, viewHeight)
} else {
val scaledHeight = (viewWidth / videoRatio).toInt()
val scaledWidthDouble = viewHeight.toDouble() * videoRatio.toDouble()
val scaledWidth = scaledWidthDouble
.coerceAtLeast(1.0)
.coerceAtMost(Int.MAX_VALUE.toDouble())
.toInt()
setMeasuredDimension(scaledWidth, viewHeight)
} else {
val scaledHeightDouble = viewWidth.toDouble() / videoRatio.toDouble()
val scaledHeight = scaledHeightDouble
.coerceAtLeast(1.0)
.coerceAtMost(Int.MAX_VALUE.toDouble())
.toInt()

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +83
suspend fun clearUserInfo() {
context.dataStore.edit { prefs ->
prefs.remove(KEY_MEMBER_ID)
prefs.remove(KEY_NAME)
prefs.remove(KEY_TOKEN)
prefs.remove(KEY_STATUS)
}
}
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The clearUserInfo() method removes specific user-related keys but leaves other potential keys in the DataStore. This could lead to incomplete logout if other user-specific data exists. Consider using the existing clear() method or documenting why selective removal is necessary.

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +14
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path

interface MatchingService {
@GET("members/matchings/female")
fun getFemaleMatchings(): Call<List<MatchingResponse>>

@POST("members/matchings/{matchingId}/select")
fun selectMatching(@Path("matchingId") matchingId: Long): Call<Void>
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The API service methods return Call objects but are being used with awaitResponse(). This is mixing Retrofit's callback-based API with Kotlin coroutines. Consider changing the interface to use suspend functions that return Response directly for cleaner and more idiomatic coroutine usage.

Suggested change
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
interface MatchingService {
@GET("members/matchings/female")
fun getFemaleMatchings(): Call<List<MatchingResponse>>
@POST("members/matchings/{matchingId}/select")
fun selectMatching(@Path("matchingId") matchingId: Long): Call<Void>
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
interface MatchingService {
@GET("members/matchings/female")
suspend fun getFemaleMatchings(): Response<List<MatchingResponse>>
@POST("members/matchings/{matchingId}/select")
suspend fun selectMatching(@Path("matchingId") matchingId: Long): Response<Void>

Copilot uses AI. Check for mistakes.
}

LaunchedEffect(matchings.size) {
if (matchings.isNotEmpty() && pagerState.currentPage >= matchings.size) {
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

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

The pager state is created with a dynamic pageCount based on matchings.size. When matchings changes, the pagerState needs to be recreated or the pageCount needs to be updated. The current implementation has a LaunchedEffect to scroll to page 0 if currentPage is out of bounds, but this doesn't handle the case where pageCount changes while the user is viewing a valid page.

Suggested change
if (matchings.isNotEmpty() && pagerState.currentPage >= matchings.size) {
if (matchings.isNotEmpty()) {

Copilot uses AI. Check for mistakes.
@mark77234 mark77234 changed the title Feat/62 feat - 홈화면 작업 Jan 4, 2026
Copy link
Collaborator

@fkal829 fkal829 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다~~~👍
에러 찾은 거 진짜 ㄴㅇㅅ

@mark77234 mark77234 merged commit 16738de into dev Jan 4, 2026
1 check failed
@mark77234 mark77234 deleted the feat/62 branch January 4, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 홈화면 작업

3 participants