From 85ccc18485482c66e8219217dd87273d954ae498 Mon Sep 17 00:00:00 2001 From: klaus Date: Fri, 10 May 2024 17:43:26 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A3=B0=EB=A0=9B=20=EB=B3=80=EA=B2=BD=20-=20?= =?UTF-8?q?=ED=99=95=EB=A5=A0=20=EC=88=98=EB=8F=99=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?-=20=EC=97=AC=EB=9F=AC=EA=B0=9C=EC=9D=98=20=EB=A3=B0=EB=A0=9B?= =?UTF-8?q?=EC=9D=B4=20=EC=BC=9C=EC=A0=B8=EC=9E=88=EC=9D=84=20=EB=95=8C=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=ED=95=98=EC=97=AC=20=EB=8F=8C=EB=A6=AC?= =?UTF-8?q?=EA=B8=B0=20-=20=ED=9B=84=EC=9B=90=20=ED=9E=88=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=EC=97=90=20=EB=A3=B0=EB=A0=9B=20=ED=9E=88?= =?UTF-8?q?=EC=8A=A4=ED=86=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 +- .../sodalive/live/room/LiveRoomActivity.kt | 18 +- .../sodalive/live/room/LiveRoomViewModel.kt | 70 +++---- .../LiveRoomDonationMessageAdapter.kt | 14 +- .../live/roulette/GetRouletteResponse.kt | 3 +- .../sodalive/live/roulette/RoulettePreview.kt | 1 + .../live/roulette/RoulettePreviewDialog.kt | 195 +++++++++++++++++- .../sodalive/live/roulette/RouletteView.kt | 11 +- .../live/roulette/SpinRouletteRequest.kt | 1 + .../live/roulette/SpinRouletteResponse.kt | 9 + .../live/roulette/config/RouletteApi.kt | 17 +- .../live/roulette/config/RouletteOption.kt | 2 +- .../config/RouletteSettingsFragment.kt | 27 ++- .../config/RouletteSettingsViewModel.kt | 124 +++++------ .../drawable-xxhdpi/btn_minus_round_rect.png | Bin 2438 -> 0 bytes .../drawable-xxhdpi/btn_plus_round_rect.png | Bin 2874 -> 0 bytes .../ic_donation_message_list.png | Bin 3606 -> 996 bytes .../drawable-xxhdpi/ic_select_check_black.png | Bin 0 -> 418 bytes .../drawable/bg_round_corner_10_ff14d9.xml | 8 + .../drawable/bg_round_corner_10_ffcb14.xml | 8 + .../bg_round_corner_10_transparent_ff14d9.xml | 8 + .../bg_round_corner_10_transparent_ffcb14.xml | 8 + .../drawable/bg_round_corner_5_3_ccc25264.xml | 8 + .../drawable/bg_round_corner_6_7_ff14d9.xml | 8 + .../drawable/bg_round_corner_6_7_ffcb14.xml | 8 + .../dialog_live_room_donation_message.xml | 4 +- .../res/layout/dialog_roulette_preview.xml | 95 +++++++++ .../res/layout/layout_roulette_option.xml | 48 +++-- app/src/main/res/values/colors.xml | 2 + 29 files changed, 519 insertions(+), 182 deletions(-) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/live/roulette/SpinRouletteResponse.kt delete mode 100644 app/src/main/res/drawable-xxhdpi/btn_minus_round_rect.png delete mode 100644 app/src/main/res/drawable-xxhdpi/btn_plus_round_rect.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_select_check_black.png create mode 100644 app/src/main/res/drawable/bg_round_corner_10_ff14d9.xml create mode 100644 app/src/main/res/drawable/bg_round_corner_10_ffcb14.xml create mode 100644 app/src/main/res/drawable/bg_round_corner_10_transparent_ff14d9.xml create mode 100644 app/src/main/res/drawable/bg_round_corner_10_transparent_ffcb14.xml create mode 100644 app/src/main/res/drawable/bg_round_corner_5_3_ccc25264.xml create mode 100644 app/src/main/res/drawable/bg_round_corner_6_7_ff14d9.xml create mode 100644 app/src/main/res/drawable/bg_round_corner_6_7_ffcb14.xml diff --git a/app/build.gradle b/app/build.gradle index f355a1b..5aa88dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { applicationId "kr.co.vividnext.sodalive" minSdk 23 targetSdk 33 - versionCode 68 - versionName "1.10.4" + versionCode 69 + versionName "1.11.0" } buildTypes { diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt index 28d7d67..04db47b 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt @@ -728,7 +728,7 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB copyMessage = { val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager clipboard.setPrimaryClip(ClipData.newPlainText(it, it)) - showToast("후원 메시지가 복사되었습니다.") + showToast("후원 히스토리가 복사되었습니다.") } ).show() } @@ -950,8 +950,10 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB viewModel.showRoulette { RoulettePreviewDialog( activity = this, - preview = it, - onClickSpin = { spinRoulette() }, + previewList = it, + onClickSpin = { rouletteId -> + spinRoulette(rouletteId = rouletteId) + }, layoutInflater = layoutInflater ).show() } @@ -1333,12 +1335,12 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB } } - private fun spinRoulette() { - viewModel.spinRoulette(roomId = roomId) { can, items, randomlySelectedItem -> + private fun spinRoulette(rouletteId: Long) { + viewModel.spinRoulette(roomId = roomId, rouletteId = rouletteId) { can, items, randomItem -> val rouletteRawMessage = Gson().toJson( LiveRoomChatRawMessage( type = LiveRoomChatRawMessageType.ROULETTE_DONATION, - message = randomlySelectedItem, + message = randomItem, can = can, donationMessage = "", ) @@ -1347,7 +1349,7 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB RouletteSpinDialog( activity = this@LiveRoomActivity, items = items, - selectedItem = randomlySelectedItem, + selectedItem = randomItem, layoutInflater = layoutInflater ) { agora.sendRawMessageToGroup( @@ -1358,7 +1360,7 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB LiveRoomRouletteDonationChat( profileUrl = SharedPreferenceManager.profileImage, nickname = SharedPreferenceManager.nickname, - rouletteResult = randomlySelectedItem + rouletteResult = randomItem ) ) invalidateChat() diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomViewModel.kt index c1a4368..4be39f7 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomViewModel.kt @@ -3,12 +3,6 @@ package kr.co.vividnext.sodalive.live.room import android.net.Uri import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.google.firebase.dynamiclinks.ShortDynamicLink -import com.google.firebase.dynamiclinks.ktx.androidParameters -import com.google.firebase.dynamiclinks.ktx.dynamicLinks -import com.google.firebase.dynamiclinks.ktx.iosParameters -import com.google.firebase.dynamiclinks.ktx.shortLinkAsync -import com.google.firebase.ktx.Firebase import com.google.gson.Gson import com.orhanobut.logger.Logger import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers @@ -36,7 +30,7 @@ import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody import java.io.File -import kotlin.math.floor +import java.util.Locale class LiveRoomViewModel( private val repository: LiveRepository, @@ -480,7 +474,12 @@ class LiveRoomViewModel( ) } - fun donation(roomId: Long, can: Int, message: String, onSuccess: (LiveRoomDonationResponse?) -> Unit) { + fun donation( + roomId: Long, + can: Int, + message: String, + onSuccess: (LiveRoomDonationResponse?) -> Unit + ) { _isLoading.postValue(true) compositeDisposable.add( repository.donation(roomId, can, message, "Bearer ${SharedPreferenceManager.token}") @@ -780,7 +779,7 @@ class LiveRoomViewModel( ) } - fun showRoulette(complete: (RoulettePreview) -> Unit) { + fun showRoulette(complete: (List) -> Unit) { if (!_isLoading.value!!) { _isLoading.value = true compositeDisposable.add( @@ -797,15 +796,19 @@ class LiveRoomViewModel( val data = it.data if ( it.success && - data != null && - data.isActive && - data.items.isNotEmpty() + !data.isNullOrEmpty() ) { complete( - RoulettePreview( - data.can, - items = calculatePercentages(data.items) - ) + data + .filter { roulette -> roulette.isActive } + .filter { roulette -> roulette.items.isNotEmpty() } + .map { roulette -> + RoulettePreview( + id = roulette.id, + can = roulette.can, + items = calculatePercentages(roulette.items) + ) + } ) } else { val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요." @@ -822,12 +825,16 @@ class LiveRoomViewModel( } } - fun spinRoulette(roomId: Long, complete: (Int, List, String) -> Unit) { + fun spinRoulette( + roomId: Long, + rouletteId: Long, + complete: (Int, List, String) -> Unit + ) { if (!_isLoading.value!!) { _isLoading.value = true compositeDisposable.add( rouletteRepository.spinRoulette( - request = SpinRouletteRequest(roomId = roomId), + request = SpinRouletteRequest(roomId = roomId, rouletteId = rouletteId), token = "Bearer ${SharedPreferenceManager.token}" ) .subscribeOn(Schedulers.io()) @@ -840,11 +847,10 @@ class LiveRoomViewModel( if ( it.success && data != null && - data.isActive && data.items.isNotEmpty() ) { SharedPreferenceManager.can -= data.can - randomSelectRouletteItem(data.can, data.items, complete) + complete(data.can, data.items, data.result) } else { val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요." _toastLiveData.postValue(message) @@ -933,31 +939,11 @@ class LiveRoomViewModel( ) } - private fun randomSelectRouletteItem( - can: Int, - items: List, - complete: (Int, List, String) -> Unit - ) { - _isLoading.value = true - - val rouletteItems = mutableListOf() - items.asSequence().forEach { item -> - repeat(item.weight * 10) { - rouletteItems.add(item.title) - } - } - - _isLoading.value = false - complete(can, items, rouletteItems.random()) - } - private fun calculatePercentages(options: List): List { - val totalWeight = options.sumOf { it.weight } - val updatedOptions = options.asSequence().map { option -> - val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100 + val updatedOptions = options.map { option -> RoulettePreviewItem( title = option.title, - percent = "${String.format("%.2f", percent)}%" + percent = "${String.format(Locale.KOREAN, "%.2f", option.percentage)}%" ) }.toList() diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/donation/LiveRoomDonationMessageAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/donation/LiveRoomDonationMessageAdapter.kt index 96e69ca..fe66fc6 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/room/donation/LiveRoomDonationMessageAdapter.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/donation/LiveRoomDonationMessageAdapter.kt @@ -2,9 +2,11 @@ package kr.co.vividnext.sodalive.live.room.donation import android.annotation.SuppressLint import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView +import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.databinding.ItemLiveRoomDonationMessageBinding class LiveRoomDonationMessageAdapter( @@ -20,8 +22,16 @@ class LiveRoomDonationMessageAdapter( @SuppressLint("SetTextI18n") fun bind(item: LiveRoomDonationMessage) { - binding.tvNickname.text = "${item.nickname}님이" - binding.tvCanMessage.text = item.canMessage + if (item.canMessage.isNotBlank()) { + binding.tvNickname.text = "${item.nickname}님이" + binding.tvCanMessage.text = item.canMessage + binding.tvCanMessage.visibility = View.VISIBLE + binding.root.setBackgroundResource(R.drawable.bg_round_corner_5_3_333333) + } else { + binding.tvNickname.text = "${item.nickname}님의 룰렛 결과?" + binding.tvCanMessage.visibility = View.GONE + binding.root.setBackgroundResource(R.drawable.bg_round_corner_5_3_ccc25264) + } binding.tvDonationMessage.text = "\"${item.donationMessage}\"" binding.ivDelete.setOnClickListener { onClickDeleteMessage(item.uuid) } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/GetRouletteResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/GetRouletteResponse.kt index 547ad30..29ee794 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/GetRouletteResponse.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/GetRouletteResponse.kt @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.live.roulette import com.google.gson.annotations.SerializedName data class GetRouletteResponse( + @SerializedName("id") val id: Long, @SerializedName("can") val can: Int, @SerializedName("isActive") val isActive: Boolean, @SerializedName("items") val items: List @@ -10,5 +11,5 @@ data class GetRouletteResponse( data class RouletteItem( @SerializedName("title") val title: String, - @SerializedName("weight") val weight: Int + @SerializedName("percentage") val percentage: Float ) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RoulettePreview.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RoulettePreview.kt index e6ed0c8..a5c5a4c 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RoulettePreview.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RoulettePreview.kt @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.live.roulette import com.google.gson.annotations.SerializedName data class RoulettePreview( + @SerializedName("id") val id: Long, @SerializedName("can") val can: Int, @SerializedName("items") val items: List ) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RoulettePreviewDialog.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RoulettePreviewDialog.kt index 6960cdd..6d410d3 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RoulettePreviewDialog.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RoulettePreviewDialog.kt @@ -8,27 +8,36 @@ import android.view.LayoutInflater import android.view.View import android.view.Window import android.view.WindowManager +import android.widget.ImageView +import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AlertDialog +import androidx.core.content.ContextCompat import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.MutableLiveData import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.databinding.DialogRoulettePreviewBinding import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.moneyFormat +import kr.co.vividnext.sodalive.live.roulette.config.RouletteSettingsViewModel.SelectedRoulette import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity class RoulettePreviewDialog( private val activity: FragmentActivity, - private val preview: RoulettePreview, + private val previewList: List, private val title: String = "", - private val onClickSpin: (() -> Unit)? = null, + private val onClickSpin: ((Long) -> Unit)? = null, layoutInflater: LayoutInflater ) { private val alertDialog: AlertDialog private val dialogView = DialogRoulettePreviewBinding.inflate(layoutInflater) + private val selectedRouletteLiveData = MutableLiveData( + SelectedRoulette.ROULETTE_1 + ) + init { val dialogBuilder = AlertDialog.Builder(activity) dialogBuilder.setView(dialogView.root) @@ -54,18 +63,189 @@ class RoulettePreviewDialog( @SuppressLint("SetTextI18n") private fun setupView() { - dialogView.tvCancel.setOnClickListener { alertDialog.dismiss() } + if (previewList.isEmpty()) { + alertDialog.dismiss() + } else { + initSelectRouletteButton() + setRouletteData(previewList[0]) + } - dialogView.tvSpinRoulette.text = "${preview.can}캔으로 룰렛 돌리기" + dialogView.tvCancel.setOnClickListener { alertDialog.dismiss() } + } + + private fun initSelectRouletteButton() { + if (previewList.size < 2) { + dialogView.llSelectRoulette.visibility = View.GONE + } else { + dialogView.llSelectRoulette.visibility = View.VISIBLE + + if (previewList.size > 2) { + dialogView.llSelectRoulette3.visibility = View.VISIBLE + } else { + dialogView.llSelectRoulette3.visibility = View.GONE + } + } + + dialogView.llSelectRoulette1.setOnClickListener { + if (selectedRouletteLiveData.value != SelectedRoulette.ROULETTE_1) { + selectedRouletteLiveData.value = SelectedRoulette.ROULETTE_1 + } + } + + dialogView.llSelectRoulette2.setOnClickListener { + if (selectedRouletteLiveData.value != SelectedRoulette.ROULETTE_2) { + selectedRouletteLiveData.value = SelectedRoulette.ROULETTE_2 + } + } + + dialogView.llSelectRoulette3.setOnClickListener { + if (selectedRouletteLiveData.value != SelectedRoulette.ROULETTE_3) { + selectedRouletteLiveData.value = SelectedRoulette.ROULETTE_3 + } + } + + selectedRouletteLiveData.observe(activity) { + deselectAllRoulette() + when (it) { + SelectedRoulette.ROULETTE_2 -> { + selectRouletteButton( + dialogView.ivSelectRoulette2, + dialogView.llSelectRoulette2, + dialogView.tvSelectRoulette2 + ) + setRouletteData(previewList[1]) + dialogView.tvCancel.setTextColor( + ContextCompat.getColor(activity, R.color.color_ffcb14) + ) + dialogView.tvCancel.setBackgroundResource( + R.drawable.bg_round_corner_10_transparent_ffcb14 + ) + } + + SelectedRoulette.ROULETTE_3 -> { + selectRouletteButton( + dialogView.ivSelectRoulette3, + dialogView.llSelectRoulette3, + dialogView.tvSelectRoulette3 + ) + setRouletteData(previewList[2]) + dialogView.tvCancel.setTextColor( + ContextCompat.getColor(activity, R.color.color_ff14d9) + ) + dialogView.tvCancel.setBackgroundResource( + R.drawable.bg_round_corner_10_transparent_ff14d9 + ) + } + + else -> { + selectRouletteButton( + dialogView.ivSelectRoulette1, + dialogView.llSelectRoulette1, + dialogView.tvSelectRoulette1 + ) + setRouletteData(previewList[0]) + dialogView.tvCancel.setTextColor( + ContextCompat.getColor(activity, R.color.color_3bb9f1) + ) + dialogView.tvCancel.setBackgroundResource( + R.drawable.bg_round_corner_10_transparent_3bb9f1 + ) + } + } + } + } + + private fun deselectAllRoulette() { + dialogView.ivSelectRoulette1.visibility = View.GONE + dialogView.ivSelectRoulette2.visibility = View.GONE + dialogView.ivSelectRoulette3.visibility = View.GONE + + dialogView.llSelectRoulette1.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b) + dialogView.tvSelectRoulette1.setTextColor( + ContextCompat.getColor( + activity, + R.color.color_3bb9f1 + ) + ) + + dialogView.llSelectRoulette2.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b) + dialogView.tvSelectRoulette2.setTextColor( + ContextCompat.getColor( + activity, + R.color.color_ffcb14 + ) + ) + + dialogView.llSelectRoulette3.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b) + dialogView.tvSelectRoulette3.setTextColor( + ContextCompat.getColor( + activity, + R.color.color_ff14d9 + ) + ) + } + + private fun selectRouletteButton( + ivSelectRoulette: ImageView, + llSelectRoulette: LinearLayout, + tvSelectRoulette: TextView + ) { + ivSelectRoulette.visibility = View.VISIBLE + llSelectRoulette.setBackgroundResource( + when (selectedRouletteLiveData.value) { + SelectedRoulette.ROULETTE_2 -> R.drawable.bg_round_corner_6_7_ffcb14 + SelectedRoulette.ROULETTE_3 -> R.drawable.bg_round_corner_6_7_ff14d9 + else -> R.drawable.bg_round_corner_6_7_3bb9f1 + } + ) + tvSelectRoulette.setTextColor( + ContextCompat.getColor( + activity, + when (selectedRouletteLiveData.value) { + SelectedRoulette.ROULETTE_2 -> R.color.black + else -> R.color.color_eeeeee + } + + ) + ) + } + + @SuppressLint("SetTextI18n") + private fun setRouletteData(roulettePreview: RoulettePreview) { + dialogView.tvSpinRoulette.text = "${roulettePreview.can}캔으로 룰렛 돌리기" dialogView.tvSpinRoulette.setOnClickListener { if (onClickSpin != null) { - onClickSpin!!() + onClickSpin!!(roulettePreview.id) } alertDialog.dismiss() } - dialogView.tvTitle.text = title.ifBlank { "룰렛" } + dialogView.tvSpinRoulette.setTextColor( + ContextCompat.getColor( + activity, + when (selectedRouletteLiveData.value) { + SelectedRoulette.ROULETTE_2 -> R.color.black + else -> R.color.white + } + ) + ) + dialogView.tvSpinRoulette.setBackgroundResource( + when (selectedRouletteLiveData.value) { + SelectedRoulette.ROULETTE_2 -> R.drawable.bg_round_corner_10_ffcb14 + SelectedRoulette.ROULETTE_3 -> R.drawable.bg_round_corner_10_ff14d9 + else -> R.drawable.bg_round_corner_10_3bb9f1 + } + ) + + dialogView.tvTitle.text = title.ifBlank { + when (selectedRouletteLiveData.value) { + SelectedRoulette.ROULETTE_2 -> "룰렛 2" + SelectedRoulette.ROULETTE_3 -> "룰렛 3" + else -> "룰렛 1" + } + } + if (onClickSpin != null) { dialogView.tvCan.visibility = View.VISIBLE dialogView.tvCan.text = SharedPreferenceManager.can.moneyFormat() @@ -80,7 +260,8 @@ class RoulettePreviewDialog( dialogView.tvCan.visibility = View.GONE } - preview.items.forEachIndexed { index, item -> + dialogView.llRouletteOptionContainer.removeAllViews() + roulettePreview.items.forEachIndexed { index, item -> dialogView.llRouletteOptionContainer.addView(createOptionView(index, item)) } } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RouletteView.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RouletteView.kt index b2f7c5b..11a78ec 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RouletteView.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RouletteView.kt @@ -74,12 +74,10 @@ class RouletteView @JvmOverloads constructor( override fun onDraw(canvas: Canvas) { super.onDraw(canvas) - val totalWeight = items.asSequence().map { it.weight }.sum() var startAngle = -90f - val shuffledColors = colors.shuffled() - items.forEachIndexed { index, (option, weight) -> - val sweepAngle = (weight / totalWeight.toFloat()) * 360f + items.forEachIndexed { index, (option, percentage) -> + val sweepAngle = (percentage / 100) * 360f fillPaint.color = shuffledColors[index] canvas.drawArc(rect, startAngle, sweepAngle, true, fillPaint) @@ -117,11 +115,10 @@ class RouletteView @JvmOverloads constructor( } private fun getAngleForOption(option: String): Float { - val totalWeight = items.asSequence().map { it.weight }.sum() var startAngle = 0f - items.forEach { (currentOption, weight) -> - val sweepAngle = (weight / totalWeight.toFloat()) * 360f + items.forEach { (currentOption, percentage) -> + val sweepAngle = (percentage / 100) * 360f if (currentOption == option) { // Return the midpoint angle of the segment return (startAngle + sweepAngle / 2) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/SpinRouletteRequest.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/SpinRouletteRequest.kt index 4a48804..aea81c8 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/SpinRouletteRequest.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/SpinRouletteRequest.kt @@ -4,5 +4,6 @@ import com.google.gson.annotations.SerializedName data class SpinRouletteRequest( @SerializedName("roomId") val roomId: Long, + @SerializedName("rouletteId") val rouletteId: Long, @SerializedName("container") val container: String = "aos" ) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/SpinRouletteResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/SpinRouletteResponse.kt new file mode 100644 index 0000000..fc40bad --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/SpinRouletteResponse.kt @@ -0,0 +1,9 @@ +package kr.co.vividnext.sodalive.live.roulette + +import com.google.gson.annotations.SerializedName + +data class SpinRouletteResponse( + @SerializedName("can") val can: Int, + @SerializedName("result") val result: String, + @SerializedName("items") val items: List +) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteApi.kt index 80d2078..fc6d86b 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteApi.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteApi.kt @@ -5,6 +5,7 @@ import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.live.roulette.GetNewRouletteResponse import kr.co.vividnext.sodalive.live.roulette.GetRouletteResponse import kr.co.vividnext.sodalive.live.roulette.SpinRouletteRequest +import kr.co.vividnext.sodalive.live.roulette.SpinRouletteResponse import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header @@ -14,37 +15,37 @@ import retrofit2.http.Path import retrofit2.http.Query interface RouletteApi { - @POST("/new-roulette") + @POST("/v2/roulette") fun createRoulette( @Body request: CreateRouletteRequest, @Header("Authorization") authHeader: String ): Single> - @PUT("/new-roulette") + @PUT("/v2/roulette") fun updateRoulette( @Body request: UpdateRouletteRequest, @Header("Authorization") authHeader: String ): Single> - @GET("/new-roulette/creator") + @GET("/v2/roulette/creator") fun getAllRoulette( @Query("creatorId") creatorId: Long, @Header("Authorization") authHeader: String ): Single>> - @GET("/new-roulette") + @GET("/v2/roulette") fun getRoulette( @Query("creatorId") creatorId: Long, @Header("Authorization") authHeader: String - ): Single> + ): Single>> - @POST("/new-roulette/spin") + @POST("/v2/roulette/spin") fun spinRoulette( @Body request: SpinRouletteRequest, @Header("Authorization") authHeader: String - ): Single> + ): Single> - @POST("/new-roulette/refund/{id}") + @POST("/v2/roulette/refund/{id}") fun refundRouletteDonation( @Path("id") id: Long, @Header("Authorization") authHeader: String diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteOption.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteOption.kt index 9c4059a..1086f69 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteOption.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteOption.kt @@ -1,3 +1,3 @@ package kr.co.vividnext.sodalive.live.roulette.config -data class RouletteOption(var title: String, var weight: Int, var percentage: String = "50.00") +data class RouletteOption(var title: String, var percentage: String = "") diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsFragment.kt index ecdc7bb..16c240b 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsFragment.kt @@ -156,7 +156,7 @@ class RouletteSettingsFragment : BaseFragment( viewModel.roulettePreviewLiveData.observe(viewLifecycleOwner) { RoulettePreviewDialog( activity = requireActivity(), - preview = it, + previewList = listOf(it), title = "룰렛 미리보기", layoutInflater = layoutInflater ).show() @@ -176,7 +176,7 @@ class RouletteSettingsFragment : BaseFragment( } private fun addOption() { - val newOption = RouletteOption("", 1) + val newOption = RouletteOption("", "") viewModel.addOption(newOption) } @@ -199,16 +199,17 @@ class RouletteSettingsFragment : BaseFragment( val etOption = optionView.findViewById(R.id.et_option) val tvOptionTitle = optionView.findViewById(R.id.tv_option_title) - val tvPercentage = optionView.findViewById(R.id.tv_option_percentage) - val ivMinus = optionView.findViewById(R.id.iv_minus) - val ivPlus = optionView.findViewById(R.id.iv_plus) + val etPercentage = optionView.findViewById(R.id.et_option_percentage) val tvDelete = optionView.findViewById(R.id.tv_delete) etOption.setText(option.title) tvOptionTitle.text = "옵션 ${index + 1}" - tvPercentage.text = "${option.percentage}%" - ivMinus.setOnClickListener { viewModel.subtractWeight(index) } - ivPlus.setOnClickListener { viewModel.plusWeight(index) } + + if (option.percentage.toFloat() > 0f) { + etPercentage.setText(option.percentage) + } else { + etPercentage.setText("") + } if (index == 0 || index == 1) { tvDelete.visibility = View.GONE @@ -227,6 +228,16 @@ class RouletteSettingsFragment : BaseFragment( } ) + compositeDisposable.add( + etPercentage.textChanges().skip(1) + .debounce(100, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.io()) + .subscribe { + viewModel.inputOptionPercentage(index, it.toString()) + } + ) + return optionView } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsViewModel.kt index 4eeba6a..93a4d2e 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsViewModel.kt @@ -12,7 +12,6 @@ import kr.co.vividnext.sodalive.live.roulette.RouletteItem import kr.co.vividnext.sodalive.live.roulette.RoulettePreview import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewItem import kr.co.vividnext.sodalive.live.roulette.RouletteRepository -import kotlin.math.floor class RouletteSettingsViewModel(private val repository: RouletteRepository) : BaseViewModel() { @@ -55,31 +54,16 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba val rouletteList = mutableListOf() - fun plusWeight(optionIndex: Int) { - val currentOption = options[optionIndex] - options[optionIndex] = currentOption.copy(weight = currentOption.weight + 1) - recalculatePercentages(options) - } - - fun subtractWeight(optionIndex: Int) { - if (options[optionIndex].weight > 1) { - val currentOption = options[optionIndex] - options[optionIndex] = currentOption.copy(weight = currentOption.weight - 1) - recalculatePercentages(options) - } - } - fun addOption(newOption: RouletteOption) { if (options.size >= 10) return - options.add(newOption) - recalculatePercentages(options) + _optionsLiveData.value = options } fun deleteOption(index: Int) { val updatedOptions = options.filterIndexed { currentIndex, _ -> currentIndex != index } removeAllAndAddOptions(updatedOptions) - recalculatePercentages(updatedOptions) + _optionsLiveData.value = updatedOptions } fun inputOption(optionIndex: Int, title: String) { @@ -87,15 +71,9 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba options[optionIndex] = currentOption.copy(title = title) } - private fun recalculatePercentages(options: List) { - val totalWeight = options.sumOf { it.weight } - val updatedOptions = options.asSequence().map { option -> - val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100 - option.copy(percentage = String.format("%.2f", percent)) - }.toList() - - removeAllAndAddOptions(updatedOptions) - _optionsLiveData.value = updatedOptions + fun inputOptionPercentage(optionIndex: Int, percentage: String) { + val currentOption = options[optionIndex] + options[optionIndex] = currentOption.copy(percentage = percentage) } fun toggleIsActive() { @@ -107,17 +85,20 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba _isLoading.value = true val items = mutableListOf() - for (option in options) { - if (option.title.trim().isEmpty()) { - _toastLiveData.value = "옵션은 빈칸을 할 수 없습니다." - _isLoading.value = false - return + if (validationOptions()) { + for (option in options) { + if (option.title.trim().isEmpty()) { + _toastLiveData.value = "옵션은 빈칸을 할 수 없습니다." + _isLoading.value = false + return + } + + items.add(RoulettePreviewItem(option.title, "${option.percentage}%")) } - items.add(RoulettePreviewItem(option.title, "${option.percentage}%")) + _roulettePreviewLiveData.postValue(RoulettePreview(0, can, items)) } - _roulettePreviewLiveData.postValue(RoulettePreview(can, items)) _isLoading.value = false } @@ -125,24 +106,41 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba if (!_isLoading.value!!) { _isLoading.value = true - if (rouletteId > 0) { - updateRoulette(onSuccess) - } else { - createRoulette(onSuccess) + if (validationOptions()) { + if (rouletteId > 0) { + updateRoulette(onSuccess) + } else { + createRoulette(onSuccess) + } } } } + private fun validationOptions(): Boolean { + var totalPercentage = 0f + for (option in options) { + if (option.title.trim().isEmpty()) { + _toastLiveData.value = "옵션은 빈칸을 할 수 없습니다." + _isLoading.value = false + return false + } + + totalPercentage += option.percentage.toFloat() + } + + if (totalPercentage != 100.0f) { + _toastLiveData.value = "확률이 100%가 아닙니다" + _isLoading.value = false + return false + } + + return true + } + private fun updateRoulette(onSuccess: (Boolean) -> Unit) { val items = mutableListOf() for (option in options) { - if (option.title.trim().isEmpty()) { - _toastLiveData.value = "옵션은 빈칸을 할 수 없습니다." - _isLoading.value = false - return - } - - items.add(RouletteItem(title = option.title, weight = option.weight)) + items.add(RouletteItem(title = option.title, percentage = option.percentage.toFloat())) } val selectedRoulette = rouletteList[_selectedRouletteLiveData.value!!.ordinal] @@ -169,24 +167,10 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba SelectedRoulette.ROULETTE_3 -> "룰렛 3" } - var isAllActive = false - - rouletteList - .filter { - it.id != selectedRoulette.id - } - .forEach { - if (it.isActive) { - isAllActive = true - } - } - val successMessage = if (isActive) { - "${selectedRouletteTitle}로 설정하였습니다." - } else if (!isAllActive) { - "${selectedRouletteTitle}이 비활성화 되었습니다." + "${selectedRouletteTitle}을 활성화 했습니다." } else { - "${selectedRouletteTitle}을 설정했습니다." + "${selectedRouletteTitle}을 비활성화 했습니다." } compositeDisposable.add( @@ -224,13 +208,7 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba private fun createRoulette(onSuccess: (Boolean) -> Unit) { val items = mutableListOf() for (option in options) { - if (option.title.trim().isEmpty()) { - _toastLiveData.value = "옵션은 빈칸을 할 수 없습니다." - _isLoading.value = false - return - } - - items.add(RouletteItem(title = option.title, weight = option.weight)) + items.add(RouletteItem(title = option.title, percentage = option.percentage.toFloat())) } val request = CreateRouletteRequest( @@ -348,10 +326,10 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba isActive = roulette.isActive val options = roulette.items.asSequence().map { item -> - RouletteOption(title = item.title, weight = item.weight) + RouletteOption(title = item.title, percentage = item.percentage.toString()) }.toList() removeAllAndAddOptions(options = options) - recalculatePercentages(options) + _optionsLiveData.value = options } else { _canLiveData.value = 0 _isActiveLiveData.value = false @@ -361,9 +339,9 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba isActive = false options.clear() - options.add(RouletteOption(title = "", weight = 1)) - options.add(RouletteOption(title = "", weight = 1)) - recalculatePercentages(options) + options.add(RouletteOption(title = "", percentage = "50.00")) + options.add(RouletteOption(title = "", percentage = "50.00")) + _optionsLiveData.value = options } } } diff --git a/app/src/main/res/drawable-xxhdpi/btn_minus_round_rect.png b/app/src/main/res/drawable-xxhdpi/btn_minus_round_rect.png deleted file mode 100644 index ae6a88e2742f1e865ea57bc318cef43ca38bb04d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2438 zcmb7G`9Bkm8=uL2tuf?Il24bTXvo;iRm?dohVo_Q3Y#NGCR>h3j>d=22TO8Ixe~&J z5IH{1+?3fY9cag>@d^2^vv)q4K@vgwPMKFm)AOkdbUf zdgaiKyC;K`x$Kaw{5%5Pr$zZ-mqSsi3um5!Zzk}kyC&#rI!DP>YAMK`%Fw`$l>f@k z3Ej6$?HZmjnYEU2ata9v2|Hq=o6FXAG@Q?D=3U$iByxE)rE1o@0|-5p;-tfArS8bf zTAfL4;4H83sypcZhqcW%ByA#GNH{r5@6AkYfV%V8WsHp&2rfY;W>6|kT~7L=5qs7Y zUZg4>K#~p|rWNrxA1-nq1pUC*>+C-l#uZf8strpmm{JQFI;;kHozVM_{Ijy7Y#d3 znUIqe_Rq%lau*C*Yjl&{)|{*BP$E*x?aX+=q9>%W-MyQ~v0kf6AYZ;)PWu^M*!aTN z&ev%m?8}Lj&@^-Z)(V$m*;V}7^=C%Zby(?n@SfR5yZRVq-(lvB2iayHMG2*TBSwQ0 zCBy>8ABBigzJv|DFN*$kT^q3g6@VHNr~ZXLGvA5D_J(~k8`Z%b5{D3lrX|8FXP^)V z*fsbp7MO{mQy&|qqx!FCTNRwkESyJ8=jB2Lky`W8kX$3)JN(6K(*$d^T2*0N6(43g zH$wpz4bskED?lV{Z8Pp!6hzhh)2IvR{$D3TI};DyM0m6??5$&x^n0>+5+f zI@yo}XB|R8s~$VUVh-KJa>`TBn)p10Ti{FRmwY1#?HD`Rw@oi817~~PABrLyIlVWA zyfAg0bW}8bn9Y(-AnX+C)6Z+CKSVC0rrq+Ifyl;ICmB#D>&R8(pSUyzeh!d!dHYD5 z?22C5oHAad6pMBJX{4tMDlM{$RwR?Oc)&d%b2Vcns&Fhx>%{*K(xsB__xD`lwd*)bmCF*2q;pA*=MXg7YQfbQ zOy9a^NKYp;ZXU0C+RYC^o{@7z?ul0_zOZ*P_g8#!OGl`#%v8)$KVjg7;{!bHxYJ9yOrRW$3GA?>|_j~MyK0Q(2)|NKWmBM0G= zR&VN%$iKJd+tunYn|_pua(x=zn|1?7TR6BWuyNCq7U34XsDfZNJU~AR^^=R6P^+~n>AdD- zZ|s)R0Mv}m&-J$E4rfIbg?DiV>D}8=;pK;A`0zH(Pd>1d1oDS4P$AJ@ysWft65Gok z5iv6vf)gFFf4#x&PS&ij#h=*i8I;P)cA>PW6=9!+CEpEC4dSPO_g%}4)JyB=%&)KC zj&xA#M4qf&$ZpT|yQiXxlQjs__#-r`OBtpRa@U*<03mpk}EOQPUtg7gU^C#`p7IDrTN5L#1cTe?nBow!@2{2GIDgg3Dj&_#sE)mOKIG76INzb$d0F`# z;FU)3E;fcs8Cx%jt~!rnnN10q#Qy#K`_Jm;+*otI67sM-#P&?2oEOGZdYUlq&f!?> z#|~=I2^rGosblv^w!-@C_`BDi0|%#i_r=QnZ+@9nqrR$>T!vTvA+bvNAaA7dq&SxN z?aTVYt83&Acvd(-b;G}{Jj0}p!Gb$>y>i;8k)s!;I8<=D+RqFXELh0iDnJsJ4 zzy1huqj&y3C%*SiE_bH3jSin9-i4^j$H$}dJ2pa$&JK+P-i93}@PDVf$Uu^}K5j5s zL1(44$>rP?E1V($5o6%kU#%=YA-1f%6w7z!_sQT|;alV~kk03<`6c`}6=&qZ8+=dF zb|EbRZt*l;)XLCVIwd&DevVF$tRBhWl1_WHK^Puv>se9txVH=h>HRQt>Y1&=ph6Aj zKNpsHi_)zPZ)3g+(1m6TYL^AT!p-eV6Q>RqdU#H`+3t*BTx5^cPl)2Qm^BMwxgO1g zCLO{Yb?hK~4=ZsP!)I@qU&IyGVgn1)MTv=nADc z*O*x*s>+)@@QO~Z(dUU%;HB{m!P#^L_2O9)X!oG{SxG{T*27ay1G)ER*LJQX+{zZb U%?eiMyiEWL6BP0_!sF3@0sU->DF6Tf diff --git a/app/src/main/res/drawable-xxhdpi/btn_plus_round_rect.png b/app/src/main/res/drawable-xxhdpi/btn_plus_round_rect.png deleted file mode 100644 index a22155e15cc787c862ac41799a63c67a8745b371..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2874 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 M07*qoM6N<$f}oYNRsaA1 diff --git a/app/src/main/res/drawable-xxhdpi/ic_select_check_black.png b/app/src/main/res/drawable-xxhdpi/ic_select_check_black.png new file mode 100644 index 0000000000000000000000000000000000000000..c9b4901c36875144f7a2ef5e8a8233fbae93703b GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBIde}J$B+ufw>Qt`9&!+9d#LZp=*j8FZuxA6 zP*79;PBmE{cFlvb3Ktnv1DFb)GAv?B2-_g!6ery{{jTgj_gS+qzB2t6d6Gd81Y#ev zmhE}@=S9scol-M{H?isKHd~+LX%|koRJmsM+H?8051!YU-97h3NCiXg|2HpHV-E@( zYuflUSw|w;?wC?hPOC|}p=VC)ID?VZi;CBG3oARp$L<-l1uDY!V?}wOfMJn ze=PMd<6yz2s;?Z6+|qx}6Ft&-t}0kj!faQE?39EVFBWa5F=BT`ce^QWjEmp0GGe{ + + + + + diff --git a/app/src/main/res/drawable/bg_round_corner_10_ffcb14.xml b/app/src/main/res/drawable/bg_round_corner_10_ffcb14.xml new file mode 100644 index 0000000..a79a7e6 --- /dev/null +++ b/app/src/main/res/drawable/bg_round_corner_10_ffcb14.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_round_corner_10_transparent_ff14d9.xml b/app/src/main/res/drawable/bg_round_corner_10_transparent_ff14d9.xml new file mode 100644 index 0000000..21898a3 --- /dev/null +++ b/app/src/main/res/drawable/bg_round_corner_10_transparent_ff14d9.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_round_corner_10_transparent_ffcb14.xml b/app/src/main/res/drawable/bg_round_corner_10_transparent_ffcb14.xml new file mode 100644 index 0000000..f242c18 --- /dev/null +++ b/app/src/main/res/drawable/bg_round_corner_10_transparent_ffcb14.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_round_corner_5_3_ccc25264.xml b/app/src/main/res/drawable/bg_round_corner_5_3_ccc25264.xml new file mode 100644 index 0000000..fececfc --- /dev/null +++ b/app/src/main/res/drawable/bg_round_corner_5_3_ccc25264.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_round_corner_6_7_ff14d9.xml b/app/src/main/res/drawable/bg_round_corner_6_7_ff14d9.xml new file mode 100644 index 0000000..acdac6a --- /dev/null +++ b/app/src/main/res/drawable/bg_round_corner_6_7_ff14d9.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_round_corner_6_7_ffcb14.xml b/app/src/main/res/drawable/bg_round_corner_6_7_ffcb14.xml new file mode 100644 index 0000000..2240c82 --- /dev/null +++ b/app/src/main/res/drawable/bg_round_corner_6_7_ffcb14.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/layout/dialog_live_room_donation_message.xml b/app/src/main/res/layout/dialog_live_room_donation_message.xml index 09ed448..3c85a4b 100644 --- a/app/src/main/res/layout/dialog_live_room_donation_message.xml +++ b/app/src/main/res/layout/dialog_live_room_donation_message.xml @@ -19,7 +19,7 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:fontFamily="@font/gmarket_sans_bold" - android:text="후원메시지" + android:text="후원 히스토리" android:textColor="@color/color_eeeeee" android:textSize="14.7sp" app:layout_constraintStart_toStartOf="parent" @@ -55,7 +55,7 @@ android:layout_marginTop="30dp" android:fontFamily="@font/gmarket_sans_medium" android:gravity="center" - android:text="후원메시지가 없습니다." + android:text="후원 히스토리가 없습니다." android:textColor="@color/color_eeeeee" android:textSize="14.7sp" android:visibility="gone" /> diff --git a/app/src/main/res/layout/dialog_roulette_preview.xml b/app/src/main/res/layout/dialog_roulette_preview.xml index d675b49..1bb295a 100644 --- a/app/src/main/res/layout/dialog_roulette_preview.xml +++ b/app/src/main/res/layout/dialog_roulette_preview.xml @@ -9,6 +9,101 @@ android:orientation="vertical" android:padding="13.3dp"> + + + + + + + + + + + + + + + + + + + + + + + + - + android:paddingVertical="16.7dp"> - + - + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index e683e70..9733802 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -79,6 +79,7 @@ #D85E37 #D38C38 #59548F + #FFCB14 #4D6AA4 #2D7390 #548F7D @@ -118,4 +119,5 @@ #002ABD #312827 #F1291C + #FF14D9