refactor(chat/character): 댓글 리스트 화면에 ViewModel 도입 및 Fragment-Repository 직접 의존 제거
CharacterCommentListViewModel을 추가하여 댓글 조회/등록/삭제/신고 및 페이지네이션 로직을 ViewModel로 이전. Fragment는 UI 업데이트와 사용자 입력 처리에 집중하도록 리팩토링. Koin DI에 ViewModel 등록.
This commit is contained in:
		@@ -8,14 +8,12 @@ import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.view.inputmethod.InputMethodManager
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.appcompat.app.AlertDialog
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import coil.load
 | 
			
		||||
import coil.transform.CircleCropTransformation
 | 
			
		||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
 | 
			
		||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
 | 
			
		||||
import io.reactivex.rxjava3.schedulers.Schedulers
 | 
			
		||||
import kr.co.vividnext.sodalive.R
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.common.LoadingDialog
 | 
			
		||||
@@ -28,7 +26,7 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
 | 
			
		||||
    FragmentCharacterCommentListBinding::inflate
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    private val repository: CharacterCommentRepository by inject()
 | 
			
		||||
    private val viewModel: CharacterCommentListViewModel by inject()
 | 
			
		||||
 | 
			
		||||
    private lateinit var imm: InputMethodManager
 | 
			
		||||
    private lateinit var loadingDialog: LoadingDialog
 | 
			
		||||
