refactor(character-comment): 답글 리스트 MVVM 적용 및 ViewModel 추가
- CharacterCommentReplyViewModel 추가: 로딩/토스트/페이지네이션/CRUD 로직 이관 - AppDI Koin 모듈에 Reply ViewModel 등록 - CharacterCommentReplyFragment에서 Repository 직접 접근 제거 및 바인딩 로직 추가
This commit is contained in:
@@ -13,8 +13,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
@@ -33,17 +31,15 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
|||||||
FragmentCharacterCommentReplyBinding::inflate
|
FragmentCharacterCommentReplyBinding::inflate
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val viewModel: CharacterCommentReplyViewModel by inject()
|
||||||
|
|
||||||
private lateinit var imm: InputMethodManager
|
private lateinit var imm: InputMethodManager
|
||||||
private lateinit var loadingDialog: LoadingDialog
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
private lateinit var adapter: CharacterCommentReplyAdapter
|
private lateinit var adapter: CharacterCommentReplyAdapter
|
||||||
private val repository: CharacterCommentRepository by inject()
|
|
||||||
|
|
||||||
private var original: CharacterCommentResponse? = null
|
private var original: CharacterCommentResponse? = null
|
||||||
private var characterId: Long = 0
|
private var characterId: Long = 0
|
||||||
|
|
||||||
private var cursor: Long? = null
|
|
||||||
private var isLoading: Boolean = false
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
@@ -76,7 +72,9 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
|||||||
imm = requireContext().getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
|
imm = requireContext().getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
|
||||||
setupView()
|
setupView()
|
||||||
loadMore() // 초기 로드 (스텁)
|
bindData()
|
||||||
|
viewModel.init(original!!)
|
||||||
|
viewModel.loadReplies(characterId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
@@ -94,49 +92,8 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
|||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
val text = binding.etComment.text.toString()
|
val text = binding.etComment.text.toString()
|
||||||
if (text.isBlank()) return@setOnClickListener
|
if (text.isBlank()) return@setOnClickListener
|
||||||
val originalId = original?.commentId ?: return@setOnClickListener
|
viewModel.createReply(characterId, text)
|
||||||
val token = "Bearer ${SharedPreferenceManager.token}"
|
binding.etComment.setText("")
|
||||||
loadingDialog.show(screenWidth)
|
|
||||||
val d = repository.createReply(
|
|
||||||
characterId = characterId,
|
|
||||||
commentId = originalId,
|
|
||||||
comment = text,
|
|
||||||
token = token
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.doFinally { loadingDialog.dismiss() }
|
|
||||||
.subscribe({ resp ->
|
|
||||||
if (resp.success) {
|
|
||||||
// 성공 시 낙관적 UI 반영: 기존 스텁과 동일하게 즉시 목록에 추가
|
|
||||||
val me = CharacterReplyResponse(
|
|
||||||
replyId = System.currentTimeMillis(),
|
|
||||||
memberId = SharedPreferenceManager.userId,
|
|
||||||
memberProfileImage = SharedPreferenceManager.profileImage,
|
|
||||||
memberNickname = SharedPreferenceManager.nickname,
|
|
||||||
createdAt = System.currentTimeMillis(),
|
|
||||||
comment = text
|
|
||||||
)
|
|
||||||
val insertAt = adapter.items.size
|
|
||||||
adapter.items.add(me)
|
|
||||||
adapter.notifyItemInserted(insertAt)
|
|
||||||
binding.rvCommentReply.scrollToPosition(adapter.items.size - 1)
|
|
||||||
binding.etComment.setText("")
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
requireContext(),
|
|
||||||
resp.message ?: "요청 중 오류가 발생했습니다",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}, { e ->
|
|
||||||
Toast.makeText(
|
|
||||||
requireContext(),
|
|
||||||
e.message ?: "요청 중 오류가 발생했습니다",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
})
|
|
||||||
compositeDisposable.add(d)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter = CharacterCommentReplyAdapter(
|
adapter = CharacterCommentReplyAdapter(
|
||||||
@@ -146,36 +103,7 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
|||||||
onReport = {
|
onReport = {
|
||||||
val reportSheet = CharacterCommentReportBottomSheet.newInstance()
|
val reportSheet = CharacterCommentReportBottomSheet.newInstance()
|
||||||
reportSheet.onSubmit = { reason ->
|
reportSheet.onSubmit = { reason ->
|
||||||
val token = "Bearer ${SharedPreferenceManager.token}"
|
viewModel.reportReply(characterId, reply.replyId, reason)
|
||||||
val d = repository.reportComment(
|
|
||||||
characterId = characterId,
|
|
||||||
commentId = reply.replyId,
|
|
||||||
reason = reason,
|
|
||||||
token = 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)
|
|
||||||
}
|
}
|
||||||
reportSheet.show(parentFragmentManager, "reply_report")
|
reportSheet.show(parentFragmentManager, "reply_report")
|
||||||
}
|
}
|
||||||
@@ -184,41 +112,7 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
|||||||
.setTitle(getString(R.string.confirm_delete_title))
|
.setTitle(getString(R.string.confirm_delete_title))
|
||||||
.setMessage(getString(R.string.confirm_delete_message))
|
.setMessage(getString(R.string.confirm_delete_message))
|
||||||
.setPositiveButton(getString(R.string.confirm)) { _, _ ->
|
.setPositiveButton(getString(R.string.confirm)) { _, _ ->
|
||||||
val token = "Bearer ${SharedPreferenceManager.token}"
|
viewModel.deleteReply(characterId, reply.replyId)
|
||||||
loadingDialog.show(screenWidth)
|
|
||||||
val d = repository.deleteComment(
|
|
||||||
characterId = characterId,
|
|
||||||
commentId = reply.replyId,
|
|
||||||
token = token
|
|
||||||
).subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.doFinally { loadingDialog.dismiss() }
|
|
||||||
.subscribe({ resp ->
|
|
||||||
if (resp.success) {
|
|
||||||
val index = adapter.items
|
|
||||||
.indexOfFirst {
|
|
||||||
it is CharacterReplyResponse
|
|
||||||
&& it.replyId == reply.replyId
|
|
||||||
}
|
|
||||||
if (index > 0) {
|
|
||||||
adapter.items.removeAt(index)
|
|
||||||
adapter.notifyItemRemoved(index)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
requireActivity(),
|
|
||||||
resp.message ?: "요청 중 오류가 발생했습니다",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}, { e ->
|
|
||||||
Toast.makeText(
|
|
||||||
requireActivity(),
|
|
||||||
e.message ?: "요청 중 오류가 발생했습니다",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
})
|
|
||||||
compositeDisposable.add(d)
|
|
||||||
}
|
}
|
||||||
.setNegativeButton(getString(R.string.cancel), null)
|
.setNegativeButton(getString(R.string.cancel), null)
|
||||||
.show()
|
.show()
|
||||||
@@ -265,10 +159,8 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
|||||||
val lm = recyclerView.layoutManager as LinearLayoutManager
|
val lm = recyclerView.layoutManager as LinearLayoutManager
|
||||||
val last = lm.findLastCompletelyVisibleItemPosition()
|
val last = lm.findLastCompletelyVisibleItemPosition()
|
||||||
val total = (recyclerView.adapter?.itemCount ?: 1) - 1
|
val total = (recyclerView.adapter?.itemCount ?: 1) - 1
|
||||||
val onlyHeader = adapter.items.size <= 1
|
if (!recyclerView.canScrollVertically(1) && last == total) {
|
||||||
val canLoadMore = onlyHeader || cursor != null
|
viewModel.loadReplies(characterId)
|
||||||
if (canLoadMore && !recyclerView.canScrollVertically(1) && last == total) {
|
|
||||||
loadMore()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -279,53 +171,28 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
|||||||
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadMore() {
|
private fun bindData() {
|
||||||
val originalId = original?.commentId ?: return
|
viewModel.isLoading.observe(viewLifecycleOwner) { loading ->
|
||||||
if (isLoading) return
|
if (loading) loadingDialog.show(screenWidth) else loadingDialog.dismiss()
|
||||||
// 초기 로드(헤더만 있는 상태)는 허용. 그 외에는 cursor가 null이면 더 이상 조회하지 않음
|
}
|
||||||
val onlyHeader = adapter.items.size <= 1
|
viewModel.toastLiveData.observe(viewLifecycleOwner) { msg ->
|
||||||
if (!onlyHeader && cursor == null) return
|
msg?.let { showToast(it) }
|
||||||
|
}
|
||||||
val token = "Bearer ${SharedPreferenceManager.token}"
|
viewModel.replies.observe(viewLifecycleOwner) { list ->
|
||||||
isLoading = true
|
// 헤더(원본 댓글)는 index 0에 유지, 나머지를 교체
|
||||||
val d = repository.listReplies(
|
val header = if (adapter.items.isNotEmpty()) adapter.items.first() else original
|
||||||
characterId = characterId,
|
adapter.items.clear()
|
||||||
commentId = originalId,
|
header?.let { adapter.items.add(it) }
|
||||||
limit = 20,
|
adapter.items.addAll(list)
|
||||||
cursor = cursor,
|
adapter.notifyDataSetChanged()
|
||||||
token = token
|
// 스크롤을 하단으로 이동 (신규 추가 시 사용자에게 피드백)
|
||||||
)
|
if (adapter.itemCount > 0) {
|
||||||
.subscribeOn(Schedulers.io())
|
binding.rvCommentReply.scrollToPosition(adapter.itemCount - 1)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
}
|
||||||
.doFinally { isLoading = false }
|
}
|
||||||
.subscribe({ resp ->
|
|
||||||
if (resp.success) {
|
|
||||||
val data = resp.data
|
|
||||||
// 서버에서 original 포함되지만, 이미 헤더에 추가되어 있으므로 replies만 사용
|
|
||||||
val replies = data?.replies ?: emptyList()
|
|
||||||
if (replies.isNotEmpty()) {
|
|
||||||
val start = adapter.items.size
|
|
||||||
adapter.items.addAll(replies)
|
|
||||||
adapter.notifyItemRangeInserted(start, replies.size)
|
|
||||||
}
|
|
||||||
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 {
|
companion object {
|
||||||
private const val EXTRA_CHARACTER_ID = "extra_character_id"
|
private const val EXTRA_CHARACTER_ID = "extra_character_id"
|
||||||
private const val EXTRA_ORIGINAL_COMMENT_ID = "extra_original_comment_id"
|
private const val EXTRA_ORIGINAL_COMMENT_ID = "extra_original_comment_id"
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
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 CharacterCommentReplyViewModel(
|
||||||
|
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 _original = MutableLiveData<CharacterCommentResponse?>()
|
||||||
|
val original: LiveData<CharacterCommentResponse?> get() = _original
|
||||||
|
|
||||||
|
private val _replies = MutableLiveData<List<CharacterReplyResponse>>(emptyList())
|
||||||
|
val replies: LiveData<List<CharacterReplyResponse>> get() = _replies
|
||||||
|
|
||||||
|
private var cursor: Long? = null
|
||||||
|
private var page: Int = 1
|
||||||
|
|
||||||
|
fun init(original: CharacterCommentResponse) {
|
||||||
|
_original.value = original
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reset() {
|
||||||
|
cursor = null
|
||||||
|
page = 1
|
||||||
|
_replies.value = emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadReplies(characterId: Long) {
|
||||||
|
val originalId = _original.value?.commentId ?: return
|
||||||
|
if (_isLoading.value == true) return
|
||||||
|
val onlyHeader = (_replies.value?.isEmpty() ?: true)
|
||||||
|
if (!onlyHeader && cursor == null) return
|
||||||
|
|
||||||
|
_isLoading.value = true
|
||||||
|
val token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.listReplies(
|
||||||
|
characterId = characterId,
|
||||||
|
commentId = originalId,
|
||||||
|
limit = 20,
|
||||||
|
cursor = cursor,
|
||||||
|
token = token
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ resp ->
|
||||||
|
_isLoading.value = false
|
||||||
|
if (resp.success && resp.data != null) {
|
||||||
|
val newReplies = resp.data.replies
|
||||||
|
val current = _replies.value ?: emptyList()
|
||||||
|
_replies.postValue(current + newReplies)
|
||||||
|
cursor = resp.data.cursor
|
||||||
|
page += 1
|
||||||
|
} else {
|
||||||
|
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
_toastLiveData.postValue(message)
|
||||||
|
}
|
||||||
|
}, { e ->
|
||||||
|
_isLoading.value = false
|
||||||
|
Logger.e(e, "Character replies load failed")
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createReply(characterId: Long, comment: String) {
|
||||||
|
if (comment.isBlank()) {
|
||||||
|
_toastLiveData.postValue("내용을 입력하세요")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val originalId = _original.value?.commentId ?: return
|
||||||
|
if (_isLoading.value == true) return
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
val token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.createReply(
|
||||||
|
characterId = characterId,
|
||||||
|
commentId = originalId,
|
||||||
|
comment = comment,
|
||||||
|
token = token
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ resp ->
|
||||||
|
_isLoading.value = false
|
||||||
|
if (resp.success) {
|
||||||
|
// 낙관적 추가
|
||||||
|
val me = CharacterReplyResponse(
|
||||||
|
replyId = System.currentTimeMillis(),
|
||||||
|
memberId = SharedPreferenceManager.userId,
|
||||||
|
memberProfileImage = SharedPreferenceManager.profileImage,
|
||||||
|
memberNickname = SharedPreferenceManager.nickname,
|
||||||
|
createdAt = System.currentTimeMillis(),
|
||||||
|
comment = comment
|
||||||
|
)
|
||||||
|
val current = _replies.value ?: emptyList()
|
||||||
|
_replies.postValue(current + listOf(me))
|
||||||
|
} else {
|
||||||
|
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
_toastLiveData.postValue(message)
|
||||||
|
}
|
||||||
|
}, { e ->
|
||||||
|
_isLoading.value = false
|
||||||
|
Logger.e(e, "Character reply create failed")
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteReply(characterId: Long, replyId: Long) {
|
||||||
|
if (_isLoading.value == true) return
|
||||||
|
_isLoading.value = true
|
||||||
|
val token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.deleteComment(
|
||||||
|
characterId = characterId,
|
||||||
|
commentId = replyId,
|
||||||
|
token = token
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ resp ->
|
||||||
|
_isLoading.value = false
|
||||||
|
if (resp.success) {
|
||||||
|
val current = _replies.value ?: emptyList()
|
||||||
|
_replies.postValue(current.filterNot { it.replyId == replyId })
|
||||||
|
} else {
|
||||||
|
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
_toastLiveData.postValue(message)
|
||||||
|
}
|
||||||
|
}, { e ->
|
||||||
|
_isLoading.value = false
|
||||||
|
Logger.e(e, "Character reply delete failed")
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reportReply(characterId: Long, replyId: 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 = replyId,
|
||||||
|
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 reply report failed")
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -360,6 +360,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||||||
viewModel { CharacterDetailViewModel(get()) }
|
viewModel { CharacterDetailViewModel(get()) }
|
||||||
viewModel { TalkTabViewModel(get()) }
|
viewModel { TalkTabViewModel(get()) }
|
||||||
viewModel { kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentListViewModel(get()) }
|
viewModel { kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentListViewModel(get()) }
|
||||||
|
viewModel { kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentReplyViewModel(get()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val repositoryModule = module {
|
private val repositoryModule = module {
|
||||||
|
|||||||
Reference in New Issue
Block a user