From e2c7134f61dc6662f8d101c71570e486857ddced Mon Sep 17 00:00:00 2001 From: klaus Date: Thu, 11 Dec 2025 20:09:58 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BA=90=EB=A6=AD=ED=84=B0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20-=20=ED=8F=B0=20=EC=96=B8=EC=96=B4=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EB=B2=88=EC=97=AD=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A5=BC=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/chat/character/CharacterApi.kt | 7 +++--- .../detail/detail/CharacterDetailFragment.kt | 23 +++++++++++------ .../detail/CharacterDetailRepository.kt | 11 ++++++-- .../detail/detail/CharacterDetailResponse.kt | 25 ++++++++++++++++++- .../detail/detail/CharacterDetailViewModel.kt | 11 +++++--- .../kr/co/vividnext/sodalive/common/Utils.kt | 13 ++++++++++ 6 files changed, 73 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterApi.kt index e57eee53..20d9159f 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterApi.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterApi.kt @@ -6,12 +6,12 @@ import kr.co.vividnext.sodalive.chat.character.detail.gallery.CharacterImageList import kr.co.vividnext.sodalive.chat.character.detail.gallery.CharacterImagePurchaseRequest import kr.co.vividnext.sodalive.chat.character.detail.gallery.CharacterImagePurchaseResponse import kr.co.vividnext.sodalive.common.ApiResponse +import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header +import retrofit2.http.POST import retrofit2.http.Path import retrofit2.http.Query -import retrofit2.http.Body -import retrofit2.http.POST interface CharacterApi { @GET("/api/chat/character/main") @@ -22,7 +22,8 @@ interface CharacterApi { @GET("/api/chat/character/{characterId}") fun getCharacterDetail( @Header("Authorization") authHeader: String, - @Path("characterId") characterId: Long + @Path("characterId") characterId: Long, + @Query("languageCode") languageCode: String ): Single> @GET("/api/chat/character/image/list") diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailFragment.kt index 34dfba7b..c4210944 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailFragment.kt @@ -23,6 +23,7 @@ import kr.co.vividnext.sodalive.chat.character.detail.CharacterDetailActivity.Co import kr.co.vividnext.sodalive.chat.talk.room.ChatRoomActivity import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.SharedPreferenceManager +import kr.co.vividnext.sodalive.common.Utils.getCurrentLanguageCode import kr.co.vividnext.sodalive.databinding.FragmentCharacterDetailBinding import kr.co.vividnext.sodalive.extensions.dpToPx import org.koin.android.ext.android.inject @@ -78,7 +79,7 @@ class CharacterDetailFragment : BaseFragment( setupView() bindObservers() - viewModel.load(characterId) + viewModel.load(characterId, languageCode = getCurrentLanguageCode(requireContext())) } @SuppressLint("SetTextI18n") @@ -117,7 +118,7 @@ class CharacterDetailFragment : BaseFragment( // 기본 정보 if (detail.gender != null) { binding.tvGender.visibility = View.VISIBLE - binding.tvGender.text = detail.gender + binding.tvGender.text = detail.translated?.gender ?: detail.gender if (detail.gender == "남성") { binding.tvGender.setTextColor( @@ -164,7 +165,7 @@ class CharacterDetailFragment : BaseFragment( View.VISIBLE } - binding.tvCharacterName.text = detail.name + binding.tvCharacterName.text = detail.translated?.name ?: detail.name binding.tvCharacterStatus.text = when (detail.characterType) { CharacterType.CLONE -> getString(R.string.chat_character_type_clone) CharacterType.CHARACTER -> getString(R.string.chat_character_type_character) @@ -176,11 +177,13 @@ class CharacterDetailFragment : BaseFragment( CharacterType.CHARACTER -> R.drawable.bg_character_status_character } ) - binding.tvCharacterDescription.text = detail.description - binding.tvCharacterTags.text = detail.tags + binding.tvCharacterDescription.text = detail.translated?.description + ?: detail.description + binding.tvCharacterTags.text = detail.translated?.tags ?: detail.tags // 세계관 내용과 버튼 가시성 초기화 - val worldviewText = detail.backgrounds?.description.orEmpty() + val worldviewText = detail.translated?.background?.description + ?: detail.backgrounds?.description.orEmpty() binding.tvWorldviewContent.text = worldviewText // 먼저 전체 줄 수를 측정한 뒤 접힘 레이아웃 적용 binding.tvWorldviewContent.post { @@ -196,7 +199,8 @@ class CharacterDetailFragment : BaseFragment( } // 성격 내용과 버튼 가시성 초기화 - val personalityText = detail.personalities?.description.orEmpty() + val personalityText = detail.translated?.personality?.description + ?: detail.personalities?.description.orEmpty() binding.tvPersonalityContent.text = personalityText // 먼저 전체 줄 수를 측정한 뒤 접힘 레이아웃 적용 binding.tvPersonalityContent.post { @@ -313,7 +317,10 @@ class CharacterDetailFragment : BaseFragment( if (resp.success) { binding.etCommentInput.setText("") showToast(getString(R.string.character_detail_comment_register_success)) - viewModel.load(targetCharacterId) + viewModel.load( + targetCharacterId, + languageCode = getCurrentLanguageCode(requireContext()) + ) } else { showToast( resp.message ?: getString(R.string.common_error_request) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailRepository.kt index cea429f4..2b45e6f9 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailRepository.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailRepository.kt @@ -8,8 +8,15 @@ class CharacterDetailRepository( private val characterApi: CharacterApi, private val talkApi: TalkApi ) { - fun getCharacterDetail(token: String, characterId: Long) = - characterApi.getCharacterDetail(authHeader = token, characterId = characterId) + fun getCharacterDetail( + token: String, + characterId: Long, + languageCode: String + ) = characterApi.getCharacterDetail( + authHeader = token, + characterId = characterId, + languageCode = languageCode + ) fun createChatRoom(token: String, request: CreateChatRoomRequest) = talkApi.createChatRoom(authHeader = token, request = request) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailResponse.kt index c27e17aa..b53f149c 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailResponse.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailResponse.kt @@ -21,7 +21,8 @@ data class CharacterDetailResponse( @SerializedName("characterType") val characterType: CharacterType, @SerializedName("others") val others: List, @SerializedName("latestComment") val latestComment: CharacterCommentResponse?, - @SerializedName("totalComments") val totalComments: Int + @SerializedName("totalComments") val totalComments: Int, + @SerializedName("translated") val translated: TranslatedAiCharacterDetail? ) @Keep @@ -51,3 +52,25 @@ data class CharacterBackgroundResponse( @SerializedName("topic") val topic: String, @SerializedName("description") val description: String ) + +@Keep +data class TranslatedAiCharacterDetail( + @SerializedName("name") val name: String?, + @SerializedName("description") val description: String?, + @SerializedName("gender") val gender: String?, + @SerializedName("personality") val personality: TranslatedAiCharacterPersonality?, + @SerializedName("background") val background: TranslatedAiCharacterBackground?, + @SerializedName("tags") val tags: String? +) + +@Keep +data class TranslatedAiCharacterPersonality( + @SerializedName("trait") val trait: String?, + @SerializedName("description") val description: String? +) + +@Keep +data class TranslatedAiCharacterBackground( + @SerializedName("topic") val topic: String?, + @SerializedName("description") val description: String? +) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt index 9cfef23a..eb7821a4 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt @@ -8,8 +8,8 @@ import io.reactivex.rxjava3.schedulers.Schedulers import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.chat.talk.room.CreateChatRoomRequest -import kr.co.vividnext.sodalive.common.UiText import kr.co.vividnext.sodalive.common.SharedPreferenceManager +import kr.co.vividnext.sodalive.common.UiText /** * 캐릭터 상세 화면에서 사용하는 ViewModel. @@ -33,12 +33,16 @@ class CharacterDetailViewModel( private val _uiState = MutableLiveData(UiState()) val uiState: LiveData get() = _uiState - fun load(characterId: Long) { + fun load(characterId: Long, languageCode: String) { _uiState.value = _uiState.value?.copy(isLoading = true, error = null) val token = "Bearer ${SharedPreferenceManager.token}" compositeDisposable.add( - repository.getCharacterDetail(token = token, characterId = characterId) + repository.getCharacterDetail( + token = token, + characterId = characterId, + languageCode = languageCode + ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( @@ -46,6 +50,7 @@ class CharacterDetailViewModel( val success = response.success val data = response.data if (success && data != null) { + Logger.d("character detail: $data") _uiState.value = UiState(detail = data, isLoading = false, error = null) } else { _uiState.value = UiState( diff --git a/app/src/main/java/kr/co/vividnext/sodalive/common/Utils.kt b/app/src/main/java/kr/co/vividnext/sodalive/common/Utils.kt index 29c7ae38..21cc906b 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/common/Utils.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/common/Utils.kt @@ -1,5 +1,7 @@ package kr.co.vividnext.sodalive.common +import android.content.Context +import android.os.Build import java.net.URLEncoder import java.nio.charset.StandardCharsets @@ -38,4 +40,15 @@ object Utils { return "https://voiceon.onelink.me/RkTm?$encodedParams" } + + fun getCurrentLanguageCode(context: Context): String { + val config = context.resources.configuration + val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + config.locales.get(0) + } else { + @Suppress("DEPRECATION") + config.locale + } + return locale.language // "ko", "en" 등 + } }