feat(chat-room): 대화 설정 다이얼로그 구현 및 채팅방 초기화 API 연동

- MoreDialog UI 구성 및 동작(배경 스위치/변경, 대화 초기화, 신고하기)
- 방별 배경 표시 SharedPreferences 저장 및 화면 반영
- TalkApi에 resetChatRoom 엔드포인트 추가, Repository 메서드 추가
- ChatRoomActivity와 다이얼로그 연동, 초기화 플로우 구현
This commit is contained in:
2025-08-26 13:30:27 +09:00
parent b3553f80c6
commit 9b1a83bd69
5 changed files with 285 additions and 12 deletions

View File

@@ -28,6 +28,13 @@ interface TalkApi {
@Body request: CreateChatRoomRequest
): Single<ApiResponse<CreateChatRoomResponse>>
// 채팅방 초기화 API (채팅방 생성 응답과 동일 구조 반환)
@POST("/api/chat/room/{roomId}/reset")
fun resetChatRoom(
@Header("Authorization") authHeader: String,
@Path("roomId") roomId: Long
): Single<ApiResponse<CreateChatRoomResponse>>
// 통합 채팅방 입장 API
@GET("/api/chat/room/{roomId}/enter")
fun enterChatRoom(

View File

@@ -184,4 +184,13 @@ class ChatRepository(
insert.andThen(Single.just(serverMsg)).subscribeOn(Schedulers.io())
}
}
/**
* 대화 초기화: 서버에 리셋 요청 → 새 채팅방 ID 반환
*/
fun resetChatRoom(token: String, roomId: Long): Single<CreateChatRoomResponse> {
return talkApi.resetChatRoom(authHeader = token, roomId = roomId)
.subscribeOn(Schedulers.io())
.map { ensureSuccess(it) }
}
}

View File

