feat(live-room): 라이브룸 채팅 삭제 기능 구현을 반영한다
This commit is contained in:
@@ -144,9 +144,14 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||
private lateinit var imm: InputMethodManager
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private val chatAdapter = LiveRoomChatAdapter { userId ->
|
||||
showLiveRoomUserProfileDialog(userId = userId)
|
||||
}
|
||||
private val chatAdapter = LiveRoomChatAdapter(
|
||||
onClickProfile = { userId ->
|
||||
showLiveRoomUserProfileDialog(userId = userId)
|
||||
},
|
||||
onLongClickNormalChat = { chat ->
|
||||
onLongClickChat(chat)
|
||||
}
|
||||
)
|
||||
private lateinit var layoutManager: LinearLayoutManager
|
||||
private var rvChatBaseBottomMargin: Int? = null
|
||||
|
||||
@@ -1633,8 +1638,128 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||
)
|
||||
}
|
||||
|
||||
private fun onLongClickChat(chat: LiveRoomNormalChat) {
|
||||
if (!isHost) {
|
||||
return
|
||||
}
|
||||
|
||||
LiveDialog(
|
||||
activity = this,
|
||||
layoutInflater = layoutInflater,
|
||||
title = getString(R.string.screen_live_room_chat_delete_title),
|
||||
desc = getString(
|
||||
R.string.screen_live_room_chat_delete_message_format,
|
||||
chat.nickname,
|
||||
chat.chat
|
||||
),
|
||||
confirmButtonTitle = getString(R.string.confirm_delete_title),
|
||||
confirmButtonClick = {
|
||||
deleteChat(chat)
|
||||
},
|
||||
cancelButtonTitle = getString(R.string.cancel),
|
||||
cancelButtonClick = {}
|
||||
).show(screenWidth)
|
||||
}
|
||||
|
||||
private fun createChatId(): String {
|
||||
return "${SharedPreferenceManager.userId}_${System.currentTimeMillis()}_${Random.nextInt(1000, 9999)}"
|
||||
}
|
||||
|
||||
private fun deleteChat(chat: LiveRoomNormalChat) {
|
||||
if (chat.chatId.isNotBlank()) {
|
||||
removeNormalChatById(chat.chatId)
|
||||
} else {
|
||||
removeNormalChatByUserAndMessage(
|
||||
userId = chat.userId,
|
||||
message = chat.chat
|
||||
)
|
||||
}
|
||||
|
||||
agora.sendRawMessageToGroup(
|
||||
rawMessage = Gson().toJson(
|
||||
LiveRoomChatRawMessage(
|
||||
type = LiveRoomChatRawMessageType.DELETE_CHAT,
|
||||
message = chat.chat,
|
||||
can = 0,
|
||||
donationMessage = "",
|
||||
chatId = chat.chatId.takeIf { it.isNotBlank() },
|
||||
targetUserId = chat.userId
|
||||
)
|
||||
).toByteArray()
|
||||
)
|
||||
}
|
||||
|
||||
private fun deleteChatsByUser(userId: Long) {
|
||||
if (userId <= 0L) {
|
||||
return
|
||||
}
|
||||
|
||||
removeChatsByUserId(userId)
|
||||
|
||||
agora.sendRawMessageToGroup(
|
||||
rawMessage = Gson().toJson(
|
||||
LiveRoomChatRawMessage(
|
||||
type = LiveRoomChatRawMessageType.DELETE_CHAT_BY_USER,
|
||||
message = "",
|
||||
can = 0,
|
||||
donationMessage = "",
|
||||
targetUserId = userId
|
||||
)
|
||||
).toByteArray()
|
||||
)
|
||||
}
|
||||
|
||||
private fun removeNormalChatById(chatId: String) {
|
||||
if (chatId.isBlank()) {
|
||||
return
|
||||
}
|
||||
|
||||
val removed = chatAdapter.items.removeAll { chat ->
|
||||
chat is LiveRoomNormalChat && chat.chatId == chatId
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
invalidateChat()
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeNormalChatByUserAndMessage(userId: Long, message: String) {
|
||||
if (userId <= 0L || message.isBlank()) {
|
||||
return
|
||||
}
|
||||
|
||||
val targetIndex = chatAdapter.items.indexOfFirst { chat ->
|
||||
chat is LiveRoomNormalChat && chat.userId == userId && chat.chat == message
|
||||
}
|
||||
|
||||
if (targetIndex >= 0) {
|
||||
chatAdapter.items.removeAt(targetIndex)
|
||||
invalidateChat()
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeChatsByUserId(userId: Long) {
|
||||
if (userId <= 0L) {
|
||||
return
|
||||
}
|
||||
|
||||
val removed = chatAdapter.items.removeAll { chat ->
|
||||
when (chat) {
|
||||
is LiveRoomNormalChat -> chat.userId == userId
|
||||
is LiveRoomDonationChat -> chat.memberId == userId
|
||||
is LiveRoomRouletteDonationChat -> chat.memberId == userId
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
invalidateChat()
|
||||
}
|
||||
}
|
||||
|
||||
private fun kickOut(userId: Long) {
|
||||
viewModel.kickOut(roomId, userId)
|
||||
deleteChatsByUser(userId)
|
||||
agora.sendRawMessageToPeer(
|
||||
receiverUid = userId.toString(),
|
||||
requestType = LiveRoomRequestType.KICK_OUT
|
||||
@@ -1725,24 +1850,37 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||
).show()
|
||||
} else if (binding.etChat.text.isNotBlank() && nickname.isNotBlank() && profileUrl.isNotBlank()) {
|
||||
val message = binding.etChat.text.toString()
|
||||
val chatId = createChatId()
|
||||
chatAdapter.items.add(
|
||||
LiveRoomNormalChat(
|
||||
userId = SharedPreferenceManager.userId,
|
||||
profileUrl = profileUrl,
|
||||
nickname = nickname,
|
||||
rank = rank,
|
||||
chat = message
|
||||
chat = message,
|
||||
chatId = chatId
|
||||
)
|
||||
)
|
||||
invalidateChat()
|
||||
|
||||
agora.inputChat(message) {
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
getString(R.string.screen_live_room_connection_issue),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
agora.sendRawMessageToGroup(
|
||||
rawMessage = Gson().toJson(
|
||||
LiveRoomChatRawMessage(
|
||||
type = LiveRoomChatRawMessageType.NORMAL_CHAT,
|
||||
message = message,
|
||||
can = 0,
|
||||
donationMessage = "",
|
||||
chatId = chatId
|
||||
)
|
||||
).toByteArray(),
|
||||
onFailure = {
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
getString(R.string.screen_live_room_connection_issue),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
)
|
||||
binding.etChat.setText("")
|
||||
}
|
||||
}
|
||||
@@ -2093,6 +2231,81 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||
}
|
||||
}
|
||||
|
||||
LiveRoomChatRawMessageType.NORMAL_CHAT -> {
|
||||
if (message.message.isBlank()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
memberId.toLong() != SharedPreferenceManager.userId &&
|
||||
!viewModel.isNotBlockedMember(memberId.toLong())
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
val chatId = message.chatId ?: ""
|
||||
if (chatId.isBlank()) {
|
||||
return
|
||||
}
|
||||
|
||||
handler.post {
|
||||
val alreadyExists = chatAdapter.items.any { chat ->
|
||||
chat is LiveRoomNormalChat && chat.chatId == chatId
|
||||
}
|
||||
if (!alreadyExists) {
|
||||
chatAdapter.items.add(
|
||||
LiveRoomNormalChat(
|
||||
userId = memberId.toLong(),
|
||||
profileUrl = profileUrl,
|
||||
nickname = nickname,
|
||||
rank = rank,
|
||||
chat = message.message,
|
||||
chatId = chatId
|
||||
)
|
||||
)
|
||||
invalidateChat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LiveRoomChatRawMessageType.DELETE_CHAT -> {
|
||||
if (!viewModel.isEqualToHostId(memberId.toInt())) {
|
||||
return
|
||||
}
|
||||
|
||||
val chatId = message.chatId
|
||||
if (!chatId.isNullOrBlank()) {
|
||||
handler.post {
|
||||
removeNormalChatById(chatId)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val targetUserId = message.targetUserId ?: return
|
||||
if (message.message.isBlank()) {
|
||||
return
|
||||
}
|
||||
|
||||
handler.post {
|
||||
removeNormalChatByUserAndMessage(
|
||||
userId = targetUserId,
|
||||
message = message.message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LiveRoomChatRawMessageType.DELETE_CHAT_BY_USER -> {
|
||||
if (!viewModel.isEqualToHostId(memberId.toInt())) {
|
||||
return
|
||||
}
|
||||
|
||||
val targetUserId = message.targetUserId ?: return
|
||||
|
||||
handler.post {
|
||||
removeChatsByUserId(targetUserId)
|
||||
}
|
||||
}
|
||||
|
||||
LiveRoomChatRawMessageType.DONATION -> {
|
||||
handler.post {
|
||||
chatAdapter.items.add(
|
||||
@@ -2149,6 +2362,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||
handler.post {
|
||||
chatAdapter.items.add(
|
||||
LiveRoomRouletteDonationChat(
|
||||
memberId = memberId.toLong(),
|
||||
profileUrl = profileUrl,
|
||||
nickname = nickname,
|
||||
rouletteResult = message.message
|
||||
@@ -3789,6 +4003,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||
handler.post {
|
||||
chatAdapter.items.add(
|
||||
LiveRoomRouletteDonationChat(
|
||||
memberId = SharedPreferenceManager.userId,
|
||||
profileUrl = SharedPreferenceManager.profileImage,
|
||||
nickname = SharedPreferenceManager.nickname,
|
||||
rouletteResult = randomItem
|
||||
|
||||
@@ -39,7 +39,8 @@ abstract class LiveRoomChat {
|
||||
abstract fun bind(
|
||||
context: Context,
|
||||
binding: ViewBinding,
|
||||
onClickProfile: ((Long) -> Unit)? = null
|
||||
onClickProfile: ((Long) -> Unit)? = null,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)? = null
|
||||
)
|
||||
}
|
||||
|
||||
@@ -48,7 +49,12 @@ data class LiveRoomJoinChat(
|
||||
val nickname: String
|
||||
) : LiveRoomChat() {
|
||||
override var type = LiveRoomChatType.JOIN
|
||||
override fun bind(context: Context, binding: ViewBinding, onClickProfile: ((Long) -> Unit)?) {
|
||||
override fun bind(
|
||||
context: Context,
|
||||
binding: ViewBinding,
|
||||
onClickProfile: ((Long) -> Unit)?,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)?
|
||||
) {
|
||||
(binding as ItemLiveRoomJoinChatBinding).tvJoin.setTextColor(
|
||||
ContextCompat.getColor(context, R.color.color_eeeeee)
|
||||
)
|
||||
@@ -88,7 +94,12 @@ data class LiveRoomSystemNoticeChat(
|
||||
val message: String
|
||||
) : LiveRoomChat() {
|
||||
override var type = LiveRoomChatType.JOIN
|
||||
override fun bind(context: Context, binding: ViewBinding, onClickProfile: ((Long) -> Unit)?) {
|
||||
override fun bind(
|
||||
context: Context,
|
||||
binding: ViewBinding,
|
||||
onClickProfile: ((Long) -> Unit)?,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)?
|
||||
) {
|
||||
val itemBinding = binding as ItemLiveRoomJoinChatBinding
|
||||
itemBinding.tvJoin.setTextColor(
|
||||
ContextCompat.getColor(context, R.color.color_eeeeee)
|
||||
@@ -104,9 +115,15 @@ data class LiveRoomNormalChat(
|
||||
@SerializedName("profileUrl") val profileUrl: String,
|
||||
@SerializedName("nickname") val nickname: String,
|
||||
@SerializedName("rank") val rank: Int,
|
||||
@SerializedName("chat") val chat: String
|
||||
@SerializedName("chat") val chat: String,
|
||||
@SerializedName("chatId") val chatId: String = ""
|
||||
) : LiveRoomChat() {
|
||||
override fun bind(context: Context, binding: ViewBinding, onClickProfile: ((Long) -> Unit)?) {
|
||||
override fun bind(
|
||||
context: Context,
|
||||
binding: ViewBinding,
|
||||
onClickProfile: ((Long) -> Unit)?,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)?
|
||||
) {
|
||||
val itemBinding = binding as ItemLiveRoomChatBinding
|
||||
itemBinding.ivProfile.load(profileUrl) {
|
||||
crossfade(true)
|
||||
@@ -222,6 +239,16 @@ data class LiveRoomNormalChat(
|
||||
} else {
|
||||
itemBinding.llMessageBg.setBackgroundResource(R.drawable.bg_round_corner_3_3_99000000)
|
||||
}
|
||||
|
||||
itemBinding.root.setOnLongClickListener {
|
||||
if (onLongClickChat != null) {
|
||||
onLongClickChat(this@LiveRoomNormalChat)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
itemBinding.ivCan.visibility = View.GONE
|
||||
itemBinding.tvDonationMessage.visibility = View.GONE
|
||||
itemBinding.root.setBackgroundResource(0)
|
||||
@@ -239,7 +266,12 @@ data class LiveRoomDonationChat(
|
||||
@SerializedName("donationMessage") val donationMessage: String,
|
||||
val isSecret: Boolean = false
|
||||
) : LiveRoomChat() {
|
||||
override fun bind(context: Context, binding: ViewBinding, onClickProfile: ((Long) -> Unit)?) {
|
||||
override fun bind(
|
||||
context: Context,
|
||||
binding: ViewBinding,
|
||||
onClickProfile: ((Long) -> Unit)?,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)?
|
||||
) {
|
||||
val itemBinding = binding as ItemLiveRoomChatBinding
|
||||
val defaultProfileSize = 33.3f.dpToPx().toInt()
|
||||
val defaultCrownSize = 16.7f.dpToPx().toInt()
|
||||
@@ -324,6 +356,7 @@ data class LiveRoomDonationChat(
|
||||
|
||||
itemBinding.llMessageBg.setPadding(0)
|
||||
itemBinding.llMessageBg.background = null
|
||||
itemBinding.root.setOnLongClickListener(null)
|
||||
|
||||
if (isSecret) {
|
||||
itemBinding.root.setBackgroundResource(R.drawable.bg_round_corner_6_7_cc59548f)
|
||||
@@ -366,11 +399,17 @@ data class LiveRoomDonationChat(
|
||||
|
||||
@Keep
|
||||
data class LiveRoomRouletteDonationChat(
|
||||
@SerializedName("memberId") val memberId: Long,
|
||||
@SerializedName("profileUrl") val profileUrl: String,
|
||||
@SerializedName("nickname") val nickname: String,
|
||||
@SerializedName("rouletteResult") val rouletteResult: String
|
||||
) : LiveRoomChat() {
|
||||
override fun bind(context: Context, binding: ViewBinding, onClickProfile: ((Long) -> Unit)?) {
|
||||
override fun bind(
|
||||
context: Context,
|
||||
binding: ViewBinding,
|
||||
onClickProfile: ((Long) -> Unit)?,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)?
|
||||
) {
|
||||
val itemBinding = binding as ItemLiveRoomChatBinding
|
||||
val defaultProfileSize = 33.3f.dpToPx().toInt()
|
||||
val defaultCrownSize = 16.7f.dpToPx().toInt()
|
||||
@@ -433,6 +472,7 @@ data class LiveRoomRouletteDonationChat(
|
||||
|
||||
itemBinding.llMessageBg.setPadding(0)
|
||||
itemBinding.llMessageBg.background = null
|
||||
itemBinding.root.setOnLongClickListener(null)
|
||||
|
||||
itemBinding.root.setBackgroundResource(R.drawable.bg_round_corner_6_7_ccc25264)
|
||||
itemBinding.root.setPadding(33)
|
||||
|
||||
@@ -10,7 +10,8 @@ import kr.co.vividnext.sodalive.databinding.ItemLiveRoomDonationStatusChatBindin
|
||||
import kr.co.vividnext.sodalive.databinding.ItemLiveRoomJoinChatBinding
|
||||
|
||||
class LiveRoomChatAdapter(
|
||||
private val onClickProfile: (Long) -> Unit
|
||||
private val onClickProfile: (Long) -> Unit,
|
||||
private val onLongClickNormalChat: ((LiveRoomNormalChat) -> Unit)? = null
|
||||
) : RecyclerView.Adapter<LiveRoomChatViewHolder>() {
|
||||
|
||||
val items = mutableListOf<LiveRoomChat>()
|
||||
@@ -53,7 +54,7 @@ class LiveRoomChatAdapter(
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: LiveRoomChatViewHolder, position: Int) {
|
||||
holder.bind(items[position], onClickProfile)
|
||||
holder.bind(items[position], onClickProfile, onLongClickNormalChat)
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.count()
|
||||
@@ -65,7 +66,11 @@ class LiveRoomChatAdapter(
|
||||
|
||||
abstract class LiveRoomChatViewHolder(binding: ViewBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
abstract fun bind(chat: LiveRoomChat, onClickProfile: ((Long) -> Unit)? = null)
|
||||
abstract fun bind(
|
||||
chat: LiveRoomChat,
|
||||
onClickProfile: ((Long) -> Unit)? = null,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)? = null
|
||||
)
|
||||
}
|
||||
|
||||
class LiveRoomNormalChatViewHolder(
|
||||
@@ -74,8 +79,9 @@ class LiveRoomNormalChatViewHolder(
|
||||
) : LiveRoomChatViewHolder(binding) {
|
||||
override fun bind(
|
||||
chat: LiveRoomChat,
|
||||
onClickProfile: ((Long) -> Unit)?
|
||||
) = chat.bind(context, binding, onClickProfile)
|
||||
onClickProfile: ((Long) -> Unit)?,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)?
|
||||
) = chat.bind(context, binding, onClickProfile, onLongClickChat)
|
||||
}
|
||||
|
||||
class LiveRoomDonationStatusChatViewHolder(
|
||||
@@ -84,7 +90,8 @@ class LiveRoomDonationStatusChatViewHolder(
|
||||
) : LiveRoomChatViewHolder(binding) {
|
||||
override fun bind(
|
||||
chat: LiveRoomChat,
|
||||
onClickProfile: ((Long) -> Unit)?
|
||||
onClickProfile: ((Long) -> Unit)?,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)?
|
||||
) = chat.bind(context, binding)
|
||||
}
|
||||
|
||||
@@ -94,6 +101,7 @@ class LiveRoomJoinChatViewHolder(
|
||||
) : LiveRoomChatViewHolder(binding) {
|
||||
override fun bind(
|
||||
chat: LiveRoomChat,
|
||||
onClickProfile: ((Long) -> Unit)?
|
||||
onClickProfile: ((Long) -> Unit)?,
|
||||
onLongClickChat: ((LiveRoomNormalChat) -> Unit)?
|
||||
) = chat.bind(context, binding)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ data class LiveRoomChatRawMessage(
|
||||
@SerializedName("signatureImageUrl") val signatureImageUrl: String? = null,
|
||||
@SerializedName("donationMessage") val donationMessage: String?,
|
||||
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean? = null,
|
||||
@SerializedName("isChatFrozen") val isChatFrozen: Boolean? = null
|
||||
@SerializedName("isChatFrozen") val isChatFrozen: Boolean? = null,
|
||||
@SerializedName("chatId") val chatId: String? = null,
|
||||
@SerializedName("targetUserId") val targetUserId: Long? = null
|
||||
)
|
||||
|
||||
enum class LiveRoomChatRawMessageType {
|
||||
@@ -35,6 +37,15 @@ enum class LiveRoomChatRawMessageType {
|
||||
@SerializedName("TOGGLE_CHAT_FREEZE")
|
||||
TOGGLE_CHAT_FREEZE,
|
||||
|
||||
@SerializedName("NORMAL_CHAT")
|
||||
NORMAL_CHAT,
|
||||
|
||||
@SerializedName("DELETE_CHAT")
|
||||
DELETE_CHAT,
|
||||
|
||||
@SerializedName("DELETE_CHAT_BY_USER")
|
||||
DELETE_CHAT_BY_USER,
|
||||
|
||||
@SerializedName("ROULETTE_DONATION")
|
||||
ROULETTE_DONATION,
|
||||
|
||||
|
||||
@@ -467,6 +467,8 @@
|
||||
<string name="screen_live_room_chat_freeze_warning">Chat is frozen. You cannot type right now.</string>
|
||||
<string name="screen_live_room_chat_freeze_started">Chat has been frozen.</string>
|
||||
<string name="screen_live_room_chat_freeze_ended">Chat freeze has been disabled.</string>
|
||||
<string name="screen_live_room_chat_delete_title">Delete chat</string>
|
||||
<string name="screen_live_room_chat_delete_message_format">%1$s: %2$s</string>
|
||||
<string name="screen_live_room_signature_off_label">Sign OFF</string>
|
||||
<string name="screen_live_room_v2v_signature_off_label">Caption OFF</string>
|
||||
<string name="screen_live_room_v2v_signature_on_label">Caption ON</string>
|
||||
|
||||
@@ -466,6 +466,8 @@
|
||||
<string name="screen_live_room_chat_freeze_warning">チャットが凍結中のため入力できません。</string>
|
||||
<string name="screen_live_room_chat_freeze_started">チャットを凍結しました。</string>
|
||||
<string name="screen_live_room_chat_freeze_ended">チャット凍結を解除しました。</string>
|
||||
<string name="screen_live_room_chat_delete_title">チャット削除</string>
|
||||
<string name="screen_live_room_chat_delete_message_format">%1$s: %2$s</string>
|
||||
<string name="screen_live_room_signature_off_label">シグ OFF</string>
|
||||
<string name="screen_live_room_v2v_signature_off_label">字幕 OFF</string>
|
||||
<string name="screen_live_room_v2v_signature_on_label">字幕 ON</string>
|
||||
|
||||
@@ -466,6 +466,8 @@
|
||||
<string name="screen_live_room_chat_freeze_warning">채팅창이 얼려져 있어 입력할 수 없습니다.</string>
|
||||
<string name="screen_live_room_chat_freeze_started">채팅창을 얼렸습니다.</string>
|
||||
<string name="screen_live_room_chat_freeze_ended">채팅창 얼리기를 해제했습니다</string>
|
||||
<string name="screen_live_room_chat_delete_title">채팅 삭제</string>
|
||||
<string name="screen_live_room_chat_delete_message_format">%1$s: %2$s</string>
|
||||
<string name="screen_live_room_signature_off_label">시그 OFF</string>
|
||||
<string name="screen_live_room_v2v_signature_off_label">자막 OFF</string>
|
||||
<string name="screen_live_room_v2v_signature_on_label">자막 ON</string>
|
||||
|
||||
Reference in New Issue
Block a user