@@ -54,7 +52,7 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
 | 
			
		||||
        setupView()
 | 
			
		||||
        bindData()
 | 
			
		||||
        // 초기 로드
 | 
			
		||||
        resetAndLoad()
 | 
			
		||||
        viewModel.reset(characterId)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun hideDialog() {
 | 
			
		||||
@@ -75,31 +73,8 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
 | 
			
		||||
            hideKeyboard()
 | 
			
		||||
            val comment = binding.etComment.text.toString()
 | 
			
		||||
            if (comment.isBlank()) return@setOnClickListener
 | 
			
		||||
            val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
            loadingDialog.show(screenWidth)
 | 
			
		||||
            val d = repository.createComment(characterId, comment, token)
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .doFinally { loadingDialog.dismiss() }
 | 
			
		||||
                .subscribe({ resp ->
 | 
			
		||||
                    if (resp.success) {
 | 
			
		||||
                        binding.etComment.setText("")
 | 
			
		||||
                        resetAndLoad()
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Toast.makeText(
 | 
			
		||||
                            requireContext(),
 | 
			
		||||
                            resp.message ?: "요청 중 오류가 발생했습니다",
 | 
			
		||||
                            Toast.LENGTH_SHORT
 | 
			
		||||
                        ).show()
 | 
			
		||||
                    }
 | 
			
		||||
                }, { e ->
 | 
			
		||||
                    Toast.makeText(
 | 
			
		||||
                        requireContext(),
 | 
			
		||||
                        e.message ?: "요청 중 오류가 발생했습니다",
 | 
			
		||||
                        Toast.LENGTH_SHORT
 | 
			
		||||
                    ).show()
 | 
			
		||||
                })
 | 
			
		||||
            compositeDisposable.add(d)
 | 
			
		||||
            viewModel.createComment(characterId, comment)
 | 
			
		||||
            binding.etComment.setText("")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        adapter = CharacterCommentsAdapter(
 | 
			
		||||
@@ -109,74 +84,20 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
 | 
			
		||||
                    onReport = {
 | 
			
		||||
                        val reportSheet = CharacterCommentReportBottomSheet.newInstance()
 | 
			
		||||
                        reportSheet.onSubmit = { reason ->
 | 
			
		||||
                            val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
                            val d =
 | 
			
		||||
                                repository.reportComment(characterId, item.commentId, reason, token)
 | 
			
		||||
                                    .subscribeOn(Schedulers.io())
 | 
			
		||||
                                    .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                                    .subscribe({ resp ->
 | 
			
		||||
                                        if (resp.success) {
 | 
			
		||||
                                            Toast.makeText(
 | 
			
		||||
                                                requireContext(),
 | 
			
		||||
                                                "신고가 접수되었습니다.",
 | 
			
		||||
                                                Toast.LENGTH_SHORT
 | 
			
		||||
                                            ).show()
 | 
			
		||||
                                        } else {
 | 
			
		||||
                                            Toast.makeText(
 | 
			
		||||
                                                requireContext(),
 | 
			
		||||
                                                resp.message ?: "요청 중 오류가 발생했습니다",
 | 
			
		||||
                                                Toast.LENGTH_SHORT
 | 
			
		||||
                                            ).show()
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }, { e ->
 | 
			
		||||
                                        Toast.makeText(
 | 
			
		||||
                                            requireContext(),
 | 
			
		||||
                                            e.message ?: "요청 중 오류가 발생했습니다",
 | 
			
		||||
                                            Toast.LENGTH_SHORT
 | 
			
		||||
                                        ).show()
 | 
			
		||||
                                    })
 | 
			
		||||
                            compositeDisposable.add(d)
 | 
			
		||||
                            viewModel.reportComment(characterId, item.commentId, reason)
 | 
			
		||||
                        }
 | 
			
		||||
                        reportSheet.show(parentFragmentManager, "comment_report")
 | 
			
		||||
                    }
 | 
			
		||||
                    onDelete = {
 | 
			
		||||
                        // 삭제 확인 팝업
 | 
			
		||||
                        androidx.appcompat.app.AlertDialog.Builder(requireContext())
 | 
			
		||||
                        AlertDialog.Builder(requireContext())
 | 
			
		||||
                            .setTitle(getString(R.string.confirm_delete_title))
 | 
			
		||||
                            .setMessage(getString(R.string.confirm_delete_message))
 | 
			
		||||
                            .setPositiveButton(getString(R.string.confirm)) { _, _ ->
 | 
			
		||||
                                val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
                                loadingDialog.show(screenWidth)
 | 
			
		||||
                                val d = repository.deleteComment(
 | 
			
		||||
                                viewModel.deleteComment(
 | 
			
		||||
                                    characterId = characterId,
 | 
			
		||||
                                    commentId = item.commentId,
 | 
			
		||||
                                    token = token
 | 
			
		||||
                                    commentId = item.commentId
 | 
			
		||||
                                )
 | 
			
		||||
                                    .subscribeOn(Schedulers.io())
 | 
			
		||||
                                    .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                                    .doFinally { loadingDialog.dismiss() }
 | 
			
		||||
                                    .subscribe({ resp ->
 | 
			
		||||
                                        if (resp.success) {
 | 
			
		||||
                                            val index = adapter.items.indexOfFirst { it.commentId == item.commentId }
 | 
			
		||||
                                            if (index >= 0) {
 | 
			
		||||
                                                adapter.items.removeAt(index)
 | 
			
		||||
                                                adapter.notifyItemRemoved(index)
 | 
			
		||||
                                            }
 | 
			
		||||
                                        } else {
 | 
			
		||||
                                            Toast.makeText(
 | 
			
		||||
                                                requireContext(),
 | 
			
		||||
                                                resp.message ?: "요청 중 오류가 발생했습니다",
 | 
			
		||||
                                                Toast.LENGTH_SHORT
 | 
			
		||||
                                            ).show()
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }, { e ->
 | 
			
		||||
                                        Toast.makeText(
 | 
			
		||||
                                            requireContext(),
 | 
			
		||||
                                            e.message ?: "요청 중 오류가 발생했습니다",
 | 
			
		||||
                                            Toast.LENGTH_SHORT
 | 
			
		||||
                                        ).show()
 | 
			
		||||
                                    })
 | 
			
		||||
                                compositeDisposable.add(d)
 | 
			
		||||
                            }
 | 
			
		||||
                            .setNegativeButton(getString(R.string.cancel), null)
 | 
			
		||||
                            .show()
 | 
			
		||||
@@ -229,13 +150,11 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
 | 
			
		||||
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
 | 
			
		||||
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
 | 
			
		||||
                super.onScrolled(recyclerView, dx, dy)
 | 
			
		||||
                val lastVisible =
 | 
			
		||||
                    (recyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition()
 | 
			
		||||
                val lastVisible = (recyclerView.layoutManager as LinearLayoutManager)
 | 
			
		||||
                        .findLastCompletelyVisibleItemPosition()
 | 
			
		||||
                val total = recyclerView.adapter?.itemCount ?: 0
 | 
			
		||||
                // 초기 진입(아이템 없음) 또는 다음 페이지가 존재할 때(cursor != null)에만 로드
 | 
			
		||||
                val canLoadMore = adapter.items.isEmpty() || cursor != null
 | 
			
		||||
                if (canLoadMore && !recyclerView.canScrollVertically(1) && lastVisible == total - 1) {
 | 
			
		||||
                    loadMore()
 | 
			
		||||
                if (!recyclerView.canScrollVertically(1) && lastVisible == total - 1) {
 | 
			
		||||
                    viewModel.getCommentList(characterId)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
@@ -245,57 +164,37 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("NotifyDataSetChanged")
 | 
			
		||||
    private fun bindData() {
 | 
			
		||||
        // total count 스텁: 어댑터 크기 사용
 | 
			
		||||
        // 필요 시 ViewModel 도입 가능
 | 
			
		||||
        viewModel.isLoading.observe(viewLifecycleOwner) {
 | 
			
		||||
            if (it) {
 | 
			
		||||
                loadingDialog.show(screenWidth)
 | 
			
		||||
            } else {
 | 
			
		||||
                loadingDialog.dismiss()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.toastLiveData.observe(viewLifecycleOwner) { msg ->
 | 
			
		||||
 | 
			
		||||
            msg?.let { showToast(it) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.totalCommentCount.observe(viewLifecycleOwner) { count ->
 | 
			
		||||
            binding.tvCommentCount.text = "$count"
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.commentList.observe(viewLifecycleOwner) { items ->
 | 
			
		||||
            if (viewModel.page - 1 == 1) {
 | 
			
		||||
                adapter.items.clear()
 | 
			
		||||
                binding.rvComment.scrollToPosition(0)
 | 
			
		||||
            }
 | 
			
		||||
            adapter.items.addAll(items)
 | 
			
		||||
            adapter.notifyDataSetChanged()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun hideKeyboard() {
 | 
			
		||||
        imm.hideSoftInputFromWindow(view?.windowToken, 0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private var cursor: Long? = null
 | 
			
		||||
    private var isLoading = false
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("NotifyDataSetChanged")
 | 
			
		||||
    private fun resetAndLoad() {
 | 
			
		||||
        cursor = null
 | 
			
		||||
        adapter.items.clear()
 | 
			
		||||
        adapter.notifyDataSetChanged()
 | 
			
		||||
        loadMore()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun loadMore() {
 | 
			
		||||
        if (isLoading) return
 | 
			
		||||
        // 초기 로드(아이템 없음)는 허용. 그 외에는 cursor가 null이면 더 이상 로드하지 않음
 | 
			
		||||
        if (adapter.items.isNotEmpty() && cursor == null) return
 | 
			
		||||
        val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
        isLoading = true
 | 
			
		||||
        val d = repository.listComments(characterId, 20, cursor, token)
 | 
			
		||||
            .subscribeOn(Schedulers.io())
 | 
			
		||||
            .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
            .doFinally { isLoading = false }
 | 
			
		||||
            .subscribe({ resp ->
 | 
			
		||||
                if (resp.success) {
 | 
			
		||||
                    val data = resp.data
 | 
			
		||||
                    val items = data?.comments ?: emptyList()
 | 
			
		||||
                    val start = adapter.items.size
 | 
			
		||||
                    adapter.items.addAll(items)
 | 
			
		||||
                    adapter.notifyItemRangeInserted(start, items.size)
 | 
			
		||||
                    binding.tvCommentCount.text = data?.totalCount?.toString() ?: "0"
 | 
			
		||||
                    cursor = data?.cursor
 | 
			
		||||
                } else {
 | 
			
		||||
                    Toast.makeText(
 | 
			
		||||
                        requireContext(),
 | 
			
		||||
                        resp.message ?: "요청 중 오류가 발생했습니다",
 | 
			
		||||
                        Toast.LENGTH_SHORT
 | 
			
		||||
                    ).show()
 | 
			
		||||
                }
 | 
			
		||||
            }, { e ->
 | 
			
		||||
                Toast.makeText(requireContext(), e.message ?: "요청 중 오류가 발생했습니다", Toast.LENGTH_SHORT)
 | 
			
		||||
                    .show()
 | 
			
		||||
            })
 | 
			
		||||
        compositeDisposable.add(d)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val EXTRA_CHARACTER_ID = "extra_character_id"
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,197 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.chat.character.comment
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.LiveData
 | 
			
		||||
import androidx.lifecycle.MutableLiveData
 | 
			
		||||
import com.orhanobut.logger.Logger
 | 
			
		||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
 | 
			
		||||
import io.reactivex.rxjava3.schedulers.Schedulers
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
 | 
			
		||||
class CharacterCommentListViewModel(
 | 
			
		||||
    private val repository: CharacterCommentRepository
 | 
			
		||||
) : BaseViewModel() {
 | 
			
		||||
 | 
			
		||||
    private val _toastLiveData = MutableLiveData<String?>()
 | 
			
		||||
    val toastLiveData: LiveData<String?>
 | 
			
		||||
        get() = _toastLiveData
 | 
			
		||||
 | 
			
		||||
    private val _isLoading = MutableLiveData(false)
 | 
			
		||||
    val isLoading: LiveData<Boolean>
 | 
			
		||||
        get() = _isLoading
 | 
			
		||||
 | 
			
		||||
    private val _commentList = MutableLiveData<List<CharacterCommentResponse>>()
 | 
			
		||||
    val commentList: LiveData<List<CharacterCommentResponse>>
 | 
			
		||||
        get() = _commentList
 | 
			
		||||
 | 
			
		||||
    private val _totalCommentCount = MutableLiveData(0)
 | 
			
		||||
    val totalCommentCount: LiveData<Int>
 | 
			
		||||
        get() = _totalCommentCount
 | 
			
		||||
 | 
			
		||||
    // 페이지네이션 상태 (cursor 기반이지만 UI에선 1페이지 초기화 판단을 위해 page 인덱스 유지)
 | 
			
		||||
    var page: Int = 1
 | 
			
		||||
        private set
 | 
			
		||||
    private var isLast: Boolean = false
 | 
			
		||||
    private val size: Int = 20
 | 
			
		||||
    private var cursor: Long? = null
 | 
			
		||||
 | 
			
		||||
    fun reset(characterId: Long) {
 | 
			
		||||
        page = 1
 | 
			
		||||
        isLast = false
 | 
			
		||||
        cursor = null
 | 
			
		||||
        getCommentList(characterId)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getCommentList(characterId: Long, onFailure: (() -> Unit)? = null) {
 | 
			
		||||
        // 로딩 중이면 차단
 | 
			
		||||
        if (_isLoading.value == true) return
 | 
			
		||||
        // 이슈 요구사항: 초기 1회 로드 허용, 이후엔 cursor != null일 때만 추가 로드
 | 
			
		||||
        if (page > 1 && cursor == null) return
 | 
			
		||||
        // 이미 마지막이면 차단 (보조 안전장치)
 | 
			
		||||
        if (isLast) return
 | 
			
		||||
 | 
			
		||||
        _isLoading.value = true
 | 
			
		||||
 | 
			
		||||
        val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
        compositeDisposable.add(
 | 
			
		||||
            repository.listComments(
 | 
			
		||||
                characterId = characterId,
 | 
			
		||||
                limit = size,
 | 
			
		||||
                cursor = cursor,
 | 
			
		||||
                token = token
 | 
			
		||||
            )
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe({ resp ->
 | 
			
		||||
                    _isLoading.value = false
 | 
			
		||||
                    if (resp.success && resp.data != null) {
 | 
			
		||||
                        // total count 업데이트
 | 
			
		||||
                        _totalCommentCount.postValue(resp.data.totalCount)
 | 
			
		||||
 | 
			
		||||
                        // 다음 페이지 커서 및 마지막 여부 갱신
 | 
			
		||||
                        val nextCursor = resp.data.cursor
 | 
			
		||||
                        cursor = nextCursor
 | 
			
		||||
                        isLast = (nextCursor == null)
 | 
			
		||||
 | 
			
		||||
                        // 페이지 인덱스 증가 (UI에서 초기화 판단용)
 | 
			
		||||
                        page += 1
 | 
			
		||||
 | 
			
		||||
                        val items = resp.data.comments
 | 
			
		||||
                        // 응답 아이템 전달 (비어있어도 전달) — UI는 addAll 처리
 | 
			
		||||
                        _commentList.postValue(items)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
 | 
			
		||||
                        _toastLiveData.postValue(message)
 | 
			
		||||
                        onFailure?.invoke()
 | 
			
		||||
                    }
 | 
			
		||||
                }, { e ->
 | 
			
		||||
                    _isLoading.value = false
 | 
			
		||||
                    Logger.e(e, "Character comments load failed")
 | 
			
		||||
                    _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
			
		||||
                    onFailure?.invoke()
 | 
			
		||||
                })
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun createComment(characterId: Long, comment: String) {
 | 
			
		||||
        if (comment.isBlank()) {
 | 
			
		||||
            _toastLiveData.postValue("내용을 입력하세요")
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        if (_isLoading.value == true) return
 | 
			
		||||
        _isLoading.value = true
 | 
			
		||||
 | 
			
		||||
        val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
        compositeDisposable.add(
 | 
			
		||||
            repository.createComment(
 | 
			
		||||
                characterId = characterId,
 | 
			
		||||
                comment = comment,
 | 
			
		||||
                token = token
 | 
			
		||||
            )
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe({ resp ->
 | 
			
		||||
                    _isLoading.value = false
 | 
			
		||||
                    if (resp.success) {
 | 
			
		||||
                        // 목록 초기화 후 재조회
 | 
			
		||||
                        page = 1
 | 
			
		||||
                        isLast = false
 | 
			
		||||
                        cursor = null
 | 
			
		||||
                        getCommentList(characterId)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
 | 
			
		||||
                        _toastLiveData.postValue(message)
 | 
			
		||||
                    }
 | 
			
		||||
                }, { e ->
 | 
			
		||||
                    _isLoading.value = false
 | 
			
		||||
                    Logger.e(e, "Character comment create failed")
 | 
			
		||||
                    _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
			
		||||
                })
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun deleteComment(characterId: Long, commentId: Long) {
 | 
			
		||||
        if (_isLoading.value == true) return
 | 
			
		||||
        _isLoading.value = true
 | 
			
		||||
        val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
        compositeDisposable.add(
 | 
			
		||||
            repository.deleteComment(
 | 
			
		||||
                characterId = characterId,
 | 
			
		||||
                commentId = commentId,
 | 
			
		||||
                token = token
 | 
			
		||||
            )
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe({ resp ->
 | 
			
		||||
                    _isLoading.value = false
 | 
			
		||||
                    if (resp.success) {
 | 
			
		||||
                        // 간단하게 전체를 새로고침
 | 
			
		||||
                        page = 1
 | 
			
		||||
                        isLast = false
 | 
			
		||||
                        cursor = null
 | 
			
		||||
                        getCommentList(characterId)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
 | 
			
		||||
                        _toastLiveData.postValue(message)
 | 
			
		||||
                    }
 | 
			
		||||
                }, { e ->
 | 
			
		||||
                    _isLoading.value = false
 | 
			
		||||
                    Logger.e(e, "Character comment delete failed")
 | 
			
		||||
                    _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
			
		||||
                })
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun reportComment(characterId: Long, commentId: Long, reason: String) {
 | 
			
		||||
        if (reason.isBlank()) {
 | 
			
		||||
            _toastLiveData.postValue("신고 사유를 입력하세요")
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        if (_isLoading.value == true) return
 | 
			
		||||
        _isLoading.value = true
 | 
			
		||||
        val token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
        compositeDisposable.add(
 | 
			
		||||
            repository.reportComment(
 | 
			
		||||
                characterId = characterId,
 | 
			
		||||
                commentId = commentId,
 | 
			
		||||
                reason = reason,
 | 
			
		||||
                token = token
 | 
			
		||||
            )
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe({ resp ->
 | 
			
		||||
                    _isLoading.value = false
 | 
			
		||||
                    if (resp.success) {
 | 
			
		||||
                        _toastLiveData.postValue("신고가 접수되었습니다.")
 | 
			
		||||
                    } else {
 | 
			
		||||
                        val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
 | 
			
		||||
                        _toastLiveData.postValue(message)
 | 
			
		||||
                    }
 | 
			
		||||
                }, { e ->
 | 
			
		||||
                    _isLoading.value = false
 | 
			
		||||
                    Logger.e(e, "Character comment report failed")
 | 
			
		||||
                    _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
			
		||||
                })
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -359,6 +359,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
			
		||||
        viewModel { CharacterTabViewModel(get()) }
 | 
			
		||||
        viewModel { CharacterDetailViewModel(get()) }
 | 
			
		||||
        viewModel { TalkTabViewModel(get()) }
 | 
			
		||||
        viewModel { kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentListViewModel(get()) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val repositoryModule = module {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user