@@ -67,6 +67,8 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
setupRecyclerView()
setupInputArea()
loadInitialMessages()
// 배경 표시 설정 적용
applyBackgroundVisibility()
}
@SuppressLint("SetTextI18n")
@@ -78,7 +80,7 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
// 더보기 클릭 시 전체화면 다이얼로그 표시
binding.ivMore.setOnClickListener {
ChatRoomMoreDialogFragment().show(supportFragmentManager, "ChatRoomMoreDialog")
ChatRoomMoreDialogFragment.newInstance(roomId).show(supportFragmentManager, "ChatRoomMoreDialog")
}
// 5.3: characterInfo가 있으면 헤더 바인딩, 없으면 기본 플레이스홀더 유지
@@ -685,6 +687,39 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
dialog.show(supportFragmentManager, "ChatImageCarousel")
}
fun applyBackgroundVisibility() {
val visible = prefs.getBoolean("chat_bg_visible_room_$roomId", true)
binding.ivBackgroundProfile.isVisible = visible
binding.viewCharacterDim.isVisible = visible
}
fun onResetChatRequested() {
val title = "대화 초기화"
val desc = "지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다."
SodaDialog(
activity = this,
layoutInflater = this.layoutInflater,
title = title,
desc = desc,
confirmButtonTitle = "초기화",
confirmButtonClick = {
val token = "Bearer ${SharedPreferenceManager.token}"
val disposable = chatRepository.resetChatRoom(token = token, roomId = roomId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
val intent = newIntent(this, response.chatRoomId)
startActivity(intent)
finish()
}, { error ->
showToast(error.message ?: "대화 초기화에 실패했어요.")
})
compositeDisposable.add(disposable)
},
cancelButtonTitle = "취소",
cancelButtonClick = { /* no-op */ }
).show(resources.displayMetrics.widthPixels)
}
companion object {
const val EXTRA_ROOM_ID: String = "extra_room_id"

View File

@@ -1,15 +1,23 @@
package kr.co.vividnext.sodalive.chat.talk.room
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.fragment.app.DialogFragment
import com.google.android.material.switchmaterial.SwitchMaterial
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.SodaDialog
/**
* 채팅방 우측 상단 더보기 버튼 클릭 시 표시되는 전체화면 다이얼로그.
* 내용은 추후 구성 예정이며 현재는 플레이스홀더 UI만 표시합니다.
* - 배경 사진 표시 스위치
* - 배경 사진 변경(추후 상세 다이얼로그 예정)
* - 대화 초기화(확인 후 API 호출은 Activity에서 처리)
* - 신고하기(임시 안내)
*/
class ChatRoomMoreDialogFragment : DialogFragment() {
@@ -26,4 +34,73 @@ class ChatRoomMoreDialogFragment : DialogFragment() {
): View? {
return inflater.inflate(R.layout.fragment_chat_room_more_dialog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val roomId = arguments?.getLong(ARG_ROOM_ID) ?: 0L
// 닫기 버튼
view.findViewById<ImageView>(R.id.iv_close)?.setOnClickListener { dismiss() }
val prefs = requireActivity().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val bgKey = bgPrefKey(roomId)
val switch = view.findViewById<SwitchMaterial>(R.id.sw_background)
switch?.isChecked = prefs.getBoolean(bgKey, true)
switch?.setOnCheckedChangeListener { _, isChecked ->
prefs.edit().putBoolean(bgKey, isChecked).apply()
(activity as? ChatRoomActivity)?.applyBackgroundVisibility()
}
// 행 클릭 시 스위치 토글
view.findViewById<LinearLayout>(R.id.row_bg_switch)?.setOnClickListener {
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)
}
// 대화 초기화: Activity에 위임
view.findViewById<LinearLayout>(R.id.row_reset)?.setOnClickListener {
(activity as? ChatRoomActivity)?.onResetChatRequested()
}
// 신고하기 (임시 안내)
view.findViewById<LinearLayout>(R.id.row_report)?.setOnClickListener {
SodaDialog(
requireActivity(),
layoutInflater,
title = "신고하기",
desc = "신고하기 기능은 준비 중입니다.",
confirmButtonTitle = "확인",
confirmButtonClick = {},
cancelButtonTitle = ""
).show(resources.displayMetrics.widthPixels)
}
}
companion object {
private const val ARG_ROOM_ID = "arg_room_id"
private const val PREFS_NAME = "chat_room_prefs"
private fun bgPrefKey(roomId: Long) = "chat_bg_visible_room_$roomId"
fun newInstance(roomId: Long): ChatRoomMoreDialogFragment {
val f = ChatRoomMoreDialogFragment()
val args = Bundle()
args.putLong(ARG_ROOM_ID, roomId)
f.arguments = args
return f
}
}
}

View File

@@ -1,20 +1,165 @@
<?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="#CC000000">
android:background="@color/color_131313">
<TextView
android:id="@+id/tv_placeholder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="준비중"
android:textColor="@android:color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
<!-- DetailToolbar -->
<LinearLayout
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="56dp"
android:background="@android:color/transparent"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/iv_close"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/a11y_back"
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:ellipsize="end"
android:fontFamily="@font/pretendard_bold"
android:maxLines="1"
android:text="대화 설정"
android:textColor="#FFFFFFFF"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/iv_close"
tools:text="대화 설정" />
</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_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- 배경 사진 스위치 -->
<LinearLayout
android:id="@+id/row_bg_switch"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingEnd="20dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="배경 사진"
android:textColor="#FFFFFFFF"
android:textSize="16sp" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/sw_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#26FFFFFF" />
<!-- 배경 사진 변경 -->
<LinearLayout
android:id="@+id/row_bg_change"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingEnd="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="배경 사진 변경"
android:textColor="#FFFFFFFF"
android:textSize="16sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#26FFFFFF" />
<!-- 대화 초기화 -->
<LinearLayout
android:id="@+id/row_reset"
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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="대화 초기화"
android:textColor="#FFFFFFFF"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다."
android:textColor="#B3FFFFFF"
android:textSize="13sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#26FFFFFF" />
<!-- 신고하기 -->
<LinearLayout
android:id="@+id/row_report"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingEnd="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="신고하기"
android:textColor="#FFFFFFFF"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>