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
|
@Query("size") size: Int
|
||||||
): Single<ApiResponse<CharacterImageListResponse>>
|
): 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")
|
@POST("/api/chat/character/image/purchase")
|
||||||
fun purchaseCharacterImage(
|
fun purchaseCharacterImage(
|
||||||
@Header("Authorization") authHeader: String,
|
@Header("Authorization") authHeader: String,
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ class CharacterGalleryRepository(
|
|||||||
fun getCharacterImageList(token: String, characterId: Long, page: Int, size: Int) =
|
fun getCharacterImageList(token: String, characterId: Long, page: Int, size: Int) =
|
||||||
characterApi.getCharacterImageList(authHeader = token, characterId = characterId, page = page, size = size)
|
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) =
|
fun purchaseCharacterImage(token: String, imageId: Long) =
|
||||||
characterApi.purchaseCharacterImage(
|
characterApi.purchaseCharacterImage(
|
||||||
authHeader = token,
|
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)
|
loadProfileImage(binding.ivProfile, info.profileImageUrl)
|
||||||
// 배경 프로필 이미지 (5.5)
|
// 배경 이미지: 저장된 값 우선, 없으면 프로필로 저장/적용
|
||||||
binding.ivBackgroundProfile.load(info.profileImageUrl) {
|
applyBackgroundFromPrefsOrProfile(info.profileImageUrl)
|
||||||
placeholder(R.drawable.ic_placeholder_profile)
|
|
||||||
error(R.drawable.ic_placeholder_profile)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 타입 배지 텍스트 및 배경
|
// 타입 배지 텍스트 및 배경
|
||||||
val (badgeText, badgeBg) = when (info.characterType) {
|
val (badgeText, badgeBg) = when (info.characterType) {
|
||||||
@@ -840,6 +837,37 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
|
|||||||
binding.viewCharacterDim.isVisible = visible
|
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() {
|
fun onResetChatRequested() {
|
||||||
val title = "대화 초기화"
|
val title = "대화 초기화"
|
||||||
val desc = "지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다."
|
val desc = "지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다."
|
||||||
|
|||||||
@@ -57,18 +57,11 @@ class ChatRoomMoreDialogFragment : DialogFragment() {
|
|||||||
switch?.toggle()
|
switch?.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 배경 사진 변경 (임시 안내)
|
// 배경 사진 변경: 배경 선택 다이얼로그 표시
|
||||||
view.findViewById<LinearLayout>(R.id.row_bg_change)?.setOnClickListener {
|
view.findViewById<LinearLayout>(R.id.row_bg_change)?.setOnClickListener {
|
||||||
// TODO: 배경 선택 다이얼로그 연결 (기본 프로필 + 구매한 캐릭터 이미지)
|
val roomIdArg = arguments?.getLong(ARG_ROOM_ID) ?: 0L
|
||||||
SodaDialog(
|
ChatBackgroundPickerDialogFragment.newInstance(roomIdArg)
|
||||||
requireActivity(),
|
.show(parentFragmentManager, "ChatBackgroundPicker")
|
||||||
layoutInflater,
|
|
||||||
title = getString(R.string.app_name),
|
|
||||||
desc = "배경 사진 변경은 곧 제공됩니다.",
|
|
||||||
confirmButtonTitle = "확인",
|
|
||||||
confirmButtonClick = {},
|
|
||||||
cancelButtonTitle = ""
|
|
||||||
).show(resources.displayMetrics.widthPixels)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 대화 초기화: Activity에 위임
|
// 대화 초기화: 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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/color_131313">
|
android:background="@color/color_131313">
|
||||||
@@ -14,8 +13,7 @@
|
|||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="16dp"
|
android:paddingHorizontal="16dp"
|
||||||
android:paddingEnd="16dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
@@ -32,25 +30,25 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:fontFamily="@font/pretendard_bold"
|
android:fontFamily="@font/pretendard_bold"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:text="대화 설정"
|
android:text="대화 설정"
|
||||||
android:textColor="#FFFFFFFF"
|
android:textColor="#FFFFFFFF"
|
||||||
android:textSize="18sp"
|
android:textSize="20sp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/iv_close"
|
app:layout_constraintStart_toEndOf="@id/iv_close" />
|
||||||
tools:text="대화 설정" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
android:id="@+id/scroll"
|
android:id="@+id/scroll"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent">
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/toolbar">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -64,16 +62,16 @@
|
|||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="20dp"
|
android:paddingHorizontal="24dp">
|
||||||
android:paddingEnd="20dp">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
android:text="배경 사진"
|
android:text="배경 사진"
|
||||||
android:textColor="#FFFFFFFF"
|
android:textColor="#B0BEC5"
|
||||||
android:textSize="16sp" />
|
android:textSize="18sp" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/sw_background"
|
android:id="@+id/sw_background"
|
||||||
@@ -93,15 +91,15 @@
|
|||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="20dp"
|
android:paddingHorizontal="24dp">
|
||||||
android:paddingEnd="20dp">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
android:text="배경 사진 변경"
|
android:text="배경 사진 변경"
|
||||||
android:textColor="#FFFFFFFF"
|
android:textColor="#B0BEC5"
|
||||||
android:textSize="16sp" />
|
android:textSize="18sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -115,25 +113,25 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingStart="20dp"
|
android:paddingHorizontal="24dp"
|
||||||
android:paddingEnd="20dp"
|
android:paddingVertical="12dp">
|
||||||
android:paddingTop="12dp"
|
|
||||||
android:paddingBottom="12dp">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
android:text="대화 초기화"
|
android:text="대화 초기화"
|
||||||
android:textColor="#FFFFFFFF"
|
android:textColor="#B0BEC5"
|
||||||
android:textSize="16sp" />
|
android:textSize="18sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
|
android:fontFamily="@font/pretendard_regular"
|
||||||
android:text="지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다."
|
android:text="지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다."
|
||||||
android:textColor="#B3FFFFFF"
|
android:textColor="#B3FFFFFF"
|
||||||
android:textSize="13sp" />
|
android:textSize="16sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -148,15 +146,15 @@
|
|||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="20dp"
|
android:paddingHorizontal="24dp">
|
||||||
android:paddingEnd="20dp">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
android:text="신고하기"
|
android:text="신고하기"
|
||||||
android:textColor="#FFFFFFFF"
|
android:textColor="#B0BEC5"
|
||||||
android:textSize="16sp" />
|
android:textSize="18sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</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