feat(chat): 채팅방 배경 사진 변경 기능 추가
- ChatRoomMoreDialog에서 배경 사진 변경 Picker 연결 - my-list API 추가 및 Repository 위임 추가 - 배경 선택 Dialog(3열 Grid, 4:5 비율) 및 선택 상태 UI 구현 - SharedPreferences로 roomId별 배경 URL 저장/로드 - ChatRoomActivity에 배경 저장/적용 헬퍼 추가 및 기본 프로필 적용 로직 구현
This commit is contained in:
		@@ -33,6 +33,16 @@ interface CharacterApi {
 | 
			
		||||
        @Query("size") size: Int
 | 
			
		||||
    ): Single<ApiResponse<CharacterImageListResponse>>
 | 
			
		||||
 | 
			
		||||
    // 내 배경 이미지 리스트 (프로필 + 무료 + 구매 이미지)
 | 
			
		||||
    // getCharacterImageList와 파라미터/응답 동일, 엔드포인트만 다름
 | 
			
		||||
    @GET("/api/chat/character/image/my-list")
 | 
			
		||||
    fun getMyCharacterImageList(
 | 
			
		||||
        @Header("Authorization") authHeader: String,
 | 
			
		||||
        @Query("characterId") characterId: Long,
 | 
			
		||||
        @Query("page") page: Int,
 | 
			
		||||
        @Query("size") size: Int
 | 
			
		||||
    ): Single<ApiResponse<CharacterImageListResponse>>
 | 
			
		||||
 | 
			
		||||
    @POST("/api/chat/character/image/purchase")
 | 
			
		||||
    fun purchaseCharacterImage(
 | 
			
		||||
        @Header("Authorization") authHeader: String,
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,9 @@ class CharacterGalleryRepository(
 | 
			
		||||
    fun getCharacterImageList(token: String, characterId: Long, page: Int, size: Int) =
 | 
			
		||||
        characterApi.getCharacterImageList(authHeader = token, characterId = characterId, page = page, size = size)
 | 
			
		||||
 | 
			
		||||
    fun getMyCharacterImageList(token: String, characterId: Long, page: Int, size: Int) =
 | 
			
		||||
        characterApi.getMyCharacterImageList(authHeader = token, characterId = characterId, page = page, size = size)
 | 
			
		||||
 | 
			
		||||
    fun purchaseCharacterImage(token: String, imageId: Long) =
 | 
			
		||||
        characterApi.purchaseCharacterImage(
 | 
			
		||||
            authHeader = token,
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,227 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.chat.talk.room
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.core.content.edit
 | 
			
		||||
import androidx.fragment.app.DialogFragment
 | 
			
		||||
import androidx.recyclerview.widget.GridLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import coil.load
 | 
			
		||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
 | 
			
		||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
 | 
			
		||||
import io.reactivex.rxjava3.schedulers.Schedulers
 | 
			
		||||
import kr.co.vividnext.sodalive.R
 | 
			
		||||
import kr.co.vividnext.sodalive.chat.character.detail.gallery.CharacterGalleryRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.common.LoadingDialog
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.FragmentChatBackgroundPickerBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.ItemChatBackgroundImageBinding
 | 
			
		||||
import org.koin.android.ext.android.inject
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 채팅방 배경 이미지 선택 다이얼로그
 | 
			
		||||
 * - 3열 Grid, 간격 0, 4:5 비율
 | 
			
		||||
 * - 캐릭터 프로필 + 무료 이미지 + 내가 구매한 이미지 (my-list)
 | 
			
		||||
 * - 선택 항목은 1dp #3bb9f1 테두리 및 우하단 "현재 배경" 라벨 표시
 | 
			
		||||
 */
 | 
			
		||||
class ChatBackgroundPickerDialogFragment : DialogFragment() {
 | 
			
		||||
 | 
			
		||||
    private var _binding: FragmentChatBackgroundPickerBinding? = null
 | 
			
		||||
    private val binding get() = _binding!!
 | 
			
		||||
 | 
			
		||||
    private val repository: CharacterGalleryRepository by inject()
 | 
			
		||||
    private val compositeDisposable = CompositeDisposable()
 | 
			
		||||
    private lateinit var loadingDialog: LoadingDialog
 | 
			
		||||
 | 
			
		||||
    private var roomId: Long = 0L
 | 
			
		||||
    private var characterId: Long = 0L
 | 
			
		||||
    private var profileUrl: String = ""
 | 
			
		||||
 | 
			
		||||
    private val prefsName = "chat_room_prefs"
 | 
			
		||||
    private fun bgUrlKey(roomId: Long) = "chat_bg_url_room_$roomId"
 | 
			
		||||
    private fun bgImageIdKey(roomId: Long) = "chat_bg_image_id_room_$roomId"
 | 
			
		||||
 | 
			
		||||
    private lateinit var adapter: BgAdapter
 | 
			
		||||
    private val items = mutableListOf<BgItem>()
 | 
			
		||||
    private var selectedUrl: String? = null
 | 
			
		||||
    private var selectedId: Long? = null
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        setStyle(STYLE_NO_TITLE, android.R.style.Theme_Black_NoTitleBar_Fullscreen)
 | 
			
		||||
        roomId = arguments?.getLong(ARG_ROOM_ID) ?: 0L
 | 
			
		||||
        // Activity에서 characterId/profileUrl 조회 (공개 getter 사용 예정)
 | 
			
		||||
        val act = activity as? ChatRoomActivity
 | 
			
		||||
        characterId = act?.getCharacterId() ?: 0L
 | 
			
		||||
        profileUrl = act?.getCharacterProfileUrl().orEmpty()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
        inflater: LayoutInflater,
 | 
			
		||||
        container: ViewGroup?,
 | 
			
		||||
        savedInstanceState: Bundle?
 | 
			
		||||
    ): View {
 | 
			
		||||
        _binding = FragmentChatBackgroundPickerBinding.inflate(inflater, container, false)
 | 
			
		||||
        return binding.root
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
        loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
 | 
			
		||||
        setupUi()
 | 
			
		||||
        loadData()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupUi() {
 | 
			
		||||
        binding.ivClose.setOnClickListener { dismiss() }
 | 
			
		||||
        binding.tvTitle.text = "배경 사진 선택"
 | 
			
		||||
 | 
			
		||||
        binding.rvGrid.layoutManager = GridLayoutManager(requireContext(), 3)
 | 
			
		||||
        adapter = BgAdapter { item ->
 | 
			
		||||
            onSelect(item)
 | 
			
		||||
        }
 | 
			
		||||
        binding.rvGrid.adapter = adapter
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun loadData() {
 | 
			
		||||
        // 초기 선택: 저장된 값 사용 (URL + ID 병행)
 | 
			
		||||
        val prefs = requireActivity().getSharedPreferences(prefsName, Context.MODE_PRIVATE)
 | 
			
		||||
        selectedUrl = prefs.getString(bgUrlKey(roomId), null)
 | 
			
		||||
        val savedId = prefs.getLong(bgImageIdKey(roomId), -1L)
 | 
			
		||||
        selectedId = if (savedId > 0) savedId else null
 | 
			
		||||
 | 
			
		||||
        items.clear()
 | 
			
		||||
 | 
			
		||||
        if (characterId > 0) {
 | 
			
		||||
            val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
            loadingDialog.show(resources.displayMetrics.widthPixels)
 | 
			
		||||
            val d = repository.getMyCharacterImageList(token, characterId, page = 0, size = 60)
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe({ resp ->
 | 
			
		||||
                    val list = resp.data?.items.orEmpty()
 | 
			
		||||
                    items.addAll(list.map { BgItem(id = it.id, url = it.imageUrl) })
 | 
			
		||||
                    adapter.submit(items, selectedId, selectedUrl)
 | 
			
		||||
 | 
			
		||||
                    // 마이그레이션: 과거에 URL만 저장되어 있고 ID가 비어 있는 경우
 | 
			
		||||
                    if (selectedId == null && !selectedUrl.isNullOrBlank()) {
 | 
			
		||||
                        val found = items.firstOrNull { it.url == selectedUrl }
 | 
			
		||||
                        if (found != null) {
 | 
			
		||||
                            selectedId = found.id
 | 
			
		||||
                            // UI 갱신
 | 
			
		||||
                            adapter.updateSelected(found)
 | 
			
		||||
                            // 영구 저장(ID 동기화)
 | 
			
		||||
                            val p = requireActivity().getSharedPreferences(prefsName, Context.MODE_PRIVATE)
 | 
			
		||||
                            p.edit {
 | 
			
		||||
                                putLong(bgImageIdKey(roomId), found.id)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    loadingDialog.dismiss()
 | 
			
		||||
                }, { _ ->
 | 
			
		||||
                    // 실패 시에도 현재까지의 목록 표시(없으면 빈 목록)
 | 
			
		||||
                    adapter.submit(items, selectedId, selectedUrl)
 | 
			
		||||
                    loadingDialog.dismiss()
 | 
			
		||||
                })
 | 
			
		||||
            compositeDisposable.add(d)
 | 
			
		||||
        } else {
 | 
			
		||||
            // characterId가 없으면 서버 요청 불가: 현재 저장된 선택 상태만 반영
 | 
			
		||||
            adapter.submit(items, selectedId, selectedUrl)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun onSelect(item: BgItem) {
 | 
			
		||||
        selectedUrl = item.url
 | 
			
		||||
        selectedId = item.id.takeIf { it > 0 }
 | 
			
		||||
        saveAndApply(item)
 | 
			
		||||
        adapter.updateSelected(item)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun saveAndApply(item: BgItem) {
 | 
			
		||||
        val prefs = requireActivity().getSharedPreferences(prefsName, Context.MODE_PRIVATE)
 | 
			
		||||
        prefs.edit {
 | 
			
		||||
            putString(bgUrlKey(roomId), item.url)
 | 
			
		||||
            if (item.id > 0) putLong(bgImageIdKey(roomId), item.id) else remove(bgImageIdKey(roomId))
 | 
			
		||||
        }
 | 
			
		||||
        (activity as? ChatRoomActivity)?.setChatBackground(item.url)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView() {
 | 
			
		||||
        super.onDestroyView()
 | 
			
		||||
        try {
 | 
			
		||||
            if (this::loadingDialog.isInitialized) loadingDialog.dismiss()
 | 
			
		||||
        } catch (_: Throwable) { }
 | 
			
		||||
        compositeDisposable.clear()
 | 
			
		||||
        _binding = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    data class BgItem(val id: Long, val url: String)
 | 
			
		||||
 | 
			
		||||
    private class BgAdapter(
 | 
			
		||||
        private val onClick: (BgItem) -> Unit
 | 
			
		||||
    ) : RecyclerView.Adapter<BgVH>() {
 | 
			
		||||
        private val data = mutableListOf<BgItem>()
 | 
			
		||||
        private var selectedUrl: String? = null
 | 
			
		||||
        private var selectedId: Long? = null
 | 
			
		||||
 | 
			
		||||
        @SuppressLint("NotifyDataSetChanged")
 | 
			
		||||
        fun submit(items: List<BgItem>, selectedId: Long?, selectedUrl: String?) {
 | 
			
		||||
            data.clear()
 | 
			
		||||
            data.addAll(items)
 | 
			
		||||
            this.selectedId = selectedId
 | 
			
		||||
            this.selectedUrl = selectedUrl
 | 
			
		||||
            notifyDataSetChanged()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @SuppressLint("NotifyDataSetChanged")
 | 
			
		||||
        fun updateSelected(item: BgItem) {
 | 
			
		||||
            this.selectedId = item.id.takeIf { it > 0 }
 | 
			
		||||
            this.selectedUrl = item.url
 | 
			
		||||
            notifyDataSetChanged()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BgVH {
 | 
			
		||||
            val binding = ItemChatBackgroundImageBinding.inflate(
 | 
			
		||||
                LayoutInflater.from(parent.context), parent, false
 | 
			
		||||
            )
 | 
			
		||||
            return BgVH(binding, onClick)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun getItemCount(): Int = data.size
 | 
			
		||||
 | 
			
		||||
        override fun onBindViewHolder(holder: BgVH, position: Int) {
 | 
			
		||||
            holder.bind(data[position], selectedId, selectedUrl)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class BgVH(
 | 
			
		||||
        private val binding: ItemChatBackgroundImageBinding,
 | 
			
		||||
        private val onClick: (BgItem) -> Unit
 | 
			
		||||
    ) : RecyclerView.ViewHolder(binding.root) {
 | 
			
		||||
        fun bind(item: BgItem, selectedId: Long?, selectedUrl: String?) {
 | 
			
		||||
            binding.ivImage.load(item.url) {
 | 
			
		||||
                placeholder(R.drawable.ic_placeholder_profile)
 | 
			
		||||
                error(R.drawable.ic_placeholder_profile)
 | 
			
		||||
            }
 | 
			
		||||
            val selected = (selectedId != null && item.id == selectedId) ||
 | 
			
		||||
                (selectedUrl != null && selectedUrl == item.url)
 | 
			
		||||
            binding.tvCurrent.visibility = if (selected) View.VISIBLE else View.GONE
 | 
			
		||||
            binding.viewBorder.visibility = if (selected) View.VISIBLE else View.GONE
 | 
			
		||||
            binding.root.setOnClickListener { onClick(item) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val ARG_ROOM_ID = "arg_room_id"
 | 
			
		||||
        fun newInstance(roomId: Long): ChatBackgroundPickerDialogFragment {
 | 
			
		||||
            val f = ChatBackgroundPickerDialogFragment()
 | 
			
		||||
            f.arguments = Bundle().apply { putLong(ARG_ROOM_ID, roomId) }
 | 
			
		||||
            return f
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -119,11 +119,8 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
 | 
			
		||||
 | 
			
		||||
        // 프로필 이미지 (공용 유틸 + 둥근 모서리 적용)
 | 
			
		||||
        loadProfileImage(binding.ivProfile, info.profileImageUrl)
 | 
			
		||||
        // 배경 프로필 이미지 (5.5)
 | 
			
		||||
        binding.ivBackgroundProfile.load(info.profileImageUrl) {
 | 
			
		||||
            placeholder(R.drawable.ic_placeholder_profile)
 | 
			
		||||
            error(R.drawable.ic_placeholder_profile)
 | 
			
		||||
        }
 | 
			
		||||
        // 배경 이미지: 저장된 값 우선, 없으면 프로필로 저장/적용
 | 
			
		||||
        applyBackgroundFromPrefsOrProfile(info.profileImageUrl)
 | 
			
		||||
 | 
			
		||||
        // 타입 배지 텍스트 및 배경
 | 
			
		||||
        val (badgeText, badgeBg) = when (info.characterType) {
 | 
			
		||||
@@ -840,6 +837,37 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
 | 
			
		||||
        binding.viewCharacterDim.isVisible = visible
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun bgUrlPrefKey(): String = "chat_bg_url_room_$roomId"
 | 
			
		||||
 | 
			
		||||
    fun setChatBackground(url: String) {
 | 
			
		||||
        binding.ivBackgroundProfile.load(url) {
 | 
			
		||||
            placeholder(R.drawable.ic_placeholder_profile)
 | 
			
		||||
            error(R.drawable.ic_placeholder_profile)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun applyBackgroundFromPrefsOrProfile(profileUrl: String) {
 | 
			
		||||
        val key = bgUrlPrefKey()
 | 
			
		||||
        val saved = prefs.getString(key, null)
 | 
			
		||||
        val target = when {
 | 
			
		||||
            !saved.isNullOrBlank() -> saved
 | 
			
		||||
            profileUrl.isNotBlank() -> {
 | 
			
		||||
                prefs.edit { putString(key, profileUrl) }
 | 
			
		||||
                profileUrl
 | 
			
		||||
            }
 | 
			
		||||
            else -> null
 | 
			
		||||
        }
 | 
			
		||||
        if (!target.isNullOrBlank()) {
 | 
			
		||||
            setChatBackground(target)
 | 
			
		||||
        } else {
 | 
			
		||||
            binding.ivBackgroundProfile.setImageResource(R.drawable.ic_placeholder_profile)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getCharacterId(): Long = characterInfo?.characterId ?: 0L
 | 
			
		||||
 | 
			
		||||
    fun getCharacterProfileUrl(): String = characterInfo?.profileImageUrl ?: ""
 | 
			
		||||
 | 
			
		||||
    fun onResetChatRequested() {
 | 
			
		||||
        val title = "대화 초기화"
 | 
			
		||||
        val desc = "지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다."
 | 
			
		||||
 
 | 
			
		||||
@@ -57,18 +57,11 @@ class ChatRoomMoreDialogFragment : DialogFragment() {
 | 
			
		||||
            switch?.toggle()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 배경 사진 변경 (임시 안내)
 | 
			
		||||
        // 배경 사진 변경: 배경 선택 다이얼로그 표시
 | 
			
		||||
        view.findViewById<LinearLayout>(R.id.row_bg_change)?.setOnClickListener {
 | 
			
		||||
            // TODO: 배경 선택 다이얼로그 연결 (기본 프로필 + 구매한 캐릭터 이미지)
 | 
			
		||||
            SodaDialog(
 | 
			
		||||
                requireActivity(),
 | 
			
		||||
                layoutInflater,
 | 
			
		||||
                title = getString(R.string.app_name),
 | 
			
		||||
                desc = "배경 사진 변경은 곧 제공됩니다.",
 | 
			
		||||
                confirmButtonTitle = "확인",
 | 
			
		||||
                confirmButtonClick = {},
 | 
			
		||||
                cancelButtonTitle = ""
 | 
			
		||||
            ).show(resources.displayMetrics.widthPixels)
 | 
			
		||||
            val roomIdArg = arguments?.getLong(ARG_ROOM_ID) ?: 0L
 | 
			
		||||
            ChatBackgroundPickerDialogFragment.newInstance(roomIdArg)
 | 
			
		||||
                .show(parentFragmentManager, "ChatBackgroundPicker")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 대화 초기화: Activity에 위임
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								app/src/main/res/drawable/bg_chat_bg_selected_border.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								app/src/main/res/drawable/bg_chat_bg_selected_border.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:shape="rectangle">
 | 
			
		||||
    <solid android:color="@android:color/transparent" />
 | 
			
		||||
    <stroke
 | 
			
		||||
        android:width="1dp"
 | 
			
		||||
        android:color="#3BB9F1" />
 | 
			
		||||
</shape>
 | 
			
		||||
							
								
								
									
										50
									
								
								app/src/main/res/layout/fragment_chat_background_picker.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								app/src/main/res/layout/fragment_chat_background_picker.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:background="@color/color_131313">
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:id="@+id/toolbar"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="56dp"
 | 
			
		||||
        android:gravity="center_vertical"
 | 
			
		||||
        android:orientation="horizontal"
 | 
			
		||||
        android:paddingHorizontal="16dp"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toTopOf="parent">
 | 
			
		||||
 | 
			
		||||
        <ImageView
 | 
			
		||||
            android:id="@+id/iv_close"
 | 
			
		||||
            android:layout_width="24dp"
 | 
			
		||||
            android:layout_height="24dp"
 | 
			
		||||
            android:contentDescription="닫기"
 | 
			
		||||
            android:src="@drawable/ic_back" />
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
            android:id="@+id/tv_title"
 | 
			
		||||
            android:layout_width="0dp"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_marginStart="12dp"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:ellipsize="end"
 | 
			
		||||
            android:fontFamily="@font/pretendard_bold"
 | 
			
		||||
            android:maxLines="1"
 | 
			
		||||
            android:text="배경 사진 선택"
 | 
			
		||||
            android:textColor="#FFFFFFFF"
 | 
			
		||||
            android:textSize="20sp" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
        android:id="@+id/rv_grid"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
        android:clipToPadding="false"
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="parent"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toBottomOf="@id/toolbar" />
 | 
			
		||||
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:background="@color/color_131313">
 | 
			
		||||
@@ -14,8 +13,7 @@
 | 
			
		||||
        android:background="@android:color/transparent"
 | 
			
		||||
        android:gravity="center_vertical"
 | 
			
		||||
        android:orientation="horizontal"
 | 
			
		||||
        android:paddingStart="16dp"
 | 
			
		||||
        android:paddingEnd="16dp"
 | 
			
		||||
        android:paddingHorizontal="16dp"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toTopOf="parent">
 | 
			
		||||
@@ -32,25 +30,25 @@
 | 
			
		||||
            android:layout_width="0dp"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_marginStart="12dp"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:ellipsize="end"
 | 
			
		||||
            android:fontFamily="@font/pretendard_bold"
 | 
			
		||||
            android:maxLines="1"
 | 
			
		||||
            android:text="대화 설정"
 | 
			
		||||
            android:textColor="#FFFFFFFF"
 | 
			
		||||
            android:textSize="18sp"
 | 
			
		||||
            android:textSize="20sp"
 | 
			
		||||
            app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
            app:layout_constraintStart_toEndOf="@id/iv_close"
 | 
			
		||||
            tools:text="대화 설정" />
 | 
			
		||||
            app:layout_constraintStart_toEndOf="@id/iv_close" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <androidx.core.widget.NestedScrollView
 | 
			
		||||
        android:id="@+id/scroll"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
        app:layout_constraintTop_toBottomOf="@id/toolbar"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="parent"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="parent">
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toBottomOf="@id/toolbar">
 | 
			
		||||
 | 
			
		||||
        <LinearLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
@@ -64,16 +62,16 @@
 | 
			
		||||
                android:layout_height="56dp"
 | 
			
		||||
                android:gravity="center_vertical"
 | 
			
		||||
                android:orientation="horizontal"
 | 
			
		||||
                android:paddingStart="20dp"
 | 
			
		||||
                android:paddingEnd="20dp">
 | 
			
		||||
                android:paddingHorizontal="24dp">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                    android:layout_width="0dp"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:layout_weight="1"
 | 
			
		||||
                    android:fontFamily="@font/pretendard_bold"
 | 
			
		||||
                    android:text="배경 사진"
 | 
			
		||||
                    android:textColor="#FFFFFFFF"
 | 
			
		||||
                    android:textSize="16sp" />
 | 
			
		||||
                    android:textColor="#B0BEC5"
 | 
			
		||||
                    android:textSize="18sp" />
 | 
			
		||||
 | 
			
		||||
                <com.google.android.material.switchmaterial.SwitchMaterial
 | 
			
		||||
                    android:id="@+id/sw_background"
 | 
			
		||||
@@ -93,15 +91,15 @@
 | 
			
		||||
                android:layout_height="56dp"
 | 
			
		||||
                android:gravity="center_vertical"
 | 
			
		||||
                android:orientation="horizontal"
 | 
			
		||||
                android:paddingStart="20dp"
 | 
			
		||||
                android:paddingEnd="20dp">
 | 
			
		||||
                android:paddingHorizontal="24dp">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:fontFamily="@font/pretendard_bold"
 | 
			
		||||
                    android:text="배경 사진 변경"
 | 
			
		||||
                    android:textColor="#FFFFFFFF"
 | 
			
		||||
                    android:textSize="16sp" />
 | 
			
		||||
                    android:textColor="#B0BEC5"
 | 
			
		||||
                    android:textSize="18sp" />
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
 | 
			
		||||
            <View
 | 
			
		||||
@@ -115,25 +113,25 @@
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:orientation="vertical"
 | 
			
		||||
                android:paddingStart="20dp"
 | 
			
		||||
                android:paddingEnd="20dp"
 | 
			
		||||
                android:paddingTop="12dp"
 | 
			
		||||
                android:paddingBottom="12dp">
 | 
			
		||||
                android:paddingHorizontal="24dp"
 | 
			
		||||
                android:paddingVertical="12dp">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:fontFamily="@font/pretendard_bold"
 | 
			
		||||
                    android:text="대화 초기화"
 | 
			
		||||
                    android:textColor="#FFFFFFFF"
 | 
			
		||||
                    android:textSize="16sp" />
 | 
			
		||||
                    android:textColor="#B0BEC5"
 | 
			
		||||
                    android:textSize="18sp" />
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:layout_marginTop="6dp"
 | 
			
		||||
                    android:fontFamily="@font/pretendard_regular"
 | 
			
		||||
                    android:text="지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다."
 | 
			
		||||
                    android:textColor="#B3FFFFFF"
 | 
			
		||||
                    android:textSize="13sp" />
 | 
			
		||||
                    android:textSize="16sp" />
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
 | 
			
		||||
            <View
 | 
			
		||||
@@ -148,15 +146,15 @@
 | 
			
		||||
                android:layout_height="56dp"
 | 
			
		||||
                android:gravity="center_vertical"
 | 
			
		||||
                android:orientation="horizontal"
 | 
			
		||||
                android:paddingStart="20dp"
 | 
			
		||||
                android:paddingEnd="20dp">
 | 
			
		||||
                android:paddingHorizontal="24dp">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:fontFamily="@font/pretendard_bold"
 | 
			
		||||
                    android:text="신고하기"
 | 
			
		||||
                    android:textColor="#FFFFFFFF"
 | 
			
		||||
                    android:textSize="16sp" />
 | 
			
		||||
                    android:textColor="#B0BEC5"
 | 
			
		||||
                    android:textSize="18sp" />
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
 | 
			
		||||
        </LinearLayout>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								app/src/main/res/layout/item_chat_background_image.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								app/src/main/res/layout/item_chat_background_image.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
        android:id="@+id/iv_image"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
        android:contentDescription="@null"
 | 
			
		||||
        android:scaleType="centerCrop"
 | 
			
		||||
        app:layout_constraintDimensionRatio="4:5"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toTopOf="parent" />
 | 
			
		||||
 | 
			
		||||
    <!-- 선택 시 표시되는 1dp 테두리 (#3bb9f1) -->
 | 
			
		||||
    <View
 | 
			
		||||
        android:id="@+id/view_border"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
        android:background="@drawable/bg_chat_bg_selected_border"
 | 
			
		||||
        android:visibility="gone"
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="@id/iv_image"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="@id/iv_image"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="@id/iv_image"
 | 
			
		||||
        app:layout_constraintTop_toTopOf="@id/iv_image" />
 | 
			
		||||
 | 
			
		||||
    <!-- 우하단 '현재 배경' 라벨 -->
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/tv_current"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_margin="6dp"
 | 
			
		||||
        android:background="@drawable/bg_round_corner_6_7_3bb9f1"
 | 
			
		||||
        android:fontFamily="@font/pretendard_regular"
 | 
			
		||||
        android:paddingHorizontal="6dp"
 | 
			
		||||
        android:paddingVertical="2dp"
 | 
			
		||||
        android:includeFontPadding="false"
 | 
			
		||||
        android:text="현재 배경"
 | 
			
		||||
        android:textColor="#FFFFFF"
 | 
			
		||||
        android:textSize="12sp"
 | 
			
		||||
        android:visibility="gone"
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="@id/iv_image"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="@id/iv_image" />
 | 
			
		||||
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
		Reference in New Issue
	
	Block a user