Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ import com.into.websoso.core.resource.R.drawable.img_loading_thumbnail
import jp.wasabeef.transformers.coil.BlurTransformation

object BindingAdapter {
@JvmStatic
@BindingAdapter("loads3ImageUrl")
fun loadS3ImageUrl(
view: ImageView,
s3ImageKey: String,
) {
val fullUrl: String = view.getS3ImageUrl(s3ImageKey)

view.load(fullUrl) {
error(img_loading_thumbnail)
}
}

@JvmStatic
@BindingAdapter(
value = ["loadImageUrl", "cornerRadius", "blurRadius", "isVectorImage", "isCircularImage"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fun AvatarResponseDto.toData(): AvatarEntity =
avatarId = avatarId,
avatarName = avatarName,
avatarLine = avatarLine,
avatarProfileImage = avatarProfileImage,
avatarImage = avatarImage,
isRepresentative = isRepresentative,
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.into.websoso.data.model

data class AvatarEntity(
val avatarId: Int,
val avatarId: Long,
val avatarName: String,
val avatarLine: String,
val avatarProfileImage: String,
val avatarImage: String,
val isRepresentative: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import com.into.websoso.data.remote.response.AvatarsResponseDto
import retrofit2.http.GET

interface AvatarApi {
@GET("avatars")
@GET("avatar-profiles")
suspend fun getAvatars(): AvatarsResponseDto
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ interface UserApi {
@Query("nickname") nickname: String,
): UserNicknameValidityResponseDto

@PATCH("users/my-profile")
@PATCH("users/profile")
suspend fun patchProfile(
@Body userProfileEditRequestDto: UserProfileEditRequestDto,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
@Serializable
data class UserProfileEditRequestDto(
@SerialName("avatarId")
val avatarId: Int?,
val avatarId: Long?,
@SerialName("nickname")
val nickname: String?,
@SerialName("intro")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ import kotlinx.serialization.Serializable

@Serializable
data class AvatarsResponseDto(
@SerialName("avatars")
@SerialName("avatarProfiles")
val avatars: List<AvatarResponseDto>,
) {
@Serializable
data class AvatarResponseDto(
@SerialName("avatarId")
val avatarId: Int,
@SerialName("avatarName")
@SerialName("avatarProfileId")
val avatarId: Long,
@SerialName("avatarProfileName")
val avatarName: String,
@SerialName("avatarLine")
@SerialName("avatarProfileLine")
val avatarLine: String,
@SerialName("avatarImage")
@SerialName("avatarProfileImage")
val avatarProfileImage: String,
@SerialName("avatarCharacterImage")
val avatarImage: String,
@SerialName("isRepresentative")
val isRepresentative: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class UserRepository
suspend fun fetchOtherUserProfile(userId: Long): OtherUserProfileEntity = userApi.getOtherUserProfile(userId).toData()

suspend fun saveEditingUserProfile(
avatarId: Int?,
avatarId: Long?,
nickname: String?,
intro: String?,
genrePreferences: List<String>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import coil.load
import com.into.websoso.R.color.bg_detail_explore_chip_background_selector
import com.into.websoso.R.color.bg_detail_explore_chip_stroke_selector
import com.into.websoso.R.color.bg_detail_explore_chip_text_selector
import com.into.websoso.R.color.gray_200_AEADB3
import com.into.websoso.R.color.gray_200_949399
import com.into.websoso.R.layout.activity_create_feed
import com.into.websoso.R.style.body2
import com.into.websoso.R.style.body4
Expand Down Expand Up @@ -81,7 +81,7 @@ class CreateFeedActivity : BaseActivity<ActivityCreateFeedBinding>(activity_crea
binding.wsetCreateFeedSearchNovel.apply {
setWebsosoFocusableInTouchMode(false)
setWebsosoSearchHint(getString(wset_create_feed_search_novel))
setWebsosoSearchHintTextColor(gray_200_AEADB3)
setWebsosoSearchHintTextColor(gray_200_949399)
setWebsosoSearchTextAppearance(body4)
setWebsosoOnClickListener {
singleEventHandler.throttleFirst { showSearchNovelDialog() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class DetailExploreDialogBottomSheet : BaseBottomSheetDialog<DialogDetailExplore

private fun updateButtonColors(selectedFragmentTitle: SelectedFragmentTitle) {
val selectedColor = requireContext().getColor(R.color.primary_100_6A5DFD)
val defaultColor = requireContext().getColor(R.color.gray_200_AEADB3)
val defaultColor = requireContext().getColor(R.color.gray_200_949399)

when (selectedFragmentTitle) {
INFO -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class DetailExploreResultDialogBottomSheet : BaseBottomSheetDialog<DialogDetailE

private fun updateButtonColors(selectedFragmentTitle: SelectedFragmentTitle) {
val selectedColor = requireContext().getColor(R.color.primary_100_6A5DFD)
val defaultColor = requireContext().getColor(R.color.gray_200_AEADB3)
val defaultColor = requireContext().getColor(R.color.gray_200_949399)

when (selectedFragmentTitle) {
INFO -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.into.websoso.R.color.black
import com.into.websoso.R.color.gray_200_AEADB3
import com.into.websoso.R.color.gray_200_949399
import com.into.websoso.R.color.secondary_100_FF675D
import com.into.websoso.core.common.util.getS3ImageUrl
import com.into.websoso.databinding.ItemFeedDetailCommentBinding
Expand Down Expand Up @@ -37,14 +37,14 @@ class FeedDetailCommentViewHolder(
if (comment.isBlocked) {
binding.tvFeedUserName.text = "차단한 유저"
binding.tvFeedDetailCommentContent.text = "차단한 유저의 댓글"
binding.tvFeedDetailCommentContent.setTextColor(gray_200_AEADB3.color())
binding.tvFeedDetailCommentContent.setTextColor(gray_200_949399.color())
binding.ivFeedDetailMoreButton.isVisible = false
return
}

if (comment.isHidden) {
binding.tvFeedDetailCommentContent.text = "숨김 처리된 댓글"
binding.tvFeedDetailCommentContent.setTextColor(gray_200_AEADB3.color())
binding.tvFeedDetailCommentContent.setTextColor(gray_200_949399.color())
binding.ivFeedDetailMoreButton.isVisible = false
return
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/com/into/websoso/ui/mapper/AvatarMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fun AvatarEntity.toUi(nickname: String) =
avatarId = avatarId,
avatarName = avatarName,
avatarLine = avatarLine.format(nickname),
avatarThumbnail = avatarImage,
avatarProfile = avatarProfileImage,
avatarImage = avatarImage,
Comment on lines +11 to +12
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# avatarThumbnail 필드의 모든 사용처 검색
rg -nP --type=kotlin '\bavatarThumbnail\b' -C 2

Repository: Team-WSS/WSS-Android

Length of output: 5039


🏁 Script executed:

cat -n app/src/main/java/com/into/websoso/ui/mapper/AvatarMapper.kt

Repository: Team-WSS/WSS-Android

Length of output: 604


🏁 Script executed:

find . -name "AvatarModel.kt" -type f

Repository: Team-WSS/WSS-Android

Length of output: 136


🏁 Script executed:

cat -n ./app/src/main/java/com/into/websoso/ui/profileEdit/model/AvatarModel.kt

Repository: Team-WSS/WSS-Android

Length of output: 413


🏁 Script executed:

rg -n --type=kotlin "AvatarModel" -C 2 | head -100

Repository: Team-WSS/WSS-Android

Length of output: 11184


🏁 Script executed:

cat -n app/src/main/java/com/into/websoso/ui/profileEdit/ProfileEditViewModel.kt | sed -n '245,285p'

Repository: Team-WSS/WSS-Android

Length of output: 2080


🏁 Script executed:

cat -n app/src/main/java/com/into/websoso/ui/mapper/UserMapper.kt | sed -n '20,35p'

Repository: Team-WSS/WSS-Android

Length of output: 664


필드 매핑 마이그레이션 완료 필요 - avatarThumbnail 참조 남아있음.

AvatarMapper가 avatarProfileavatarImage로 변경되었으나, 하위 계층 코드가 여전히 avatarThumbnail 필드를 사용하고 있습니다. ViewModel에서 수동으로 avatarProfile → avatarThumbnail으로 매핑 중이지만, 다음 위치들도 함께 업데이트되어야 합니다:

  • ProfileEditUiModel.kt:11 - avatarThumbnail 필드를 avatarProfile로 변경
  • ProfileEditViewModel.kt:249, 282 - avatarProfile 직접 사용으로 변경
  • ProfileEditActivity.kt:276-279 - 메서드명 및 파라미터 업데이트
  • UserMapper.kt:27 - 매핑 필드명 업데이트 필요

isRepresentative = isRepresentative,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import android.view.View
import androidx.core.content.ContextCompat
import androidx.fragment.app.activityViewModels
import com.into.websoso.R.color.black
import com.into.websoso.R.color.gray_200_AEADB3
import com.into.websoso.R.color.gray_200_949399
import com.into.websoso.R.layout.fragment_onboarding_second
import com.into.websoso.core.common.ui.base.BaseFragment
import com.into.websoso.core.resource.R.string.onboarding_second_input_birth_year
Expand Down Expand Up @@ -53,7 +53,7 @@ class OnboardingSecondFragment : BaseFragment<FragmentOnboardingSecondBinding>(f
ContextCompat.getColor(
context,
when (userModelInfo.birthYear) {
0 -> gray_200_AEADB3
0 -> gray_200_949399
else -> black
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@ package com.into.websoso.ui.profileEdit
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.into.websoso.R
import com.into.websoso.core.common.ui.base.BaseBottomSheetDialog
import com.into.websoso.databinding.DialogAvatarChangeBinding
import com.into.websoso.ui.profileEdit.adapter.AvatarChangeAdapter
import com.into.websoso.ui.profileEdit.model.Avatar.Companion.animation
import com.into.websoso.ui.profileEdit.adapter.AvatarPagerAdapter
import com.into.websoso.ui.profileEdit.model.AvatarChangeUiState
import com.into.websoso.ui.profileEdit.model.AvatarModel

class AvatarChangeBottomSheetDialog : BaseBottomSheetDialog<DialogAvatarChangeBinding>(R.layout.dialog_avatar_change) {
private val profileEditViewModel: ProfileEditViewModel by activityViewModels()
private val avatarChangeAdapter: AvatarChangeAdapter by lazy {
AvatarChangeAdapter { avatarModel -> profileEditViewModel.updateSelectedAvatar(avatarModel) }

private val avatarPagerAdapter: AvatarPagerAdapter by lazy {
AvatarPagerAdapter { avatarModel -> profileEditViewModel.updateSelectedAvatar(avatarModel) }
}

override fun onViewCreated(
Expand Down Expand Up @@ -49,35 +47,26 @@ class AvatarChangeBottomSheetDialog : BaseBottomSheetDialog<DialogAvatarChangeBi
}

private fun handleAvatarChangeUiState(uiState: AvatarChangeUiState) {
when {
uiState.loading -> Unit
if (uiState.avatars.isNotEmpty()) {
if (binding.vpProfileEditAvatar.adapter == null) {
setupViewPager()
}

uiState.error -> Unit
val currentPage = binding.vpProfileEditAvatar.currentItem

uiState.avatars.isNotEmpty() -> {
setupRecyclerView()
updateAvatarAnimation(uiState.selectedAvatar)
avatarChangeAdapter.submitList(uiState.avatars)
avatarPagerAdapter.submitList(uiState.avatars.chunked(10)) {
binding.vpProfileEditAvatar.setCurrentItem(currentPage, false)
}
}
}

private fun setupRecyclerView() {
// TODO: 갯수가 일정 갯수 초과시 그리드 리사이클러뷰 가운데 정렬
if (binding.rvProfileEditAvatar.childCount > 0) return
binding.rvProfileEditAvatar.apply {
adapter = avatarChangeAdapter
layoutManager = GridLayoutManager(context, profileEditViewModel.getFormattedSpanCount())
itemAnimator = null
private fun setupViewPager() {
binding.vpProfileEditAvatar.apply {
adapter = avatarPagerAdapter
offscreenPageLimit = 1
}
}

private fun updateAvatarAnimation(avatar: AvatarModel) {
if (avatar.avatarId == 0) return
binding.lavProfileEditAvatar.apply {
setAnimation(avatar.animation())
playAnimation()
}
binding.dotsIndicatorProfileEdit.attachTo(binding.vpProfileEditAvatar)
}

private fun onSaveClick() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.into.websoso.ui.profileEdit

import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.RecyclerView

class ColumnSpacingItemDecoration(
private val spanCount: Int,
private val spacing: Int,
) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State,
) {
val position = parent.getChildAdapterPosition(view)
val column = position / spanCount

if (column > 0) {
outRect.left = spacing
} else {
outRect.left = 0
}
Comment on lines +17 to +24
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

컬럼 계산 로직 오류 수정 필요

Line 18의 컬럼 계산이 잘못되었습니다. 현재 코드는 나눗셈(/)을 사용하여 행 번호를 계산하고 있지만, 컬럼 인덱스를 구하려면 나머지 연산자(%)를 사용해야 합니다.

현재 동작 (잘못됨):

  • spanCount=3일 때, position 0-2는 column 0, position 3-5는 column 1
  • 전체 행에 spacing이 적용되어 의도한 동작이 아님

올바른 동작:

  • spanCount=3일 때, position 0,3,6은 column 0 (간격 없음)
  • position 1,4,7은 column 1 (왼쪽 간격), position 2,5,8은 column 2 (왼쪽 간격)
🔎 수정 제안
     val position = parent.getChildAdapterPosition(view)
-    val column = position / spanCount
+    val column = position % spanCount
 
     if (column > 0) {
         outRect.left = spacing
📝 Committable suggestion

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

Suggested change
val position = parent.getChildAdapterPosition(view)
val column = position / spanCount
if (column > 0) {
outRect.left = spacing
} else {
outRect.left = 0
}
val position = parent.getChildAdapterPosition(view)
val column = position % spanCount
if (column > 0) {
outRect.left = spacing
} else {
outRect.left = 0
}
🤖 Prompt for AI Agents
In
app/src/main/java/com/into/websoso/ui/profileEdit/ColumnSpacingItemDecoration.kt
around lines 17 to 24, the code incorrectly computes the column using integer
division (position / spanCount); change it to use the remainder operator
(position % spanCount) so column = position % spanCount, then keep the existing
logic to set outRect.left = spacing when column > 0 and 0 when column == 0;
ensure you only change the operator and not the surrounding spacing logic.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import androidx.core.widget.addTextChangedListener
import com.into.websoso.R.color.bg_profile_edit_chip_background_selector
import com.into.websoso.R.color.bg_profile_edit_chip_stroke_selector
import com.into.websoso.R.color.bg_profile_edit_chip_text_selector
import com.into.websoso.R.color.gray_200_AEADB3
import com.into.websoso.R.color.gray_200_949399
import com.into.websoso.R.color.gray_300_52515F
import com.into.websoso.R.color.primary_100_6A5DFD
import com.into.websoso.R.drawable.bg_profile_edit_gray_50_radius_12dp
Expand Down Expand Up @@ -109,7 +109,7 @@ class ProfileEditActivity : BaseActivity<ActivityProfileEditBinding>(activity_pr
primary_100_6A5DFD,
).defaultColor
} else {
AppCompatResources.getColorStateList(this, gray_200_AEADB3).defaultColor
AppCompatResources.getColorStateList(this, gray_200_949399).defaultColor
},
)
binding.tvProfileEditNicknameCheckDuplicate.setBackgroundResource(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,15 +237,16 @@ class ProfileEditViewModel
?.nicknameModel
?.nickname ?: ""
val avatarsModel = avatars.map { it.toUi(previousNickname) }
val representativeAvatar: AvatarModel? = avatarsModel.find { it.isRepresentative }
_avatarChangeUiState.value = avatarChangeUiState.value?.copy(
avatars = avatarsModel,
loading = false,
selectedAvatar = representativeAvatar ?: AvatarModel(),
)
val representativeAvatar = avatarsModel.find { it.isRepresentative }
updatePreviousProfile(
profileEditUiState.value?.profile?.copy(
avatarId = representativeAvatar?.avatarId ?: 0,
avatarThumbnail = representativeAvatar?.avatarThumbnail ?: "",
avatarThumbnail = representativeAvatar?.avatarProfile ?: "",
) ?: ProfileModel(),
)
}.onFailure {
Expand Down Expand Up @@ -278,7 +279,7 @@ class ProfileEditViewModel
uiState.copy(
profile = uiState.profile.copy(
avatarId = selectedAvatar.avatarId,
avatarThumbnail = selectedAvatar.avatarThumbnail,
avatarThumbnail = selectedAvatar.avatarProfile,
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ class AvatarChangeAdapter(
holder: AvatarChangeViewHolder,
position: Int,
) {
if (holder.itemView.tag == null) {
holder.setupItem(getItem(position))
} else {
holder.updateItemSelection(getItem(position).isRepresentative)
}
holder.setupItem(getItem(position))
}

companion object {
Expand All @@ -34,7 +30,9 @@ class AvatarChangeAdapter(
override fun areContentsTheSame(
oldItem: AvatarModel,
newItem: AvatarModel,
): Boolean = oldItem == newItem
): Boolean =
oldItem.avatarId == newItem.avatarId &&
oldItem.isRepresentative == newItem.isRepresentative
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,12 @@ class AvatarChangeViewHolder(
}

fun setupItem(avatar: AvatarModel) {
binding.root.tag = avatar.avatarId
binding.avatar = avatar.copy(
avatarThumbnail = binding.root.getS3ImageUrl(avatar.avatarThumbnail),
avatarProfile = binding.root.getS3ImageUrl(avatar.avatarProfile),
)
binding.isSelected = avatar.isRepresentative
}

fun updateItemSelection(isRepresentative: Boolean) {
binding.isSelected = isRepresentative
binding.executePendingBindings()
}

companion object {
Expand Down
Loading