From 6f00438e8d09838870b77e873d4bf15709a66be3 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:56:30 +0900 Subject: [PATCH 01/24] =?UTF-8?q?[fix]=20=EB=B3=B4=ED=98=B8=EC=9E=A5?= =?UTF-8?q?=EC=86=8C,=20=EB=B0=9C=EA=B2=AC=EC=9E=A5=EC=86=8C=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존에 보호장소(tvShelterLocation)에 표시되던 주소(careAddr)를 발견장소(tvValueFoundLocation)로 수정 - 보호장소(tvValueProtectLocation)에는 기존 주소(careAddr)를 표시하도록 수정 --- .../ui/search/detail/SearchProtectingDetailFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchProtectingDetailFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchProtectingDetailFragment.kt index 4390ef68..6f2df9c5 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchProtectingDetailFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchProtectingDetailFragment.kt @@ -139,13 +139,13 @@ class SearchProtectingDetailFragment : Fragment() { tvValueFoundDate.text = data.foundDate tvValueHairColor.text = data.furColor tvSpecialNote.text = data.significant - tvShelterLocation.text = data.careAddr tvValueShelterName.text = data.careName tvValueNotiDate.text = data.noticeDuration tvValueNotiNum.text = data.noticeNumber tvValueShelterPhoneNumber.text = data.careTel tvValueJurisdiction.text = data.authority - tvValueProtectLocation.text = data.foundLocation.ifBlank { data.careAddr } + tvValueProtectLocation.text = data.careAddr + tvValueFoundLocation.text = data.foundLocation initTagView(data.tag) if (data.imageUrls.isNotEmpty()) { From bcd27bc3f8c7dc0e883754c52de13f6424eccf23 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:05:27 +0900 Subject: [PATCH 02/24] =?UTF-8?q?[fix]=20=ED=95=98=EB=8B=A8=EB=B0=94(BNV)?= =?UTF-8?q?=20=EB=85=B8=EC=B6=9C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 상세 검색 결과 화면에서 하단바가 보이지 않도록 수정 --- .../java/com/kuit/findu/presentation/ui/main/MainActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/main/MainActivity.kt b/app/src/main/java/com/kuit/findu/presentation/ui/main/MainActivity.kt index f1cc619f..77a38283 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/main/MainActivity.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/main/MainActivity.kt @@ -49,7 +49,6 @@ class MainActivity : AppCompatActivity() { binding.bnvMain.visibility = when (destination.id) { R.id.fragment_home, R.id.fragment_search, R.id.fragment_info, R.id.fragment_my -> View.VISIBLE - R.id.fragment_search_detail_witness, R.id.fragment_search_detail_disappear, R.id.fragment_search_detail_protecting -> View.VISIBLE else -> View.GONE } } From 7a28f91bf980e01fd64f94391426c5fbfaaf1f0f Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:05:37 +0900 Subject: [PATCH 03/24] =?UTF-8?q?[feat]=20bg=5Fradius=5F20=20=EB=B0=B0?= =?UTF-8?q?=EA=B2=BD=20=EC=83=89=EC=83=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `bg_radius_20.xml` drawable에서 배경 색상(@color/gray2)을 제거하여 투명한 배경을 가지도록 수정 --- app/src/main/res/drawable/bg_radius_20.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/drawable/bg_radius_20.xml b/app/src/main/res/drawable/bg_radius_20.xml index 38bfa96b..c00ca712 100644 --- a/app/src/main/res/drawable/bg_radius_20.xml +++ b/app/src/main/res/drawable/bg_radius_20.xml @@ -1,7 +1,6 @@ - Date: Sun, 4 Jan 2026 17:12:06 +0900 Subject: [PATCH 04/24] =?UTF-8?q?[refactor]=20=EB=B3=B4=ED=98=B8=20?= =?UTF-8?q?=EC=9E=A5=EC=86=8C=20UI=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Flow를 사용하여 보호 장소 및 복사 버튼 UI를 유연하게 변경 --- .../fragment_search_detail_protecting.xml | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/layout/fragment_search_detail_protecting.xml b/app/src/main/res/layout/fragment_search_detail_protecting.xml index e43971ee..dd2085c9 100644 --- a/app/src/main/res/layout/fragment_search_detail_protecting.xml +++ b/app/src/main/res/layout/fragment_search_detail_protecting.xml @@ -322,25 +322,38 @@ app:layout_constraintStart_toEndOf="@id/tv_value_shelter_name" app:layout_constraintTop_toTopOf="@id/tv_value_shelter_name" /> + + + tools:layout_editor_absoluteX="0dp" + tools:layout_editor_absoluteY="0dp" /> + tools:layout_editor_absoluteX="0dp" + tools:layout_editor_absoluteY="0dp"> Date: Sun, 4 Jan 2026 17:12:13 +0900 Subject: [PATCH 05/24] =?UTF-8?q?[fix]=20=EB=94=94=EC=8A=A4=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=97=90=EB=9F=AC=20=EB=A1=9C=EA=B9=85=20=EB=B2=94?= =?UTF-8?q?=EC=9C=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 5xx 에러만 로깅하던 것을 4xx 에러도 포함하도록 수정 --- .../kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt b/app/src/main/java/com/kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt index 4dcf5036..2e882522 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt @@ -41,7 +41,7 @@ class ErrorTrackingInterceptor @Inject constructor( key("api_status", code) } - if (code in 500..599) { + if (code in 400..599) { CoroutineScope(Dispatchers.IO).launch { discordLogger.logServerError( code = code, From e5ff60c718792637aa08a1ee0628ffc7fe8a2a5c Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:13:31 +0900 Subject: [PATCH 06/24] =?UTF-8?q?[feat]=20=EA=B2=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B2=84=ED=8A=BC=20UI=20?= =?UTF-8?q?=EB=B3=B5=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존의 회색 배경 버튼에서 밑줄이 있는 텍스트 버튼으로 변경 --- .../ui/login/composeview/LoginScreen.kt | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/login/composeview/LoginScreen.kt b/app/src/main/java/com/kuit/findu/presentation/ui/login/composeview/LoginScreen.kt index b3ea8688..c06aee10 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/login/composeview/LoginScreen.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/login/composeview/LoginScreen.kt @@ -2,7 +2,6 @@ package com.kuit.findu.presentation.ui.login.composeview import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -10,6 +9,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.Icon import androidx.compose.material.Text +import androidx.compose.material.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -17,11 +17,11 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.kuit.findu.R import com.kuit.findu.presentation.util.extension.noRippleClickable -import com.kuit.findu.presentation.util.extension.roundedBackgroundWithPadding import com.kuit.findu.ui.theme.FindUTheme @Composable @@ -65,29 +65,27 @@ fun LoginScreen( contentDescription = null, tint = Color.Unspecified, ) - Spacer(modifier = Modifier.height(53.dp)) -// Icon( -// painter = painterResource(R.drawable.img_kakao_login), -// contentDescription = null, -// modifier = Modifier.noRippleClickable(), -// tint = Color.Unspecified -// ) - Spacer(modifier = Modifier.height(50.dp)) - Spacer(modifier = Modifier.height(15.dp)) - Text( - text = stringResource(R.string.login_without_signup), - textAlign = TextAlign.Center, - style = FindUTheme.typography.body1SemiBold16, - color = FindUTheme.colors.gray5, - modifier = Modifier - .fillMaxWidth() - .roundedBackgroundWithPadding( - backgroundColor = FindUTheme.colors.gray2, - cornerRadius = 8.dp, - padding = PaddingValues(vertical = 15.dp) - ) - .noRippleClickable(withoutSignUpButtonClicked) + Spacer(modifier = Modifier.height(100.dp)) + Icon( + painter = painterResource(R.drawable.img_kakao_login), + contentDescription = null, + modifier = Modifier.noRippleClickable(onClick = kakaoLoginButtonClicked), + tint = Color.Unspecified ) + Spacer(modifier = Modifier.height(15.dp)) + + TextButton( + onClick = withoutSignUpButtonClicked, + ) { + Text( + text = stringResource(R.string.login_without_signup), + textAlign = TextAlign.Center, + style = FindUTheme.typography.body1SemiBold16, + color = FindUTheme.colors.gray5, + textDecoration = TextDecoration.Underline, + modifier = Modifier + ) + } Spacer(modifier = Modifier.weight(1.5f)) } From 0a23bc33cfb20cc22280f89263918935458f167f Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:29:25 +0900 Subject: [PATCH 07/24] =?UTF-8?q?[fix]=20=EC=A7=80=EB=8F=84=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EC=A0=95=EB=B3=B4=20=EC=97=86=EC=9D=84=20=EC=8B=9C?= =?UTF-8?q?=20=EC=A7=80=EB=8F=84=20=EC=88=A8=EA=B9=80=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 상세 정보 화면에서 위도, 경도 값이 null일 경우 지도를 표시하지 않도록 수정합니다. - 관련 DTO 및 데이터 모델의 위도(latitude), 경도(longitude) 타입을 nullable(Double?)로 변경합니다. --- .../model/response/search/DetailMissingResponseDto.kt | 4 ++-- .../model/response/search/DetailProtectResponseDto.kt | 4 ++-- .../model/response/search/DetailWitnessResponseDto.kt | 4 ++-- .../findu/domain/model/search/DetailMissingData.kt | 4 ++-- .../findu/domain/model/search/DetailProtectData.kt | 4 ++-- .../findu/domain/model/search/DetailWitnessData.kt | 4 ++-- .../ui/search/detail/SearchDisappearDetailFragment.kt | 11 +++++++++-- .../search/detail/SearchProtectingDetailFragment.kt | 9 ++++++++- .../ui/search/detail/SearchWitnessDetailFragment.kt | 9 ++++++++- 9 files changed, 37 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailMissingResponseDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailMissingResponseDto.kt index dd277f58..418e475a 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailMissingResponseDto.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailMissingResponseDto.kt @@ -16,8 +16,8 @@ data class DetailMissingResponseDto( @SerialName("significant") val significant: String, @SerialName("missingLocation") val missingLocation: String, @SerialName("missingAddress") val missingAddress: String, - @SerialName("latitude") val latitude: Double, - @SerialName("longitude") val longitude: Double, + @SerialName("latitude") val latitude: Double?, + @SerialName("longitude") val longitude: Double?, @SerialName("reporterName") val reporterName: String, @SerialName("reporterTel") val reporterTel: String, @SerialName("interest") val interest: Boolean diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailProtectResponseDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailProtectResponseDto.kt index ddce9e30..0a634282 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailProtectResponseDto.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailProtectResponseDto.kt @@ -28,9 +28,9 @@ data class DetailProtectResponseDto( @SerialName("careAddr") val careAddr: String, @SerialName("latitude") - val latitude: Double, + val latitude: Double?, @SerialName("longitude") - val longitude: Double, + val longitude: Double?, @SerialName("careTel") val careTel: String, @SerialName("foundDate") diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailWitnessResponseDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailWitnessResponseDto.kt index d2ee4a00..49f4ee25 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailWitnessResponseDto.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/DetailWitnessResponseDto.kt @@ -12,8 +12,8 @@ data class DetailWitnessResponseDto( @SerialName("significant") val significant: String, @SerialName("witnessLocation") val witnessLocation: String, @SerialName("witnessAddress") val witnessAddress: String, - @SerialName("latitude") val latitude: Double, - @SerialName("longitude") val longitude: Double, + @SerialName("latitude") val latitude: Double?, + @SerialName("longitude") val longitude: Double?, @SerialName("reporterInfo") val reporterInfo: String, @SerialName("witnessDate") val witnessDate: String, @SerialName("interest") val interest: Boolean diff --git a/app/src/main/java/com/kuit/findu/domain/model/search/DetailMissingData.kt b/app/src/main/java/com/kuit/findu/domain/model/search/DetailMissingData.kt index d80dd763..58e1a69e 100644 --- a/app/src/main/java/com/kuit/findu/domain/model/search/DetailMissingData.kt +++ b/app/src/main/java/com/kuit/findu/domain/model/search/DetailMissingData.kt @@ -13,8 +13,8 @@ data class DetailMissingData( val significant: String, val missingLocation: String, val missingAddress: String, - val latitude: Double, - val longitude: Double, + val latitude: Double?, + val longitude: Double?, val reporterName: String, val reporterTel: String, val interest: Boolean diff --git a/app/src/main/java/com/kuit/findu/domain/model/search/DetailProtectData.kt b/app/src/main/java/com/kuit/findu/domain/model/search/DetailProtectData.kt index 38dd3e3b..a3355eb6 100644 --- a/app/src/main/java/com/kuit/findu/domain/model/search/DetailProtectData.kt +++ b/app/src/main/java/com/kuit/findu/domain/model/search/DetailProtectData.kt @@ -14,8 +14,8 @@ data class DetailProtectData( val significant: String, val careName: String, val careAddr: String, - val latitude: Double, - val longitude: Double, + val latitude: Double?, + val longitude: Double?, val careTel: String, val foundDate: String, val foundLocation: String, diff --git a/app/src/main/java/com/kuit/findu/domain/model/search/DetailWitnessData.kt b/app/src/main/java/com/kuit/findu/domain/model/search/DetailWitnessData.kt index 3e31427d..3723a636 100644 --- a/app/src/main/java/com/kuit/findu/domain/model/search/DetailWitnessData.kt +++ b/app/src/main/java/com/kuit/findu/domain/model/search/DetailWitnessData.kt @@ -10,8 +10,8 @@ data class DetailWitnessData( val significant: String, val witnessLocation: String, val witnessAddress: String, - val latitude: Double, - val longitude: Double, + val latitude: Double?, + val longitude: Double?, val reporterInfo: String, val witnessDate: String, val interest: Boolean diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchDisappearDetailFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchDisappearDetailFragment.kt index e8e81a2f..401ce5de 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchDisappearDetailFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchDisappearDetailFragment.kt @@ -97,7 +97,7 @@ class SearchDisappearDetailFragment : Fragment() { position = location this.map = map icon = OverlayImage.fromResource(R.drawable.ic_search_map_marker) - height = 23 + height = 40 } } @@ -145,7 +145,14 @@ class SearchDisappearDetailFragment : Fragment() { if (data.imageUrls.isNotEmpty()) { initViewPager(data.imageUrls) } - setupMap(data.latitude, data.longitude) + + // latitude, longitude가 null이면 지도 숨기기 + if (data.latitude != null && data.longitude != null) { + clSearchMap.visibility = View.VISIBLE + setupMap(data.latitude, data.longitude) + } else { + clSearchMap.visibility = View.GONE + } } } diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchProtectingDetailFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchProtectingDetailFragment.kt index 6f2df9c5..12347495 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchProtectingDetailFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchProtectingDetailFragment.kt @@ -151,7 +151,14 @@ class SearchProtectingDetailFragment : Fragment() { if (data.imageUrls.isNotEmpty()) { initViewPager(data.imageUrls) } - setupMap(data.latitude, data.longitude) + + // latitude, longitude가 null이면 지도 숨기기 + if (data.latitude != null && data.longitude != null) { + clSearchMap.visibility = View.VISIBLE + setupMap(data.latitude, data.longitude) + } else { + clSearchMap.visibility = View.GONE + } } } diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchWitnessDetailFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchWitnessDetailFragment.kt index 08f77d81..4b788efe 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchWitnessDetailFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/detail/SearchWitnessDetailFragment.kt @@ -139,7 +139,14 @@ class SearchWitnessDetailFragment : Fragment() { if (data.imageUrls.isNotEmpty()) { initViewPager(data.imageUrls) } - setupMap(data.latitude, data.longitude) + + // latitude, longitude가 null이면 지도 숨기기 + if (data.latitude != null && data.longitude != null) { + clSearchMap.visibility = View.VISIBLE + setupMap(data.latitude, data.longitude) + } else { + clSearchMap.visibility = View.GONE + } } } From dffa147cf35a20785865e85c562f1065d2eb4080 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:35:33 +0900 Subject: [PATCH 08/24] =?UTF-8?q?[refactor]=20=EA=B2=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f55120c8..8b910071 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,7 +14,7 @@ 누군가의 세상이 됩니다. 유기동물 관련 어플리케이션 가입없이 시작하기 - 가입없이 찾아유 실행 + 찾아유에 오신 것을 환영합니다! From 80b92578740855016d4529704a42facc48ab0e19 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:35:42 +0900 Subject: [PATCH 09/24] =?UTF-8?q?[feat]=20refreshToken=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로그인 API 응답에 refreshToken을 추가하고 관련 데이터 클래스 및 로직을 수정했습니다. - 일반 로그인 및 게스트 로그인 시 refreshToken을 저장하도록 구현했습니다. --- .../model/response/auth/GuestLoginResponseDto.kt | 4 +++- .../dataremote/model/response/auth/LoginResponseDto.kt | 4 +++- .../mapper/todomain/GuestLoginResponseDtoMapper.kt | 3 ++- .../findu/data/mapper/todomain/UserInfoDtoMapper.kt | 3 ++- .../main/java/com/kuit/findu/domain/model/AuthData.kt | 10 ++++++---- .../presentation/ui/login/viewmodel/LoginViewModel.kt | 4 ++++ 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/GuestLoginResponseDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/GuestLoginResponseDto.kt index 3a973259..dd648a71 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/GuestLoginResponseDto.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/GuestLoginResponseDto.kt @@ -8,5 +8,7 @@ data class GuestLoginResponseDto( @SerialName("userId") val userId: Long, @SerialName("accessToken") - val accessToken: String + val accessToken: String, + @SerialName("refreshToken") + val refreshToken: String ) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/LoginResponseDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/LoginResponseDto.kt index b8ee05f0..1eb6d610 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/LoginResponseDto.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/LoginResponseDto.kt @@ -18,5 +18,7 @@ data class UserInfoDto( @SerialName("nickname") val nickname: String, @SerialName("accessToken") - val accessToken: String + val accessToken: String, + @SerialName("refreshToken") + val refreshToken: String, ) \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/data/mapper/todomain/GuestLoginResponseDtoMapper.kt b/app/src/main/java/com/kuit/findu/data/mapper/todomain/GuestLoginResponseDtoMapper.kt index 0b8a3c75..86231319 100644 --- a/app/src/main/java/com/kuit/findu/data/mapper/todomain/GuestLoginResponseDtoMapper.kt +++ b/app/src/main/java/com/kuit/findu/data/mapper/todomain/GuestLoginResponseDtoMapper.kt @@ -6,5 +6,6 @@ import com.kuit.findu.domain.model.GuestLoginData fun GuestLoginResponseDto.toDomain(): GuestLoginData = GuestLoginData( userId = this.userId, - accessToken = this.accessToken + accessToken = this.accessToken, + refreshToken = this.refreshToken ) \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/data/mapper/todomain/UserInfoDtoMapper.kt b/app/src/main/java/com/kuit/findu/data/mapper/todomain/UserInfoDtoMapper.kt index 644287b7..ecce2eef 100644 --- a/app/src/main/java/com/kuit/findu/data/mapper/todomain/UserInfoDtoMapper.kt +++ b/app/src/main/java/com/kuit/findu/data/mapper/todomain/UserInfoDtoMapper.kt @@ -7,5 +7,6 @@ fun UserInfoDto.toDomain(): UserInfo = UserInfo( userId = this.userId, nickname = this.nickname, - accessToken = this.accessToken + accessToken = this.accessToken, + refreshToken = this.refreshToken ) \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/domain/model/AuthData.kt b/app/src/main/java/com/kuit/findu/domain/model/AuthData.kt index 8de51cf1..4516eb2f 100644 --- a/app/src/main/java/com/kuit/findu/domain/model/AuthData.kt +++ b/app/src/main/java/com/kuit/findu/domain/model/AuthData.kt @@ -2,21 +2,23 @@ package com.kuit.findu.domain.model data class LoginInfo( val kakaoId: Long, - val deviceId: String + val deviceId: String, ) data class LoginData( val isFirstLogin: Boolean, - val userInfo: UserInfo? + val userInfo: UserInfo?, ) data class GuestLoginData( val userId: Long, - val accessToken: String + val accessToken: String, + val refreshToken: String, ) data class UserInfo( val userId: Long, val nickname: String, - val accessToken: String + val accessToken: String, + val refreshToken: String, ) \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt index 8480dd4d..54e85633 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt @@ -9,6 +9,7 @@ import com.kuit.findu.domain.usecase.SetNicknameUseCase import com.kuit.findu.domain.usecase.auth.PostGuestLoginUseCase import com.kuit.findu.domain.usecase.auth.PostLoginUseCase import com.kuit.findu.domain.usecase.token.SetAccessTokenUseCase +import com.kuit.findu.domain.usecase.token.SetRefreshTokenUseCase import com.kuit.findu.presentation.util.Nickname.GUEST_NAME import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow @@ -21,6 +22,7 @@ class LoginViewModel @Inject constructor( private val loginUseCase: PostLoginUseCase, private val guestLoginUseCase: PostGuestLoginUseCase, private val setAccessTokenUseCase: SetAccessTokenUseCase, + private val setRefreshTokenUseCase: SetRefreshTokenUseCase, private val setNicknameUseCase: SetNicknameUseCase, private val analyticsHelper: AnalyticsHelper, ) : ViewModel() { @@ -41,6 +43,7 @@ class LoginViewModel @Inject constructor( userName = loginData.userInfo?.nickname ?: "Null Nickname", type = "kakao" ) setAccessTokenUseCase(accessToken = loginData.userInfo!!.accessToken) + setRefreshTokenUseCase(refreshToken = loginData.userInfo.refreshToken) setNicknameUseCase(nickname = loginData.userInfo.nickname) startMainActivity() } @@ -56,6 +59,7 @@ class LoginViewModel @Inject constructor( .onSuccess { loginData -> analyticsHelper.logUserSignIn(userName = GUEST_NAME, type = "Guest") setAccessTokenUseCase(accessToken = loginData.accessToken) + setRefreshTokenUseCase(refreshToken = loginData.refreshToken) setNicknameUseCase(nickname = GUEST_NAME) onSuccess() startMainActivity() From 40cd83ac43c90c5ae938c44bb86188b5e21452de Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:41:14 +0900 Subject: [PATCH 10/24] =?UTF-8?q?[refactor]=20=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=AC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 메인 컬러 #FFA938를 #FF9000으로 변경 --- app/src/main/res/drawable/ic_info_navigate.xml | 2 +- app/src/main/res/drawable/ic_location_pin.xml | 2 +- app/src/main/res/drawable/ic_report_upload_20.xml | 2 +- app/src/main/res/drawable/ic_search_call.xml | 2 +- app/src/main/res/drawable/ic_search_detail_location.xml | 2 +- app/src/main/res/drawable/ic_search_fill_bookmark.xml | 4 ++-- app/src/main/res/drawable/ic_search_phone.xml | 4 ++-- app/src/main/res/drawable/icon_home_find_report.xml | 2 +- app/src/main/res/drawable/icon_report_location_map_orange.xml | 2 +- app/src/main/res/drawable/search_detail_phone.xml | 4 ++-- app/src/main/res/values/colors.xml | 2 +- app/src/main/res/values/ic_launcher_background.xml | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/src/main/res/drawable/ic_info_navigate.xml b/app/src/main/res/drawable/ic_info_navigate.xml index 010a052b..10c71e08 100644 --- a/app/src/main/res/drawable/ic_info_navigate.xml +++ b/app/src/main/res/drawable/ic_info_navigate.xml @@ -8,6 +8,6 @@ android:strokeLineJoin="round" android:strokeWidth="1.5" android:fillColor="#00000000" - android:strokeColor="#FFA938" + android:strokeColor="#FF9000" android:strokeLineCap="round"/> diff --git a/app/src/main/res/drawable/ic_location_pin.xml b/app/src/main/res/drawable/ic_location_pin.xml index 2632f9f2..ac47d0d5 100644 --- a/app/src/main/res/drawable/ic_location_pin.xml +++ b/app/src/main/res/drawable/ic_location_pin.xml @@ -5,7 +5,7 @@ android:viewportHeight="31"> - + diff --git a/app/src/main/res/drawable/ic_search_call.xml b/app/src/main/res/drawable/ic_search_call.xml index 75a6ade6..33b12b32 100644 --- a/app/src/main/res/drawable/ic_search_call.xml +++ b/app/src/main/res/drawable/ic_search_call.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/drawable/ic_search_detail_location.xml b/app/src/main/res/drawable/ic_search_detail_location.xml index e904dd97..1d218585 100644 --- a/app/src/main/res/drawable/ic_search_detail_location.xml +++ b/app/src/main/res/drawable/ic_search_detail_location.xml @@ -5,6 +5,6 @@ android:viewportHeight="16"> diff --git a/app/src/main/res/drawable/ic_search_fill_bookmark.xml b/app/src/main/res/drawable/ic_search_fill_bookmark.xml index fd5fceb0..da7dbabc 100644 --- a/app/src/main/res/drawable/ic_search_fill_bookmark.xml +++ b/app/src/main/res/drawable/ic_search_fill_bookmark.xml @@ -7,7 +7,7 @@ android:pathData="M15.792,19.875L8.5,14.667L1.208,19.875V3.208C1.208,2.656 1.428,2.126 1.819,1.735C2.209,1.344 2.739,1.125 3.292,1.125H13.708C14.261,1.125 14.791,1.344 15.182,1.735C15.572,2.126 15.792,2.656 15.792,3.208V19.875Z" android:strokeLineJoin="round" android:strokeWidth="2" - android:fillColor="#FFA938" - android:strokeColor="#FFA938" + android:fillColor="#FF9000" + android:strokeColor="#FF9000" android:strokeLineCap="round"/> diff --git a/app/src/main/res/drawable/ic_search_phone.xml b/app/src/main/res/drawable/ic_search_phone.xml index dad1fd63..c29ea3ae 100644 --- a/app/src/main/res/drawable/ic_search_phone.xml +++ b/app/src/main/res/drawable/ic_search_phone.xml @@ -7,7 +7,7 @@ android:pathData="M16.22,14.642C16.22,14.642 15.254,15.591 15.017,15.869C14.632,16.28 14.178,16.474 13.583,16.474C13.525,16.474 13.464,16.474 13.407,16.47C12.274,16.398 11.22,15.956 10.43,15.579C8.27,14.536 6.373,13.054 4.797,11.176C3.496,9.611 2.626,8.164 2.049,6.61C1.694,5.662 1.565,4.923 1.622,4.226C1.66,3.78 1.832,3.411 2.149,3.095L3.45,1.796C3.637,1.621 3.835,1.525 4.03,1.525C4.27,1.525 4.465,1.67 4.587,1.792C4.591,1.796 4.595,1.8 4.599,1.803C4.832,2.021 5.053,2.245 5.286,2.485C5.404,2.607 5.526,2.729 5.648,2.855L6.69,3.894C7.095,4.298 7.095,4.671 6.69,5.075C6.579,5.185 6.473,5.296 6.362,5.403C6.041,5.73 6.293,5.479 5.961,5.776C5.953,5.783 5.946,5.787 5.942,5.795C5.614,6.122 5.675,6.442 5.744,6.659C5.747,6.671 5.751,6.682 5.755,6.694C6.026,7.349 6.408,7.966 6.988,8.701L6.992,8.705C8.045,10 9.155,11.009 10.38,11.782C10.537,11.881 10.697,11.961 10.85,12.037C10.987,12.106 11.117,12.17 11.228,12.239C11.243,12.247 11.258,12.258 11.274,12.266C11.403,12.33 11.525,12.361 11.651,12.361C11.968,12.361 12.167,12.163 12.231,12.098L12.979,11.352C13.109,11.222 13.315,11.066 13.556,11.066C13.792,11.066 13.987,11.215 14.105,11.344C14.109,11.348 14.109,11.348 14.113,11.352L16.216,13.45C16.609,13.839 16.22,14.642 16.22,14.642Z" android:strokeLineJoin="round" android:strokeWidth="2" - android:fillColor="#FFA938" - android:strokeColor="#FFA938" + android:fillColor="#FF9000" + android:strokeColor="#FF9000" android:strokeLineCap="round"/> diff --git a/app/src/main/res/drawable/icon_home_find_report.xml b/app/src/main/res/drawable/icon_home_find_report.xml index 4d7be56d..1e06d36e 100644 --- a/app/src/main/res/drawable/icon_home_find_report.xml +++ b/app/src/main/res/drawable/icon_home_find_report.xml @@ -8,6 +8,6 @@ android:strokeLineJoin="round" android:strokeWidth="2" android:fillColor="#00000000" - android:strokeColor="#FFA938" + android:strokeColor="#FF9000" android:strokeLineCap="round"/> diff --git a/app/src/main/res/drawable/icon_report_location_map_orange.xml b/app/src/main/res/drawable/icon_report_location_map_orange.xml index 6d3c8575..04588514 100644 --- a/app/src/main/res/drawable/icon_report_location_map_orange.xml +++ b/app/src/main/res/drawable/icon_report_location_map_orange.xml @@ -5,6 +5,6 @@ android:viewportHeight="17"> diff --git a/app/src/main/res/drawable/search_detail_phone.xml b/app/src/main/res/drawable/search_detail_phone.xml index dad1fd63..c29ea3ae 100644 --- a/app/src/main/res/drawable/search_detail_phone.xml +++ b/app/src/main/res/drawable/search_detail_phone.xml @@ -7,7 +7,7 @@ android:pathData="M16.22,14.642C16.22,14.642 15.254,15.591 15.017,15.869C14.632,16.28 14.178,16.474 13.583,16.474C13.525,16.474 13.464,16.474 13.407,16.47C12.274,16.398 11.22,15.956 10.43,15.579C8.27,14.536 6.373,13.054 4.797,11.176C3.496,9.611 2.626,8.164 2.049,6.61C1.694,5.662 1.565,4.923 1.622,4.226C1.66,3.78 1.832,3.411 2.149,3.095L3.45,1.796C3.637,1.621 3.835,1.525 4.03,1.525C4.27,1.525 4.465,1.67 4.587,1.792C4.591,1.796 4.595,1.8 4.599,1.803C4.832,2.021 5.053,2.245 5.286,2.485C5.404,2.607 5.526,2.729 5.648,2.855L6.69,3.894C7.095,4.298 7.095,4.671 6.69,5.075C6.579,5.185 6.473,5.296 6.362,5.403C6.041,5.73 6.293,5.479 5.961,5.776C5.953,5.783 5.946,5.787 5.942,5.795C5.614,6.122 5.675,6.442 5.744,6.659C5.747,6.671 5.751,6.682 5.755,6.694C6.026,7.349 6.408,7.966 6.988,8.701L6.992,8.705C8.045,10 9.155,11.009 10.38,11.782C10.537,11.881 10.697,11.961 10.85,12.037C10.987,12.106 11.117,12.17 11.228,12.239C11.243,12.247 11.258,12.258 11.274,12.266C11.403,12.33 11.525,12.361 11.651,12.361C11.968,12.361 12.167,12.163 12.231,12.098L12.979,11.352C13.109,11.222 13.315,11.066 13.556,11.066C13.792,11.066 13.987,11.215 14.105,11.344C14.109,11.348 14.109,11.348 14.113,11.352L16.216,13.45C16.609,13.839 16.22,14.642 16.22,14.642Z" android:strokeLineJoin="round" android:strokeWidth="2" - android:fillColor="#FFA938" - android:strokeColor="#FFA938" + android:fillColor="#FF9000" + android:strokeColor="#FF9000" android:strokeLineCap="round"/> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 0c06d71d..0790de03 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,7 +1,7 @@ - #FFA938 + #FF9000 #FFEED9 #EF4346 diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml index 3dae097e..4bd1fb3c 100644 --- a/app/src/main/res/values/ic_launcher_background.xml +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -1,4 +1,4 @@ - #FFA938 + #FF9000 \ No newline at end of file From 3ce4483112410e29ef3ba44a9da06bf9135576ae Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:41:17 +0900 Subject: [PATCH 11/24] =?UTF-8?q?[fix]=20=ED=9A=8C=EC=9B=90=20=ED=83=88?= =?UTF-8?q?=ED=87=B4=20=EC=99=84=EB=A3=8C=20=EC=8B=9C=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=EC=9D=84=20=EC=A0=9C=EA=B1=B0=ED=95=98=EB=8A=94=20=EA=B2=83?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt | 1 - .../com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt index 5db589ab..6b3cb26a 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt @@ -175,7 +175,6 @@ class MyFragment : Fragment() { context = requireContext(), onWithdrawalClick = { myViewModel.deleteUserData() - myViewModel.clearToken() with(requireActivity()) { startActivity(Intent(requireContext(), LoginActivity::class.java)) finish() diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt index 977b43d8..d5952c4f 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt @@ -128,6 +128,7 @@ class MyViewModel @Inject constructor( viewModelScope.launch { deleteUserUseCase().fold( onSuccess = { + clearToken() _deleteUserMessage.value = "회원 탈퇴가 완료되었습니다." }, onFailure = { From e91d2c2e774531d73ef713d54933508463347b0f Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 18:06:54 +0900 Subject: [PATCH 12/24] =?UTF-8?q?[feat]=20=EC=A1=B0=ED=9A=8C=20createdAt?= =?UTF-8?q?=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/search/SearchResponseDto.kt | 8 ++-- .../todomain/SearchResponseDtoMapper.kt | 1 + .../findu/domain/model/search/SearchData.kt | 6 ++- .../ui/search/adapter/SearchListAdapter.kt | 29 ++++++++++---- .../presentation/ui/search/model/SearchRv.kt | 3 +- .../ui/search/model/SearchRvTag.kt | 11 +++--- .../ui/search/tablayout/SearchAllFragment.kt | 3 +- .../search/tablayout/SearchReportFragment.kt | 3 +- .../search/tablayout/SearchRescueFragment.kt | 3 +- .../res/layout/item_search_grid_content.xml | 36 ++++++++++++++++-- .../layout/search_horizontal_content_item.xml | 38 ++++++++++++++++--- 11 files changed, 111 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/SearchResponseDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/SearchResponseDto.kt index 6fc1c066..0938da87 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/SearchResponseDto.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/search/SearchResponseDto.kt @@ -8,9 +8,9 @@ data class SearchResponseDto( @SerialName("cards") val cards: List, @SerialName("lastId") - val lastId : Long?, + val lastId: Long?, @SerialName("isLast") - val isLast : Boolean + val isLast: Boolean, ) @Serializable @@ -28,5 +28,7 @@ data class SearchAnimalCard( @SerialName("location") val location: String, @SerialName("interest") - val interest: Boolean = false + val interest: Boolean = false, + @SerialName("createdAt") + val createdAt: String, ) diff --git a/app/src/main/java/com/kuit/findu/data/mapper/todomain/SearchResponseDtoMapper.kt b/app/src/main/java/com/kuit/findu/data/mapper/todomain/SearchResponseDtoMapper.kt index 4f571fd9..25f9c087 100644 --- a/app/src/main/java/com/kuit/findu/data/mapper/todomain/SearchResponseDtoMapper.kt +++ b/app/src/main/java/com/kuit/findu/data/mapper/todomain/SearchResponseDtoMapper.kt @@ -26,6 +26,7 @@ fun SearchAnimalCard.toDomain(): SearchAnimal { date = this.date, location = this.location, interest = this.interest, + createdAt = this.createdAt, ) } diff --git a/app/src/main/java/com/kuit/findu/domain/model/search/SearchData.kt b/app/src/main/java/com/kuit/findu/domain/model/search/SearchData.kt index bec3a7d4..203f2ba8 100644 --- a/app/src/main/java/com/kuit/findu/domain/model/search/SearchData.kt +++ b/app/src/main/java/com/kuit/findu/domain/model/search/SearchData.kt @@ -5,7 +5,7 @@ import java.io.Serializable data class SearchData( val cards: List, val lastId: Long, - val isLast: Boolean + val isLast: Boolean, ) : Serializable data class SearchAnimal( @@ -15,7 +15,9 @@ data class SearchAnimal( val tag: SearchStatus, val date: String, val location: String, - val interest: Boolean + val interest: Boolean, + val createdAt: String, + ) : Serializable fun String.toSearchStatus(): SearchStatus { diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/adapter/SearchListAdapter.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/adapter/SearchListAdapter.kt index bdead7d3..68b3910f 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/adapter/SearchListAdapter.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/adapter/SearchListAdapter.kt @@ -19,7 +19,7 @@ sealed class SearchListItem { } class SearchListAdapter( - private val listener: SearchListListener + private val listener: SearchListListener, ) : ListAdapter(DIFF) { companion object { @@ -28,16 +28,23 @@ class SearchListAdapter( const val VIEW_TYPE_GRID = 1 private val DIFF = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: SearchListItem, newItem: SearchListItem): Boolean { + override fun areItemsTheSame( + oldItem: SearchListItem, + newItem: SearchListItem, + ): Boolean { return when { oldItem is SearchListItem.Header && newItem is SearchListItem.Header -> true oldItem is SearchListItem.Content && newItem is SearchListItem.Content -> oldItem.data.reportId == newItem.data.reportId + else -> false } } - override fun areContentsTheSame(oldItem: SearchListItem, newItem: SearchListItem): Boolean { + override fun areContentsTheSame( + oldItem: SearchListItem, + newItem: SearchListItem, + ): Boolean { return oldItem == newItem } } @@ -65,10 +72,12 @@ class SearchListAdapter( ItemSearchHeaderBinding.inflate(inflater, parent, false), listener ) + VIEW_TYPE_GRID -> BaseVH.GridVH( ItemSearchGridContentBinding.inflate(inflater, parent, false), listener ) + else -> BaseVH.HorizontalVH( SearchHorizontalContentItemBinding.inflate(inflater, parent, false), listener @@ -87,7 +96,7 @@ class SearchListAdapter( sealed class BaseVH(bindingRoot: ViewGroup) : RecyclerView.ViewHolder(bindingRoot) { class HeaderVH( private val binding: ItemSearchHeaderBinding, - private val listener: SearchListListener + private val listener: SearchListListener, ) : BaseVH(binding.root as ViewGroup) { private var isGrid = false fun bind() = with(binding) { @@ -106,13 +115,15 @@ class SearchListAdapter( class HorizontalVH( private val binding: SearchHorizontalContentItemBinding, - private val listener: SearchListListener + private val listener: SearchListListener, ) : BaseVH(binding.root as ViewGroup) { fun bind(item: SearchRv) = with(binding) { tvSearchContentName.text = item.name - tvSearchContentDate.text = item.date + tvSearchFoundDate.text = item.date + tvSearchContentDate.text = item.createdAt tvSearchContentAddress.text = item.location tvSearchContentStatus.text = item.tag.text + tvSearchFoundDateTitle.text = item.tag.dateTag tvSearchContentStatus.setTextColor(root.context.getColor(item.tag.textColor)) tvSearchContentStatus.setBackgroundResource(item.tag.backgroundRes) updateBookmarkIcon(item.isBookmark) @@ -143,13 +154,15 @@ class SearchListAdapter( class GridVH( private val binding: ItemSearchGridContentBinding, - private val listener: SearchListListener + private val listener: SearchListListener, ) : BaseVH(binding.root as ViewGroup) { fun bind(item: SearchRv) = with(binding) { tvSearchContentName.text = item.name - tvSearchContentDate.text = item.date + tvSearchFoundDate.text = item.date + tvSearchContentDate.text = item.createdAt tvSearchContentAddress.text = item.location tvSearchContentStatus.text = item.tag.text + tvSearchFoundDateTitle.text = item.tag.dateTag tvSearchContentStatus.setTextColor(root.context.getColor(item.tag.textColor)) tvSearchContentStatus.setBackgroundResource(item.tag.backgroundRes) updateBookmarkIcon(item.isBookmark) diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/model/SearchRv.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/model/SearchRv.kt index f50d5d55..b33e3954 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/model/SearchRv.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/model/SearchRv.kt @@ -9,5 +9,6 @@ data class SearchRv( val location : String, var isBookmark : Boolean, var tag : SearchRvTag, - val reportId: Long + val reportId: Long, + val createdAt: String, ) : Serializable diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/model/SearchRvTag.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/model/SearchRvTag.kt index e9bcad0f..34b3a2cb 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/model/SearchRvTag.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/model/SearchRvTag.kt @@ -6,10 +6,11 @@ import java.io.Serializable enum class SearchRvTag( val text: String, val textColor: Int, - val backgroundRes: Int + val backgroundRes: Int, + val dateTag: String ) : Serializable { - PROTECTING("보호중", R.color.green1, R.drawable.bg_search_protecting_tag), - WITNESS("목격신고", R.color.blue1, R.drawable.bg_search_report_tag), - MISSING("실종신고", R.color.red1, R.drawable.bg_search_lost_tag), - UNKNOWN("기본",R.color.white, R.drawable.bg_search_protecting_tag) + PROTECTING("보호중", R.color.green1, R.drawable.bg_search_protecting_tag, "발견날짜: "), + WITNESS("목격신고", R.color.blue1, R.drawable.bg_search_report_tag, "신고날짜: "), + MISSING("실종신고", R.color.red1, R.drawable.bg_search_lost_tag, "신고날짜: "), + UNKNOWN("기본",R.color.white, R.drawable.bg_search_protecting_tag, "") } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchAllFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchAllFragment.kt index 2356bb9c..1ff3d2ed 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchAllFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchAllFragment.kt @@ -119,7 +119,8 @@ class SearchAllFragment : Fragment(), SearchListListener { location = item.location, isBookmark = item.interest, tag = item.tag.toSearchRvTag(), - reportId = item.reportId + reportId = item.reportId, + createdAt = item.createdAt, ) } diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchReportFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchReportFragment.kt index 4cb79c7e..0503fae3 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchReportFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchReportFragment.kt @@ -118,7 +118,8 @@ class SearchReportFragment : Fragment(), SearchListListener { location = item.location, isBookmark = item.interest, tag = item.tag.toSearchRvTag(), - reportId = item.reportId + reportId = item.reportId, + createdAt = item.createdAt, ) } diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchRescueFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchRescueFragment.kt index 4c887848..7c66fc40 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchRescueFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/search/tablayout/SearchRescueFragment.kt @@ -119,7 +119,8 @@ class SearchRescueFragment : Fragment(), SearchListListener { location = item.location, isBookmark = item.interest, tag = item.tag.toSearchRvTag(), - reportId = item.reportId + reportId = item.reportId, + createdAt = item.createdAt, ) } diff --git a/app/src/main/res/layout/item_search_grid_content.xml b/app/src/main/res/layout/item_search_grid_content.xml index 7a73daa8..7fa49391 100644 --- a/app/src/main/res/layout/item_search_grid_content.xml +++ b/app/src/main/res/layout/item_search_grid_content.xml @@ -39,7 +39,7 @@ + + + + + + + app:layout_constraintTop_toBottomOf="@id/tv_search_found_date"> @@ -69,6 +69,15 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + + app:layout_constraintTop_toBottomOf="@id/tv_search_found_date"> Date: Sun, 4 Jan 2026 18:21:42 +0900 Subject: [PATCH 13/24] =?UTF-8?q?[refactor]=20=EC=98=A8=EB=B3=B4=EB=94=A9?= =?UTF-8?q?=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=84=A4=EC=A0=95=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 온보딩 과정에서 프로필 이미지를 설정하는 UI 및 관련 로직을 제거하고, 닉네임 설정만 남도록 수정했습니다. --- .../AuthRemoteDataSourceImpl.kt | 4 ++-- .../data/dataremote/service/AuthService.kt | 4 ++-- .../component/OnboardingNickname.kt | 2 +- .../composeview/OnboardingScreen.kt | 19 ++++++++++--------- .../viewmodel/OnboardingViewModel.kt | 2 +- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/datasourceimpl/AuthRemoteDataSourceImpl.kt b/app/src/main/java/com/kuit/findu/data/dataremote/datasourceimpl/AuthRemoteDataSourceImpl.kt index 13b6c354..8af2046f 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/datasourceimpl/AuthRemoteDataSourceImpl.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/datasourceimpl/AuthRemoteDataSourceImpl.kt @@ -35,8 +35,8 @@ class AuthRemoteDataSourceImpl @Inject constructor( kakaoId: Long, deviceId: String ): NullableBaseResponse = authService.postSignup( - profileImage = profileImageFile?.toImageMultipart("profileImage"), - defaultImageName = defaultImageName?.toPlainTextRequestBody(), +// profileImage = profileImageFile?.toImageMultipart("profileImage"), +// defaultImageName = defaultImageName?.toPlainTextRequestBody(), nickname = nickname.toPlainTextRequestBody(), kakaoId = kakaoId.toString().toPlainTextRequestBody(), deviceId = deviceId.toPlainTextRequestBody() diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt b/app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt index 1142f17f..0a3e6b33 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt @@ -38,8 +38,8 @@ interface AuthService { @Multipart @POST("/$API/$VERSION/users") suspend fun postSignup( - @Part profileImage: MultipartBody.Part?, - @Part("defaultProfileImageName") defaultImageName: RequestBody?, +// @Part profileImage: MultipartBody.Part?, +// @Part("defaultProfileImageName") defaultImageName: RequestBody?, @Part("nickname") nickname: RequestBody, @Part("kakaoId") kakaoId: RequestBody, @Part("deviceId") deviceId: RequestBody diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/component/OnboardingNickname.kt b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/component/OnboardingNickname.kt index ade59e9e..a012a7e9 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/component/OnboardingNickname.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/component/OnboardingNickname.kt @@ -59,7 +59,7 @@ fun OnboardingNickname( .fillMaxWidth() ) { // NOTE: 페이지 아이콘 첫/끝 요소 여백 불균형으로 임시 여백 삽입 (디자인 수정 시 제거 예정) - BaseVectorIcon(vectorResource = R.drawable.ic_onboarding_page_last, modifier = Modifier.padding(start = 4.dp)) +// BaseVectorIcon(vectorResource = R.drawable.ic_onboarding_page_last, modifier = Modifier.padding(start = 4.dp)) Spacer(modifier = Modifier.height(40.dp)) Text( text = stringResource(R.string.onboarding_nickname_title_first), diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/composeview/OnboardingScreen.kt b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/composeview/OnboardingScreen.kt index 982332c8..ca936cd7 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/composeview/OnboardingScreen.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/composeview/OnboardingScreen.kt @@ -56,14 +56,15 @@ fun OnboardingScreen( focusManager.clearFocus() } ) { - BaseVectorIcon( - vectorResource = R.drawable.ic_arrow_back_24, - modifier = Modifier - .padding(horizontal = 20.dp, vertical = 18.dp) - .noRippleClickable(backButtonClicked) - ) +// BaseVectorIcon( +// vectorResource = R.drawable.ic_arrow_back_24, +// modifier = Modifier +// .padding(horizontal = 20.dp, vertical = 18.dp) +// .noRippleClickable(backButtonClicked) +// ) + Spacer(modifier = Modifier.height(110.dp)) Spacer(modifier = Modifier.height(12.dp)) - when (uiState.pageState) { + /*when (uiState.pageState) { 1 -> OnboardingProfile( modifier = Modifier.padding(horizontal = 20.dp), defaultProfileType = uiState.defaultProfileType, @@ -73,7 +74,7 @@ fun OnboardingScreen( clearProfileImage = clearProfileImage ) - 2 -> OnboardingNickname( + 2 -> */OnboardingNickname( modifier = Modifier.padding(horizontal = 20.dp), nicknameValueChanged = { nickname -> nicknameValueChanged(nickname) @@ -86,7 +87,7 @@ fun OnboardingScreen( }, focusChanged = { focusChanged(it) } ) - } +// } Spacer(modifier = Modifier.weight(1f)) OnboardingButton( enabled = isNextButtonEnabled, diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt index 779f3b49..1d953d2a 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt @@ -24,7 +24,7 @@ import java.io.File import javax.inject.Inject data class OnboardingUiState( - val pageState: Int = 1, + val pageState: Int = 2, val kakaoId: Long = -1L, val profileImageUri: Uri? = null, val defaultProfileType: DefaultProfileType = DefaultProfileType.DEFAULT, From a8886ace5478b6d6318a4cee7b4eb45c9af48299 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sun, 4 Jan 2026 19:12:35 +0900 Subject: [PATCH 14/24] =?UTF-8?q?[refactor]=20=EC=8A=A4=ED=94=8C=EB=9E=98?= =?UTF-8?q?=EC=8B=9C=20=ED=99=94=EB=A9=B4=20=EB=A0=88=EA=B1=B0=EC=8B=9C=20?= =?UTF-8?q?=EC=83=89=EC=83=81=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 스플래시 화면의 배경 색상을 기존 main_color에서 main_color_deprecated로 변경 --- app/src/main/res/layout/activity_splash.xml | 2 +- app/src/main/res/values/colors.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml index 24818020..e534a37a 100644 --- a/app/src/main/res/layout/activity_splash.xml +++ b/app/src/main/res/layout/activity_splash.xml @@ -5,7 +5,7 @@ android:id="@+id/splash" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/main_color" + android:background="@color/main_color_deprecated" tools:context=".presentation.ui.splash.SplashActivity"> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 0790de03..f0277ce7 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,6 +1,7 @@ + #FFA938 #FF9000 #FFEED9 From 1bca66590036c48285c1024db8737007f769183d Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Fri, 9 Jan 2026 22:49:17 +0900 Subject: [PATCH 15/24] =?UTF-8?q?[fix]=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=EA=B0=92=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 프로필 이미지가 없는 경우를 대비하여 MyNickNameResponseDto의 profileImage 타입을 nullable로 변경하고, null일 경우 빈 문자열을 반환하도록 MyProfileMapper 수정 --- .../data/dataremote/model/response/my/MyNickNameResponseDto.kt | 2 +- .../com/kuit/findu/data/mapper/todomain/my/MyProfileMapper.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/my/MyNickNameResponseDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/my/MyNickNameResponseDto.kt index b8371af3..4d71e780 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/my/MyNickNameResponseDto.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/my/MyNickNameResponseDto.kt @@ -9,5 +9,5 @@ data class MyNickNameResponseDto( @SerialName("nickname") val nickname: String, @SerialName("profileImage") - val profileImage : String, + val profileImage : String? = null, ) \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/data/mapper/todomain/my/MyProfileMapper.kt b/app/src/main/java/com/kuit/findu/data/mapper/todomain/my/MyProfileMapper.kt index 935fa68d..2d33148c 100644 --- a/app/src/main/java/com/kuit/findu/data/mapper/todomain/my/MyProfileMapper.kt +++ b/app/src/main/java/com/kuit/findu/data/mapper/todomain/my/MyProfileMapper.kt @@ -6,5 +6,5 @@ import com.kuit.findu.domain.model.my.MyProfileData fun MyNickNameResponseDto.toDomain(): MyProfileData = MyProfileData( nickname = nickname, - profileImage = profileImage + profileImage = profileImage ?: "" ) \ No newline at end of file From a7b9f3af65687dba1afef2dae85c2eaba573e988 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Fri, 9 Jan 2026 23:07:21 +0900 Subject: [PATCH 16/24] =?UTF-8?q?[refactor]=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20API=20=EC=9A=94=EC=B2=AD=20=ED=98=95=EC=8B=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Multipart 형식에서 JSON 형식으로 변경 - `PostUserRequestDto` 추가 --- .../datasourceimpl/AuthRemoteDataSourceImpl.kt | 17 ++++++----------- .../model/request/PostUserRequestDto.kt | 14 ++++++++++++++ .../data/dataremote/service/AuthService.kt | 17 +++++------------ 3 files changed, 25 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/com/kuit/findu/data/dataremote/model/request/PostUserRequestDto.kt diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/datasourceimpl/AuthRemoteDataSourceImpl.kt b/app/src/main/java/com/kuit/findu/data/dataremote/datasourceimpl/AuthRemoteDataSourceImpl.kt index 8af2046f..efa9a5bf 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/datasourceimpl/AuthRemoteDataSourceImpl.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/datasourceimpl/AuthRemoteDataSourceImpl.kt @@ -6,24 +6,23 @@ import com.kuit.findu.data.dataremote.model.base.NullableBaseResponse import com.kuit.findu.data.dataremote.model.request.CheckNicknameRequestDto import com.kuit.findu.data.dataremote.model.request.GuestLoginRequestDto import com.kuit.findu.data.dataremote.model.request.LoginRequestDto +import com.kuit.findu.data.dataremote.model.request.PostUserRequestDto import com.kuit.findu.data.dataremote.model.response.CheckNicknameResponseDto import com.kuit.findu.data.dataremote.model.response.auth.GuestLoginResponseDto import com.kuit.findu.data.dataremote.model.response.auth.LoginResponseDto import com.kuit.findu.data.dataremote.model.response.auth.UserInfoDto import com.kuit.findu.data.dataremote.service.AuthService -import com.kuit.findu.data.mapper.torequest.toImageMultipart -import com.kuit.findu.data.mapper.torequest.toPlainTextRequestBody import java.io.File import javax.inject.Inject class AuthRemoteDataSourceImpl @Inject constructor( - private val authService: AuthService + private val authService: AuthService, ) : AuthRemoteDataSource { override suspend fun postLogin(loginRequestDto: LoginRequestDto): NullableBaseResponse = - authService.postLogin(loginRequestDto=loginRequestDto) + authService.postLogin(loginRequestDto = loginRequestDto) override suspend fun postGuestLogin(guestLoginRequestDto: GuestLoginRequestDto): NullableBaseResponse = - authService.postGuestLogin(guestLoginRequestDto=guestLoginRequestDto) + authService.postGuestLogin(guestLoginRequestDto = guestLoginRequestDto) override suspend fun postCheckNickname(nickname: String): BaseResponse = authService.postCheckNickname(CheckNicknameRequestDto(nickname)) @@ -33,12 +32,8 @@ class AuthRemoteDataSourceImpl @Inject constructor( defaultImageName: String?, nickname: String, kakaoId: Long, - deviceId: String + deviceId: String, ): NullableBaseResponse = authService.postSignup( -// profileImage = profileImageFile?.toImageMultipart("profileImage"), -// defaultImageName = defaultImageName?.toPlainTextRequestBody(), - nickname = nickname.toPlainTextRequestBody(), - kakaoId = kakaoId.toString().toPlainTextRequestBody(), - deviceId = deviceId.toPlainTextRequestBody() + PostUserRequestDto(nickname, kakaoId, deviceId) ) } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/request/PostUserRequestDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/request/PostUserRequestDto.kt new file mode 100644 index 00000000..4e482c53 --- /dev/null +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/request/PostUserRequestDto.kt @@ -0,0 +1,14 @@ +package com.kuit.findu.data.dataremote.model.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class PostUserRequestDto( + @SerialName("nickname") + val nickname: String, + @SerialName("kakaoId") + val kakaoId: Long, + @SerialName("deviceId") + val deviceId: String, +) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt b/app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt index 0a3e6b33..91822f8e 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt @@ -5,6 +5,7 @@ import com.kuit.findu.data.dataremote.model.base.NullableBaseResponse import com.kuit.findu.data.dataremote.model.request.CheckNicknameRequestDto import com.kuit.findu.data.dataremote.model.request.GuestLoginRequestDto import com.kuit.findu.data.dataremote.model.request.LoginRequestDto +import com.kuit.findu.data.dataremote.model.request.PostUserRequestDto import com.kuit.findu.data.dataremote.model.response.CheckNicknameResponseDto import com.kuit.findu.data.dataremote.model.response.auth.GuestLoginResponseDto import com.kuit.findu.data.dataremote.model.response.auth.LoginResponseDto @@ -12,36 +13,28 @@ import com.kuit.findu.data.dataremote.model.response.auth.UserInfoDto import com.kuit.findu.data.dataremote.util.ApiConstraints.API import com.kuit.findu.data.dataremote.util.ApiConstraints.AUTH import com.kuit.findu.data.dataremote.util.ApiConstraints.VERSION -import okhttp3.MultipartBody -import okhttp3.RequestBody import retrofit2.http.Body import retrofit2.http.Multipart import retrofit2.http.POST -import retrofit2.http.Part interface AuthService { @POST("/$API/$VERSION/$AUTH/login/kakao") suspend fun postLogin( - @Body loginRequestDto: LoginRequestDto + @Body loginRequestDto: LoginRequestDto, ): NullableBaseResponse @POST("/$API/$VERSION/$AUTH/login/guest") suspend fun postGuestLogin( - @Body guestLoginRequestDto: GuestLoginRequestDto + @Body guestLoginRequestDto: GuestLoginRequestDto, ): NullableBaseResponse @POST("/$API/$VERSION/users/check/duplicate-nickname") suspend fun postCheckNickname( - @Body checkNicknameRequestDto: CheckNicknameRequestDto + @Body checkNicknameRequestDto: CheckNicknameRequestDto, ): BaseResponse - @Multipart @POST("/$API/$VERSION/users") suspend fun postSignup( -// @Part profileImage: MultipartBody.Part?, -// @Part("defaultProfileImageName") defaultImageName: RequestBody?, - @Part("nickname") nickname: RequestBody, - @Part("kakaoId") kakaoId: RequestBody, - @Part("deviceId") deviceId: RequestBody + @Body postUserRequestDto: PostUserRequestDto, ): NullableBaseResponse } \ No newline at end of file From af8f1a53d9c20eb15108217f321f1662634b5972 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Fri, 9 Jan 2026 23:42:45 +0900 Subject: [PATCH 17/24] =?UTF-8?q?[feat]=20=ED=86=A0=ED=81=B0=20=EC=9E=AC?= =?UTF-8?q?=EB=B0=9C=EA=B8=89=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ReissueService 인터페이스와 관련 DTO 추가 - 액세스 토큰 및 리프레시 토큰 재발급 기능 구현 --- .../model/request/TokenReissueRequestDto.kt | 10 ++++++++++ .../response/auth/TokenReissueResponseDto.kt | 12 ++++++++++++ .../data/dataremote/service/ReissueService.kt | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 app/src/main/java/com/kuit/findu/data/dataremote/model/request/TokenReissueRequestDto.kt create mode 100644 app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/TokenReissueResponseDto.kt create mode 100644 app/src/main/java/com/kuit/findu/data/dataremote/service/ReissueService.kt diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/request/TokenReissueRequestDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/request/TokenReissueRequestDto.kt new file mode 100644 index 00000000..8ecdf15c --- /dev/null +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/request/TokenReissueRequestDto.kt @@ -0,0 +1,10 @@ +package com.kuit.findu.data.dataremote.model.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class TokenReissueRequestDto( + @SerialName("refreshToken") + val refreshToken: String, +) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/TokenReissueResponseDto.kt b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/TokenReissueResponseDto.kt new file mode 100644 index 00000000..ff3a4cd6 --- /dev/null +++ b/app/src/main/java/com/kuit/findu/data/dataremote/model/response/auth/TokenReissueResponseDto.kt @@ -0,0 +1,12 @@ +package com.kuit.findu.data.dataremote.model.response.auth + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class TokenReissueResponseDto( + @SerialName("accessToken") + val accessToken: String, + @SerialName("refreshToken") + val refreshToken: String, +) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/service/ReissueService.kt b/app/src/main/java/com/kuit/findu/data/dataremote/service/ReissueService.kt new file mode 100644 index 00000000..4182837f --- /dev/null +++ b/app/src/main/java/com/kuit/findu/data/dataremote/service/ReissueService.kt @@ -0,0 +1,18 @@ +package com.kuit.findu.data.dataremote.service + +import com.kuit.findu.data.dataremote.model.base.BaseResponse +import com.kuit.findu.data.dataremote.model.request.TokenReissueRequestDto +import com.kuit.findu.data.dataremote.model.response.auth.TokenReissueResponseDto +import com.kuit.findu.data.dataremote.util.ApiConstraints.API +import com.kuit.findu.data.dataremote.util.ApiConstraints.AUTH +import com.kuit.findu.data.dataremote.util.ApiConstraints.VERSION +import retrofit2.http.Body +import retrofit2.http.POST + +interface ReissueService { + + @POST("/$API/$VERSION/$AUTH/reissue/token") + suspend fun postReissueToken( + @Body tokenReissueRequestDto: TokenReissueRequestDto, + ): BaseResponse +} \ No newline at end of file From c511eb70697076b412e77e1b6c45477cdc29f2a3 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sat, 10 Jan 2026 02:02:51 +0900 Subject: [PATCH 18/24] =?UTF-8?q?[feat]=20=ED=86=A0=ED=81=B0=20=EC=9E=AC?= =?UTF-8?q?=EB=B0=9C=EA=B8=89=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AccessToken 만료 시 RefreshToken을 사용하여 자동으로 토큰을 재발급하는 로직을 추가했습니다. - 토큰 재발급 전용 Retrofit, Service, Authenticator를 DI(Dependency Injection)를 통해 구성했습니다. - 회원가입 성공 시 발급된 AccessToken과 RefreshToken을 로컬에 저장하도록 수정했습니다. --- .../data/dataremote/util/AuthAuthenticator.kt | 55 +++++++++++++------ .../java/com/kuit/findu/di/NetworkModule.kt | 33 +++++++++-- .../java/com/kuit/findu/di/ServiceModule.kt | 7 +++ .../com/kuit/findu/di/qualifier/Qualifier.kt | 6 +- .../viewmodel/OnboardingViewModel.kt | 8 ++- 5 files changed, 83 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/util/AuthAuthenticator.kt b/app/src/main/java/com/kuit/findu/data/dataremote/util/AuthAuthenticator.kt index 63d2f5b9..ae9c3111 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/util/AuthAuthenticator.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/util/AuthAuthenticator.kt @@ -1,34 +1,53 @@ package com.kuit.findu.data.dataremote.util -import android.content.Context -import android.content.Intent import com.kuit.findu.data.datalocal.datasource.TokenLocalDataSource -import com.kuit.findu.presentation.ui.login.LoginActivity -import dagger.hilt.android.qualifiers.ApplicationContext -import okhttp3.Interceptor +import com.kuit.findu.data.dataremote.model.request.TokenReissueRequestDto +import com.kuit.findu.data.dataremote.service.ReissueService +import kotlinx.coroutines.runBlocking +import okhttp3.Authenticator +import okhttp3.Request import okhttp3.Response +import okhttp3.Route import javax.inject.Inject class AuthAuthenticator @Inject constructor( private val tokenLocalDataSource: TokenLocalDataSource, - @ApplicationContext private val context: Context -) : Interceptor { - override fun intercept(chain: Interceptor.Chain): Response { - val request = chain.request() - val response = chain.proceed(request) - + private val reissueService: ReissueService, +) : Authenticator { + override fun authenticate(route: Route?, response: Response): Request? { // 401 Unauthorized 에러 감지 if (response.code == 401) { - // 토큰 삭제 - tokenLocalDataSource.clearToken() + return try { + val refreshToken = tokenLocalDataSource.refreshToken + + // 토큰 재발급 요청 + val reissueResponse = runBlocking { + reissueService.postReissueToken( + TokenReissueRequestDto(refreshToken) + ) + } + + if (reissueResponse.success) { + // 새로운 토큰으로 저장 + tokenLocalDataSource.accessToken = reissueResponse.data.accessToken + tokenLocalDataSource.refreshToken = reissueResponse.data.refreshToken - // 로그인 화면으로 이동 - val intent = Intent(context, LoginActivity::class.java).apply { - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + // 새로운 토큰으로 원래 요청 재시도 + response.request.newBuilder() + .header("Authorization", "Bearer ${reissueResponse.data.accessToken}") + .build() + } else { + // 토큰 재발급 실패 - 로그인 화면으로 이동 + tokenLocalDataSource.clearToken() + null + } + } catch (e: Exception) { + // 토큰 재발급 중 오류 발생 - 로그인 화면으로 이동 + tokenLocalDataSource.clearToken() + null } - context.startActivity(intent) } - return response + return null } } diff --git a/app/src/main/java/com/kuit/findu/di/NetworkModule.kt b/app/src/main/java/com/kuit/findu/di/NetworkModule.kt index 7a938353..cb7ff881 100644 --- a/app/src/main/java/com/kuit/findu/di/NetworkModule.kt +++ b/app/src/main/java/com/kuit/findu/di/NetworkModule.kt @@ -6,10 +6,12 @@ import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFact import com.kuit.findu.BuildConfig import com.kuit.findu.BuildConfig.DEBUG import com.kuit.findu.data.datalocal.datasource.TokenLocalDataSource +import com.kuit.findu.data.dataremote.service.ReissueService import com.kuit.findu.data.dataremote.util.AuthAuthenticator import com.kuit.findu.data.dataremote.util.AuthInterceptor import com.kuit.findu.data.dataremote.util.DiscordLogger import com.kuit.findu.data.dataremote.util.ErrorTrackingInterceptor +import com.kuit.findu.di.qualifier.ReissueRetrofit import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -54,7 +56,7 @@ object NetworkModule { addInterceptor(authInterceptor) if (DEBUG) addInterceptor(loggingInterceptor) else addInterceptor(errorTrackingInterceptor) - addInterceptor(authAuthenticator) + authenticator(authAuthenticator) }.build() @Provides @@ -77,24 +79,23 @@ object NetworkModule { @Singleton fun provideAuthAuthenticator( tokenLocalDataSource: TokenLocalDataSource, - @ApplicationContext context: Context, + reissueService: ReissueService, ): AuthAuthenticator { - return AuthAuthenticator(tokenLocalDataSource, context) + return AuthAuthenticator(tokenLocalDataSource, reissueService) } @Provides @Singleton fun provideErrorTrackingInterceptor( firebaseCrashlytics: FirebaseCrashlytics, - discordLogger: DiscordLogger + discordLogger: DiscordLogger, ): ErrorTrackingInterceptor { return ErrorTrackingInterceptor( - firebaseCrashlytics= firebaseCrashlytics, + firebaseCrashlytics = firebaseCrashlytics, discordLogger = discordLogger ) } - @ExperimentalSerializationApi @Provides @Singleton fun providesRetrofit( @@ -108,4 +109,24 @@ object NetworkModule { json.asConverterFactory(requireNotNull("application/json".toMediaTypeOrNull())) ) .build() + + @Provides + @ReissueRetrofit + @Singleton + fun providesReissueRetrofit( + loggingInterceptor: HttpLoggingInterceptor, + json: Json, + ): Retrofit { + val authOkHttpClient = OkHttpClient.Builder().apply { + readTimeout(20, TimeUnit.SECONDS) + if (DEBUG) addInterceptor(loggingInterceptor) + }.build() + return Retrofit.Builder() + .baseUrl(BuildConfig.BASE_URL) + .client(authOkHttpClient) + .addConverterFactory( + json.asConverterFactory(requireNotNull("application/json".toMediaTypeOrNull())) + ) + .build() + } } diff --git a/app/src/main/java/com/kuit/findu/di/ServiceModule.kt b/app/src/main/java/com/kuit/findu/di/ServiceModule.kt index 469be617..e2b4d870 100644 --- a/app/src/main/java/com/kuit/findu/di/ServiceModule.kt +++ b/app/src/main/java/com/kuit/findu/di/ServiceModule.kt @@ -12,8 +12,10 @@ import com.kuit.findu.data.dataremote.service.InquiryService import com.kuit.findu.data.dataremote.service.InterestService import com.kuit.findu.data.dataremote.service.MyService import com.kuit.findu.data.dataremote.service.NaverService +import com.kuit.findu.data.dataremote.service.ReissueService import com.kuit.findu.data.dataremote.service.ReportService import com.kuit.findu.data.dataremote.service.SearchService +import com.kuit.findu.di.qualifier.ReissueRetrofit import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -115,4 +117,9 @@ object ServiceModule { @Singleton fun provideInquiryService(retrofit: Retrofit): InquiryService = retrofit.create(InquiryService::class.java) + + @Provides + @Singleton + fun provideReissueService(@ReissueRetrofit reissueRetrofit: Retrofit): ReissueService = + reissueRetrofit.create(ReissueService::class.java) } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/di/qualifier/Qualifier.kt b/app/src/main/java/com/kuit/findu/di/qualifier/Qualifier.kt index 89d424b9..29ddb2fe 100644 --- a/app/src/main/java/com/kuit/findu/di/qualifier/Qualifier.kt +++ b/app/src/main/java/com/kuit/findu/di/qualifier/Qualifier.kt @@ -8,4 +8,8 @@ annotation class TokenPrefs @Qualifier @Retention(AnnotationRetention.BINARY) -annotation class DeviceIdPrefs \ No newline at end of file +annotation class DeviceIdPrefs + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class ReissueRetrofit \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt index 1d953d2a..e453b4af 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt @@ -9,6 +9,8 @@ import com.kuit.findu.analytics.AnalyticsHelper import com.kuit.findu.analytics.logUserSignUp import com.kuit.findu.domain.usecase.auth.PostCheckNicknameUseCase import com.kuit.findu.domain.usecase.auth.PostSignupUseCase +import com.kuit.findu.domain.usecase.token.SetAccessTokenUseCase +import com.kuit.findu.domain.usecase.token.SetRefreshTokenUseCase import com.kuit.findu.presentation.type.DefaultProfileType import com.kuit.findu.presentation.type.NicknameValidType import dagger.hilt.android.lifecycle.HiltViewModel @@ -37,6 +39,8 @@ class OnboardingViewModel @Inject constructor( @ApplicationContext private val context: Context, private val postCheckNicknameUseCase: PostCheckNicknameUseCase, private val postSignupUseCase: PostSignupUseCase, + private val setAccessTokenUseCase: SetAccessTokenUseCase, + private val setRefreshTokenUseCase: SetRefreshTokenUseCase, private val analyticsHelper: AnalyticsHelper, ) : ViewModel() { private val _uiState = MutableStateFlow(OnboardingUiState()) @@ -122,8 +126,10 @@ class OnboardingViewModel @Inject constructor( defaultImageName = uiState.value.defaultProfileType.string, nickname = uiState.value.nickname, kakaoId = uiState.value.kakaoId - ).onSuccess { + ).onSuccess { data -> analyticsHelper.logUserSignUp(userName = uiState.value.nickname) + setAccessTokenUseCase(data.accessToken) + setRefreshTokenUseCase(data.refreshToken) startMainActivity() }.onFailure { e -> Log.d("http", "Error Message: : $e") From de3647cd52664e72e75965ebf0eadfdc40d0ef71 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sat, 10 Jan 2026 02:18:37 +0900 Subject: [PATCH 19/24] =?UTF-8?q?[feat]=20=EA=B2=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=8B=9C=20=EC=9D=B4=EB=AF=B8=20?= =?UTF-8?q?=EA=B0=80=EC=9E=85=EB=90=9C=20=EA=B3=84=EC=A0=95=EC=9D=B4?= =?UTF-8?q?=EB=A9=B4=20=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 404 에러를 처리하기 위한 `ApiNotFoundException` 추가 - ApiResponseHandler에서 404 코드를 받으면 `ApiNotFoundException`을 발생시키도록 수정 - 게스트 로그인 실패 시 `ApiNotFoundException`인 경우, "가입된 계정이 있습니다. 카카오 계정으로 로그인해주세요." 라는 에러 메시지를 표시하도록 구현 --- .../data/dataremote/exception/ApiNotFoundException.kt | 5 +++++ .../findu/data/dataremote/util/ApiResponseHandler.kt | 8 +++++++- .../presentation/ui/login/viewmodel/LoginViewModel.kt | 10 +++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/kuit/findu/data/dataremote/exception/ApiNotFoundException.kt diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/exception/ApiNotFoundException.kt b/app/src/main/java/com/kuit/findu/data/dataremote/exception/ApiNotFoundException.kt new file mode 100644 index 00000000..6f466462 --- /dev/null +++ b/app/src/main/java/com/kuit/findu/data/dataremote/exception/ApiNotFoundException.kt @@ -0,0 +1,5 @@ +package com.kuit.findu.data.dataremote.exception + +class ApiNotFoundException( + message: String, +) : Exception(message) diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/util/ApiResponseHandler.kt b/app/src/main/java/com/kuit/findu/data/dataremote/util/ApiResponseHandler.kt index 80c14513..5e066fdc 100644 --- a/app/src/main/java/com/kuit/findu/data/dataremote/util/ApiResponseHandler.kt +++ b/app/src/main/java/com/kuit/findu/data/dataremote/util/ApiResponseHandler.kt @@ -1,5 +1,6 @@ package com.kuit.findu.data.dataremote.util +import com.kuit.findu.data.dataremote.exception.ApiNotFoundException import com.kuit.findu.data.dataremote.model.base.BaseResponse import com.kuit.findu.data.dataremote.model.base.NullableBaseResponse @@ -28,8 +29,13 @@ fun NullableBaseResponse.handleBaseResponse(): Result = Result.success(this.data) } + in 400..499 -> { // 클라이언트 에러 - Result.failure(Exception("Client error : ${this.message}")) + if (this.code == 404) { + Result.failure(ApiNotFoundException("Client error : ${this.message}")) + } else { + Result.failure(Exception("Client error : ${this.message}")) + } } in 500..599 -> { // 서버 에러 diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt index 54e85633..a6df17c5 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.kuit.findu.analytics.AnalyticsHelper import com.kuit.findu.analytics.logUserSignIn +import com.kuit.findu.data.dataremote.exception.ApiNotFoundException import com.kuit.findu.domain.usecase.SetNicknameUseCase import com.kuit.findu.domain.usecase.auth.PostGuestLoginUseCase import com.kuit.findu.domain.usecase.auth.PostLoginUseCase @@ -33,6 +34,9 @@ class LoginViewModel @Inject constructor( private val _startOnboardingActivity = MutableSharedFlow() val startOnboardingActivity: SharedFlow = _startOnboardingActivity + private val _errorMessage = MutableSharedFlow() + val errorMessage: SharedFlow = _errorMessage + fun postLogin(kakaoId: Long) { viewModelScope.launch { loginUseCase.postLogin(kakaoId = kakaoId).onSuccess { loginData -> @@ -65,6 +69,11 @@ class LoginViewModel @Inject constructor( startMainActivity() } .onFailure { e -> + if(e is ApiNotFoundException) { + viewModelScope.launch { + _errorMessage.emit("가입된 계정이 있습니다.\n카카오 계정으로 로그인해주세요.") + } + } Log.d("http", "Error Message: : $e") } } @@ -82,6 +91,5 @@ class LoginViewModel @Inject constructor( _startOnboardingActivity.emit(kakaoId) } } - } From 450d33bd683c829fe2ad38110c746908dfc71cb3 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Sat, 10 Jan 2026 05:58:20 +0900 Subject: [PATCH 20/24] =?UTF-8?q?[feat]=20=EA=B2=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=EC=A0=9C=EB=B3=B4=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 게스트 로그인 여부를 저장하고 확인하는 로직을 추가했습니다. - `UserInfoRepository` 및 `DeviceLocalDataSource`에 `isGuestLogin` 관련 함수/변수 추가 - 로그인 및 회원가입 시 `isGuestLogin` 상태를 `false`로 설정 - 게스트 로그인 시 `isGuestLogin` 상태를 `true`로 설정 - 홈 화면에서 제보하기 관련 기능(실종/발견 제보, 제보 다이얼로그)을 사용할 때, 게스트 유저일 경우 "로그인을 하고 제보해주세요!" 라는 토스트 메시지를 표시하도록 수정했습니다. --- .../datasource/DeviceLocalDataSource.kt | 1 + .../DeviceLocalDataSourceImpl.kt | 5 +++++ .../repositoryimpl/UserInfoRepositoryImpl.kt | 8 ++++++- .../java/com/kuit/findu/di/UseCaseModule.kt | 14 ++++++++++++ .../domain/repository/UserInfoRepository.kt | 2 ++ .../domain/usecase/GetIsGuestLoginUseCase.kt | 12 ++++++++++ .../domain/usecase/SetIsGuestLoginUseCase.kt | 12 ++++++++++ .../domain/usecase/auth/PostSignupUseCase.kt | 4 +++- .../ui/home/viewmodel/HomeViewModel.kt | 22 ++++++++++++++++--- .../ui/login/viewmodel/LoginViewModel.kt | 4 ++++ .../viewmodel/OnboardingViewModel.kt | 3 +++ 11 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/kuit/findu/domain/usecase/GetIsGuestLoginUseCase.kt create mode 100644 app/src/main/java/com/kuit/findu/domain/usecase/SetIsGuestLoginUseCase.kt diff --git a/app/src/main/java/com/kuit/findu/data/datalocal/datasource/DeviceLocalDataSource.kt b/app/src/main/java/com/kuit/findu/data/datalocal/datasource/DeviceLocalDataSource.kt index 4a454114..c5603986 100644 --- a/app/src/main/java/com/kuit/findu/data/datalocal/datasource/DeviceLocalDataSource.kt +++ b/app/src/main/java/com/kuit/findu/data/datalocal/datasource/DeviceLocalDataSource.kt @@ -3,6 +3,7 @@ package com.kuit.findu.data.datalocal.datasource interface DeviceLocalDataSource { var deviceId: String var nickname: String + var isGuestLogin: Boolean fun clear() } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/data/datalocal/datasourceimpl/DeviceLocalDataSourceImpl.kt b/app/src/main/java/com/kuit/findu/data/datalocal/datasourceimpl/DeviceLocalDataSourceImpl.kt index 09885d8e..7f55fde1 100644 --- a/app/src/main/java/com/kuit/findu/data/datalocal/datasourceimpl/DeviceLocalDataSourceImpl.kt +++ b/app/src/main/java/com/kuit/findu/data/datalocal/datasourceimpl/DeviceLocalDataSourceImpl.kt @@ -23,6 +23,10 @@ class DeviceLocalDataSourceImpl @Inject constructor( get() = sharedPreferences.getString(NICKNAME, INITIAL_VALUE).toString() set(value) = sharedPreferences.edit { putString(NICKNAME, value) } + override var isGuestLogin: Boolean + get() = sharedPreferences.getBoolean(IS_GUEST_LOGIN, false) + set(value) = sharedPreferences.edit { putBoolean(IS_GUEST_LOGIN, value) } + override fun clear() { val currentDeviceId = deviceId sharedPreferences.edit { @@ -34,6 +38,7 @@ class DeviceLocalDataSourceImpl @Inject constructor( const val PREFERENCES_NAME = "device_preferences" const val DEVICE_ID = "deviceId" const val NICKNAME = "nickname" + const val IS_GUEST_LOGIN = "isGuestLogin" const val INITIAL_VALUE = "" } diff --git a/app/src/main/java/com/kuit/findu/data/repositoryimpl/UserInfoRepositoryImpl.kt b/app/src/main/java/com/kuit/findu/data/repositoryimpl/UserInfoRepositoryImpl.kt index 44d402e0..83bbc326 100644 --- a/app/src/main/java/com/kuit/findu/data/repositoryimpl/UserInfoRepositoryImpl.kt +++ b/app/src/main/java/com/kuit/findu/data/repositoryimpl/UserInfoRepositoryImpl.kt @@ -5,7 +5,7 @@ import com.kuit.findu.domain.repository.UserInfoRepository import javax.inject.Inject class UserInfoRepositoryImpl @Inject constructor( - private val deviceLocalDataSource: DeviceLocalDataSource + private val deviceLocalDataSource: DeviceLocalDataSource, ) : UserInfoRepository { override fun getDeviceId(): String = deviceLocalDataSource.deviceId @@ -19,5 +19,11 @@ class UserInfoRepositoryImpl @Inject constructor( deviceLocalDataSource.nickname = nickname } + override fun getIsGuestLogin(): Boolean = deviceLocalDataSource.isGuestLogin + + override fun setIsGuestLogin(isGuest: Boolean) { + deviceLocalDataSource.isGuestLogin = isGuest + } + override fun clear() = deviceLocalDataSource.clear() } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/di/UseCaseModule.kt b/app/src/main/java/com/kuit/findu/di/UseCaseModule.kt index 484a284b..f180ea38 100644 --- a/app/src/main/java/com/kuit/findu/di/UseCaseModule.kt +++ b/app/src/main/java/com/kuit/findu/di/UseCaseModule.kt @@ -14,9 +14,11 @@ import com.kuit.findu.domain.repository.report.ReportRepository import com.kuit.findu.domain.usecase.GetBreedDataUseCase import com.kuit.findu.domain.usecase.GetBreedValidationUseCase import com.kuit.findu.domain.usecase.GetDetailSearchUseCase +import com.kuit.findu.domain.usecase.GetIsGuestLoginUseCase import com.kuit.findu.domain.usecase.GetNicknameUseCase import com.kuit.findu.domain.usecase.GetSearchUseCase import com.kuit.findu.domain.usecase.PostAiDetectionUseCase +import com.kuit.findu.domain.usecase.SetIsGuestLoginUseCase import com.kuit.findu.domain.usecase.SetNicknameUseCase import com.kuit.findu.domain.usecase.auth.PostCheckNicknameUseCase import com.kuit.findu.domain.usecase.auth.PostGuestLoginUseCase @@ -290,4 +292,16 @@ object UseCaseModule { fun provideGetSigunguUseCase( informationRepository: InformationRepository, ): GetSigunguUseCase = GetSigunguUseCase(informationRepository) + + @Provides + @Singleton + fun provideSetIsGuestLoginUseCase( + userInfoRepository: UserInfoRepository, + ): SetIsGuestLoginUseCase = SetIsGuestLoginUseCase(userInfoRepository) + + @Provides + @Singleton + fun provideGetIsGuestLoginUseCase( + userInfoRepository: UserInfoRepository, + ): GetIsGuestLoginUseCase = GetIsGuestLoginUseCase(userInfoRepository) } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/domain/repository/UserInfoRepository.kt b/app/src/main/java/com/kuit/findu/domain/repository/UserInfoRepository.kt index d4f5c8e2..547978db 100644 --- a/app/src/main/java/com/kuit/findu/domain/repository/UserInfoRepository.kt +++ b/app/src/main/java/com/kuit/findu/domain/repository/UserInfoRepository.kt @@ -5,5 +5,7 @@ interface UserInfoRepository { fun setDeviceId(deviceId: String) fun getNickname(): String fun setNickname(nickname: String) + fun getIsGuestLogin(): Boolean + fun setIsGuestLogin(isGuest: Boolean) fun clear() } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/domain/usecase/GetIsGuestLoginUseCase.kt b/app/src/main/java/com/kuit/findu/domain/usecase/GetIsGuestLoginUseCase.kt new file mode 100644 index 00000000..bd028c2d --- /dev/null +++ b/app/src/main/java/com/kuit/findu/domain/usecase/GetIsGuestLoginUseCase.kt @@ -0,0 +1,12 @@ +package com.kuit.findu.domain.usecase + +import com.kuit.findu.domain.repository.UserInfoRepository +import javax.inject.Inject + +class GetIsGuestLoginUseCase @Inject constructor( + private val userInfoRepository: UserInfoRepository +) { + operator fun invoke(): Boolean { + return userInfoRepository.getIsGuestLogin() + } +} diff --git a/app/src/main/java/com/kuit/findu/domain/usecase/SetIsGuestLoginUseCase.kt b/app/src/main/java/com/kuit/findu/domain/usecase/SetIsGuestLoginUseCase.kt new file mode 100644 index 00000000..f3ac1051 --- /dev/null +++ b/app/src/main/java/com/kuit/findu/domain/usecase/SetIsGuestLoginUseCase.kt @@ -0,0 +1,12 @@ +package com.kuit.findu.domain.usecase + +import com.kuit.findu.domain.repository.UserInfoRepository +import javax.inject.Inject + +class SetIsGuestLoginUseCase @Inject constructor( + private val userInfoRepository: UserInfoRepository +) { + suspend operator fun invoke(isGuest: Boolean) { + userInfoRepository.setIsGuestLogin(isGuest) + } +} diff --git a/app/src/main/java/com/kuit/findu/domain/usecase/auth/PostSignupUseCase.kt b/app/src/main/java/com/kuit/findu/domain/usecase/auth/PostSignupUseCase.kt index e065a309..71557784 100644 --- a/app/src/main/java/com/kuit/findu/domain/usecase/auth/PostSignupUseCase.kt +++ b/app/src/main/java/com/kuit/findu/domain/usecase/auth/PostSignupUseCase.kt @@ -22,6 +22,8 @@ class PostSignupUseCase( nickname = nickname, kakaoId = kakaoId, deviceId = userInfoRepository.getDeviceId() - ) + ).onSuccess { + userInfoRepository.setIsGuestLogin(false) + } } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt index ce7d67dc..de8c4ccb 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt @@ -7,6 +7,7 @@ import com.kuit.findu.data.dataremote.util.AuthenticationException import com.kuit.findu.domain.model.HomeData import com.kuit.findu.domain.model.ProtectAnimal import com.kuit.findu.domain.model.ReportAnimal +import com.kuit.findu.domain.usecase.GetIsGuestLoginUseCase import com.kuit.findu.domain.usecase.GetNicknameUseCase import com.kuit.findu.domain.usecase.home.GetHomeUseCase import com.kuit.findu.presentation.type.HomeReportDurationType @@ -87,6 +88,7 @@ sealed class HomeUiEffect { class HomeViewModel @Inject constructor( private val homeUseCase: GetHomeUseCase, private val getNicknameUseCase: GetNicknameUseCase, + private val getIsGuestLoginUseCase: GetIsGuestLoginUseCase, ) : ViewModel() { private val _uiState = MutableStateFlow(HomeUiState()) @@ -114,7 +116,13 @@ class HomeViewModel @Inject constructor( is HomeUiEvent.OnHomeReportDurationClick -> changeReportDuration(event.duration) is HomeUiEvent.OnReportDialogClick -> { - _uiState.update { it.copy(isReportDialogVisible = true) } + if (getIsGuestLoginUseCase()) { + viewModelScope.launch { + _uiEffect.send(HomeUiEffect.ShowToast("로그인 이후에 제보해주세요!")) + } + } else { + _uiState.update { it.copy(isReportDialogVisible = true) } + } } is HomeUiEvent.OnReportDialogDismiss -> { @@ -241,13 +249,21 @@ class HomeViewModel @Inject constructor( fun navigateToLostReport() { viewModelScope.launch { - _uiEffect.send(HomeUiEffect.NavigateToLostReport) + if (getIsGuestLoginUseCase()) { + _uiEffect.send(HomeUiEffect.ShowToast("로그인 이후에 제보해주세요!")) + } else { + _uiEffect.send(HomeUiEffect.NavigateToLostReport) + } } } fun navigateToFindReport() { viewModelScope.launch { - _uiEffect.send(HomeUiEffect.NavigateToFindReport) + if (getIsGuestLoginUseCase()) { + _uiEffect.send(HomeUiEffect.ShowToast("로그인 이후에 제보해주세요!")) + } else { + _uiEffect.send(HomeUiEffect.NavigateToFindReport) + } } } diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt index a6df17c5..b883ffe2 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope import com.kuit.findu.analytics.AnalyticsHelper import com.kuit.findu.analytics.logUserSignIn import com.kuit.findu.data.dataremote.exception.ApiNotFoundException +import com.kuit.findu.domain.usecase.SetIsGuestLoginUseCase import com.kuit.findu.domain.usecase.SetNicknameUseCase import com.kuit.findu.domain.usecase.auth.PostGuestLoginUseCase import com.kuit.findu.domain.usecase.auth.PostLoginUseCase @@ -25,6 +26,7 @@ class LoginViewModel @Inject constructor( private val setAccessTokenUseCase: SetAccessTokenUseCase, private val setRefreshTokenUseCase: SetRefreshTokenUseCase, private val setNicknameUseCase: SetNicknameUseCase, + private val setIsGuestLoginUseCase: SetIsGuestLoginUseCase, private val analyticsHelper: AnalyticsHelper, ) : ViewModel() { private val _startMainActivity = MutableSharedFlow() @@ -49,6 +51,7 @@ class LoginViewModel @Inject constructor( setAccessTokenUseCase(accessToken = loginData.userInfo!!.accessToken) setRefreshTokenUseCase(refreshToken = loginData.userInfo.refreshToken) setNicknameUseCase(nickname = loginData.userInfo.nickname) + setIsGuestLoginUseCase(isGuest = false) startMainActivity() } }.onFailure { e -> @@ -65,6 +68,7 @@ class LoginViewModel @Inject constructor( setAccessTokenUseCase(accessToken = loginData.accessToken) setRefreshTokenUseCase(refreshToken = loginData.refreshToken) setNicknameUseCase(nickname = GUEST_NAME) + setIsGuestLoginUseCase(isGuest = true) onSuccess() startMainActivity() } diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt index e453b4af..6cab8657 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.kuit.findu.analytics.AnalyticsHelper import com.kuit.findu.analytics.logUserSignUp +import com.kuit.findu.domain.usecase.SetIsGuestLoginUseCase import com.kuit.findu.domain.usecase.auth.PostCheckNicknameUseCase import com.kuit.findu.domain.usecase.auth.PostSignupUseCase import com.kuit.findu.domain.usecase.token.SetAccessTokenUseCase @@ -41,6 +42,7 @@ class OnboardingViewModel @Inject constructor( private val postSignupUseCase: PostSignupUseCase, private val setAccessTokenUseCase: SetAccessTokenUseCase, private val setRefreshTokenUseCase: SetRefreshTokenUseCase, + private val setIsGuestLoginUseCase: SetIsGuestLoginUseCase, private val analyticsHelper: AnalyticsHelper, ) : ViewModel() { private val _uiState = MutableStateFlow(OnboardingUiState()) @@ -130,6 +132,7 @@ class OnboardingViewModel @Inject constructor( analyticsHelper.logUserSignUp(userName = uiState.value.nickname) setAccessTokenUseCase(data.accessToken) setRefreshTokenUseCase(data.refreshToken) + setIsGuestLoginUseCase(false) startMainActivity() }.onFailure { e -> Log.d("http", "Error Message: : $e") From b96e2d9627895ee3863a759814f64b81fc6f6df4 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:14:03 +0900 Subject: [PATCH 21/24] =?UTF-8?q?[feat]=20=ED=99=88=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EC=B5=9C=EC=83=81=EB=8B=A8=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EB=B2=84=ED=8A=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 홈 화면에서 스크롤을 최상단으로 이동시키는 버튼과 관련 로직을 제거했습니다. - `HomeScrollToTopButton` 컴포저블을 삭제했습니다. - `HomeScreen`에서 스크롤 위치에 따라 버튼을 표시하는 로직을 제거했습니다. - `HomeViewModel`에서 버튼 표시 여부를 관리하던 `isScrollToTopVisible` 상태와 관련 이벤트를 삭제했습니다. --- .../home/component/HomeScrollToTopButton.kt | 41 ------------------- .../ui/home/composeview/HomeScreen.kt | 30 +------------- .../ui/home/viewmodel/HomeViewModel.kt | 10 +---- 3 files changed, 2 insertions(+), 79 deletions(-) delete mode 100644 app/src/main/java/com/kuit/findu/presentation/ui/home/component/HomeScrollToTopButton.kt diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/home/component/HomeScrollToTopButton.kt b/app/src/main/java/com/kuit/findu/presentation/ui/home/component/HomeScrollToTopButton.kt deleted file mode 100644 index 58e2cfcd..00000000 --- a/app/src/main/java/com/kuit/findu/presentation/ui/home/component/HomeScrollToTopButton.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.kuit.findu.presentation.ui.home.component - -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.kuit.findu.R -import com.kuit.findu.presentation.ui.base.BaseVectorIcon -import com.kuit.findu.presentation.util.extension.noRippleClickable -import com.kuit.findu.ui.theme.FindUTheme - -@Composable -fun HomeScrollToTopButton(onClick: () -> Unit, modifier: Modifier = Modifier) { - Box( - modifier = modifier - .background(shape = CircleShape, color = FindUTheme.colors.white) - .border( - width = 1.dp, - color = FindUTheme.colors.gray3, - shape = CircleShape - ) - .padding(11.dp) - .noRippleClickable(onClick), contentAlignment = Alignment.Center - ) { - BaseVectorIcon(vectorResource = R.drawable.ic_arrow_top_white_24, tint = FindUTheme.colors.gray4) - } -} - -@Preview -@Composable -private fun HomeScrollToTopButtonPreview() { - HomeScrollToTopButton( - onClick = {} - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/home/composeview/HomeScreen.kt b/app/src/main/java/com/kuit/findu/presentation/ui/home/composeview/HomeScreen.kt index 6ccdf2d9..214686a4 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/home/composeview/HomeScreen.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/home/composeview/HomeScreen.kt @@ -15,13 +15,10 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -38,7 +35,6 @@ import com.kuit.findu.presentation.ui.home.component.HomeProtectAnimalList import com.kuit.findu.presentation.ui.home.component.HomeReportCard import com.kuit.findu.presentation.ui.home.component.HomeReportDialog import com.kuit.findu.presentation.ui.home.component.HomeReportedAnimalList -import com.kuit.findu.presentation.ui.home.component.HomeScrollToTopButton import com.kuit.findu.presentation.ui.home.component.HomeTopBar import com.kuit.findu.presentation.ui.home.component.HomeWebLinkList import com.kuit.findu.presentation.ui.home.viewmodel.HomeUiState @@ -46,7 +42,6 @@ import com.kuit.findu.ui.theme.FindUTheme import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.rememberPagerState import kotlinx.coroutines.delay -import kotlinx.coroutines.launch @OptIn(ExperimentalPagerApi::class) @@ -72,17 +67,6 @@ fun HomeScreen( val bannerList = HomeBannerType.entries val pagerState = rememberPagerState() val listState = rememberLazyListState() - val coroutineScope = rememberCoroutineScope() - - val isLastItemVisible = remember { - derivedStateOf { - val layoutInfo = listState.layoutInfo - val totalItemsCount = layoutInfo.totalItemsCount - val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: -1 - - lastVisibleItem == totalItemsCount - 1 - } - } LaunchedEffect(pagerState) { while (true) { @@ -186,18 +170,6 @@ fun HomeScreen( } } } - if (isLastItemVisible.value) { - HomeScrollToTopButton( - onClick = { - coroutineScope.launch { - listState.animateScrollToItem(0) - } - }, - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(bottom = 60.dp, end = 20.dp) - ) - } if (uiState.isReportDialogVisible) { HomeReportDialog( onDismissRequest = onReportDialogDismiss, @@ -237,4 +209,4 @@ private fun HomeScreenPreview() { navigateToHomeExtra = {}, ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt index de8c4ccb..c4cda3eb 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt @@ -33,7 +33,6 @@ data class HomeUiState( val nickname: String = "", val isRefreshing: Boolean = false, val bannerCurrentPage: Int = 0, - val isScrollToTopVisible: Boolean = false, val isReportDialogVisible: Boolean = false, val locationPermission: Boolean = false, ) { @@ -63,7 +62,6 @@ sealed class HomeUiEvent { data class OnBannerPageChanged(val page: Int) : HomeUiEvent() - data class OnScrollPositionChanged(val firstVisibleItemIndex: Int) : HomeUiEvent() data class SetLocationPermission(val locationPermission: Boolean) : HomeUiEvent() data object SetUserNickname : HomeUiEvent() @@ -111,7 +109,6 @@ class HomeViewModel @Inject constructor( is HomeUiEvent.ClearError -> clearError() is HomeUiEvent.OnBannerPageChanged -> updateBannerPage(event.page) - is HomeUiEvent.OnScrollPositionChanged -> updateScrollToTopVisibility(event.firstVisibleItemIndex) is HomeUiEvent.OnAlarmButtonClick -> alarmButtonClicked() is HomeUiEvent.OnHomeReportDurationClick -> changeReportDuration(event.duration) @@ -277,9 +274,4 @@ class HomeViewModel @Inject constructor( _uiState.update { it.copy(bannerCurrentPage = page) } } - private fun updateScrollToTopVisibility(firstVisibleItemIndex: Int) { - val isVisible = firstVisibleItemIndex > 2 - _uiState.update { it.copy(isScrollToTopVisible = isVisible) } - } - -} \ No newline at end of file +} From 3bfa6be8a052ed7f3f7d32852972d3d82b8daf5d Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:41:28 +0900 Subject: [PATCH 22/24] =?UTF-8?q?[chore]=20=EC=95=B1=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=20=EC=A0=95=EB=B3=B4=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 앱의 `versionCode`를 12에서 13으로, `versionName`을 "1.0.11"에서 "1.0.12"로 업데이트했습니다. --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2330c379..2f1c029f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,8 +24,8 @@ android { applicationId = "com.kuit.findu" minSdk = 28 targetSdk = 35 - versionCode = 12 - versionName = "1.0.11" + versionCode = 13 + versionName = "1.0.12" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" buildConfigField("String", "GPT_KEY", properties["GPT_KEY"].toString()) From d202b7f0400a344d944d62708acac5c2558405c1 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:38:46 +0900 Subject: [PATCH 23/24] =?UTF-8?q?[feat]=20Proguard=20=EA=B7=9C=EC=B9=99=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 코드 난독화 및 최적화를 위해 Proguard 규칙을 추가했습니다. - Retrofit, OkHttp, Kotlinx Serialization 등 외부 라이브러리에 대한 keep 규칙을 설정하여 앱이 정상적으로 동작하도록 했습니다. - Hilt, Glide, Naver Map, CameraX, Kakao SDK, Firebase 등 주요 SDK에 대한 규칙을 추가했습니다. - 데이터 클래스, 뷰모델, Jetpack Compose 관련 클래스들이 난독화 대상에서 제외되도록 설정했습니다. --- app/proguard-rules.pro | 166 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 152 insertions(+), 14 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb434..97f999fc 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -5,17 +5,155 @@ # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +# Keep line numbers for debugging +-keepattributes SourceFile,LineNumberTable +-renamesourcefileattribute SourceFile + +# Keep annotations +-keepattributes *Annotation* +-keepattributes Signature +-keepattributes Exceptions + +# ========== Retrofit & OkHttp ========== +-dontwarn okhttp3.** +-dontwarn okio.** +-dontwarn javax.annotation.** +-keepclasseswithmembers class * { + @retrofit2.http.* ; +} +-keepclassmembers,allowshrinking,allowobfuscation interface * { + @retrofit2.http.* ; +} +-if interface * { @retrofit2.http.* ; } +-keep,allowobfuscation interface <1> + +# ========== Kotlinx Serialization ========== +-keepattributes *Annotation*, InnerClasses +-dontnote kotlinx.serialization.AnnotationsKt +-keepclassmembers class kotlinx.serialization.json.** { + *** Companion; +} +-keepclasseswithmembers class kotlinx.serialization.json.** { + kotlinx.serialization.KSerializer serializer(...); +} +-keep,includedescriptorclasses class com.kuit.findu.**$$serializer { *; } +-keepclassmembers class com.kuit.findu.** { + *** Companion; +} +-keepclasseswithmembers class com.kuit.findu.** { + kotlinx.serialization.KSerializer serializer(...); +} + +# Keep all data classes and their properties +-keep class com.kuit.findu.data.** { *; } +-keep class com.kuit.findu.domain.** { *; } + +# ========== Hilt ========== +-dontwarn com.google.errorprone.annotations.** +-keep class dagger.** { *; } +-keep class javax.inject.** { *; } +-keep class * extends dagger.hilt.android.internal.managers.ViewComponentManager$FragmentContextWrapper { *; } +-keep class * implements dagger.hilt.internal.GeneratedComponent { *; } +-keep class * implements dagger.hilt.internal.GeneratesRootInput { *; } +-keep class dagger.hilt.** { *; } +-keep class javax.inject.** { *; } +-keep class * extends dagger.hilt.android.lifecycle.HiltViewModel { *; } + +# ========== Glide ========== +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep class * extends com.bumptech.glide.module.AppGlideModule { + (...); +} +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} +-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { + *** rewind(); +} + +# ========== Naver Map SDK ========== +-keep class com.naver.maps.** { *; } +-keep interface com.naver.maps.** { *; } +-dontwarn com.naver.maps.** + +# ========== CameraX ========== +-keep class androidx.camera.** { *; } +-dontwarn androidx.camera.** + +# ========== Kakao SDK ========== +-keep class com.kakao.sdk.**.model.* { ; } +-keep class * extends com.google.gson.TypeAdapter +-keep class com.kakao.sdk.auth.** { *; } +-keep class com.kakao.sdk.user.** { *; } +-keep class com.kakao.sdk.common.** { *; } + +# ========== Firebase ========== +-keep class com.google.firebase.** { *; } +-keep class com.google.android.gms.** { *; } +-dontwarn com.google.firebase.** +-dontwarn com.google.android.gms.** + +# ========== Jetpack Compose ========== +-keep class androidx.compose.** { *; } +-keep class androidx.compose.runtime.** { *; } +-keep class androidx.compose.ui.** { *; } +-dontwarn androidx.compose.** + +# Keep ViewModels +-keep class * extends androidx.lifecycle.ViewModel { + (); +} +-keep class * extends androidx.lifecycle.AndroidViewModel { + (android.app.Application); +} + +# ========== AndroidX Navigation ========== +-keep class androidx.navigation.fragment.NavHostFragment { *; } +-keepnames class * extends android.os.Parcelable +-keepnames class * extends java.io.Serializable + +# ========== Material Components ========== +-keep class com.google.android.material.** { *; } +-dontwarn com.google.android.material.** + +# ========== ViewBinding & DataBinding ========== +-keep class * implements androidx.viewbinding.ViewBinding { + public static * inflate(android.view.LayoutInflater); + public static * inflate(android.view.LayoutInflater, android.view.ViewGroup, boolean); + public static * bind(android.view.View); +} + +# ========== Lottie ========== +-keep class com.airbnb.lottie.** { *; } +-dontwarn com.airbnb.lottie.** + +# ========== WebView ========== +-keepclassmembers class * { + @android.webkit.JavascriptInterface ; +} + +# ========== Kotlin ========== +-keep class kotlin.** { *; } +-keep class kotlin.Metadata { *; } +-dontwarn kotlin.** +-keepclassmembers class **$WhenMappings { + ; +} +-keepclassmembers class kotlin.Metadata { + public ; +} +-assumenosideeffects class kotlin.jvm.internal.Intrinsics { + static void checkParameterIsNotNull(java.lang.Object, java.lang.String); +} + +# ========== Coroutines ========== +-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {} +-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {} +-keepclassmembernames class kotlinx.** { + volatile ; +} + +# ========== R8 Full Mode ========== +-allowaccessmodification +-repackageclasses From 25dc686cdd1014d99eaacbefa2cc53dfb202c247 Mon Sep 17 00:00:00 2001 From: ikseong00 <127182222+ikseong00@users.noreply.github.com> Date: Fri, 16 Jan 2026 20:33:54 +0900 Subject: [PATCH 24/24] =?UTF-8?q?[feat]=20=EA=B2=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20'=EB=82=B4=20=EC=A0=9C=EB=B3=B4=20?= =?UTF-8?q?=EB=82=B4=EC=97=AD'=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - '마이페이지' 화면에서 '내 제보 내역' 버튼 클릭 시, 게스트 유저일 경우 "로그인 이후에 이용해주세요!" 라는 토스트 메시지를 표시하도록 수정했습니다. - `MyViewModel`에 `isGuestLogin` 상태를 확인하는 `isGuest()` 함수를 추가했습니다. [chore] 앱 버전 정보 업데이트 - 앱의 `versionCode`를 13에서 14로, `versionName`을 "1.0.12"에서 "1.0.13"으로 업데이트했습니다. --- app/build.gradle.kts | 4 ++-- .../java/com/kuit/findu/presentation/ui/my/MyFragment.kt | 6 +++++- .../kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2f1c029f..e6ae5dc9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,8 +24,8 @@ android { applicationId = "com.kuit.findu" minSdk = 28 targetSdk = 35 - versionCode = 13 - versionName = "1.0.12" + versionCode = 14 + versionName = "1.0.13" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" buildConfigField("String", "GPT_KEY", properties["GPT_KEY"].toString()) diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt index 6b3cb26a..1648b277 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/my/MyFragment.kt @@ -122,7 +122,11 @@ class MyFragment : Fragment() { } btnMyReportHistory.setOnClickListener { - findNavController().navigate(R.id.action_fragment_my_to_fragment_my_report_history) + if (myViewModel.isGuest()) { + Toast.makeText(requireContext(), "로그인 이후에 이용해주세요!", Toast.LENGTH_SHORT).show() + } else { + findNavController().navigate(R.id.action_fragment_my_to_fragment_my_report_history) + } } clMyRecentHistory.setOnClickListener { diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt index d5952c4f..35217ad5 100644 --- a/app/src/main/java/com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt +++ b/app/src/main/java/com/kuit/findu/presentation/ui/my/viewmodel/MyViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.kuit.findu.domain.model.my.MyProfileData import com.kuit.findu.domain.model.my.MyProfileImageUpdate +import com.kuit.findu.domain.usecase.GetIsGuestLoginUseCase import com.kuit.findu.domain.usecase.interest.DeleteInterestAnimalUseCase import com.kuit.findu.domain.usecase.interest.PostInterestAnimalUseCase import com.kuit.findu.domain.usecase.my.DeleteUserUseCase @@ -46,6 +47,7 @@ class MyViewModel @Inject constructor( private val deleteReportUseCase: DeleteReportUseCase, private val patchProfileImageUseCase: PatchProfileImageUseCase, private val clearTokenUseCase: ClearTokenUseCase, + private val getIsGuestLoginUseCase: GetIsGuestLoginUseCase, ) : ViewModel() { private val _interestAnimals = MutableStateFlow>(emptyList()) @@ -251,4 +253,6 @@ class MyViewModel @Inject constructor( } } + fun isGuest(): Boolean = getIsGuestLoginUseCase() + } \ No newline at end of file