룰렛 변경
- 확률 수동 설정 - 여러개의 룰렛이 켜져있을 때 선택하여 돌리기 - 후원 히스토리에 룰렛 히스토리 추가
This commit is contained in:
parent
9df08cdf24
commit
85ccc18485
|
@ -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 {
|
||||
|
|
|
@ -728,7 +728,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(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<ActivityLiveRoomBinding>(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<ActivityLiveRoomBinding>(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<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
RouletteSpinDialog(
|
||||
activity = this@LiveRoomActivity,
|
||||
items = items,
|
||||
selectedItem = randomlySelectedItem,
|
||||
selectedItem = randomItem,
|
||||
layoutInflater = layoutInflater
|
||||
) {
|
||||
agora.sendRawMessageToGroup(
|
||||
|
@ -1358,7 +1360,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
LiveRoomRouletteDonationChat(
|
||||
profileUrl = SharedPreferenceManager.profileImage,
|
||||
nickname = SharedPreferenceManager.nickname,
|
||||
rouletteResult = randomlySelectedItem
|
||||
rouletteResult = randomItem
|
||||
)
|
||||
)
|
||||
invalidateChat()
|
||||
|
|
|
@ -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<RoulettePreview>) -> 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<RouletteItem>, String) -> Unit) {
|
||||
fun spinRoulette(
|
||||
roomId: Long,
|
||||
rouletteId: Long,
|
||||
complete: (Int, List<RouletteItem>, 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<RouletteItem>,
|
||||
complete: (Int, List<RouletteItem>, String) -> Unit
|
||||
) {
|
||||
_isLoading.value = true
|
||||
|
||||
val rouletteItems = mutableListOf<String>()
|
||||
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<RouletteItem>): List<RoulettePreviewItem> {
|
||||
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()
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
||||
|
|
|
@ -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<RouletteItem>
|
||||
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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<RoulettePreviewItem>
|
||||
)
|
||||
|
|
|
@ -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<RoulettePreview>,
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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<RouletteItem>
|
||||
)
|
|
@ -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<ApiResponse<Any>>
|
||||
|
||||
@PUT("/new-roulette")
|
||||
@PUT("/v2/roulette")
|
||||
fun updateRoulette(
|
||||
@Body request: UpdateRouletteRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@GET("/new-roulette/creator")
|
||||
@GET("/v2/roulette/creator")
|
||||
fun getAllRoulette(
|
||||
@Query("creatorId") creatorId: Long,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<List<GetNewRouletteResponse>>>
|
||||
|
||||
@GET("/new-roulette")
|
||||
@GET("/v2/roulette")
|
||||
fun getRoulette(
|
||||
@Query("creatorId") creatorId: Long,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<GetRouletteResponse>>
|
||||
): Single<ApiResponse<List<GetRouletteResponse>>>
|
||||
|
||||
@POST("/new-roulette/spin")
|
||||
@POST("/v2/roulette/spin")
|
||||
fun spinRoulette(
|
||||
@Body request: SpinRouletteRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<GetRouletteResponse>>
|
||||
): Single<ApiResponse<SpinRouletteResponse>>
|
||||
|
||||
@POST("/new-roulette/refund/{id}")
|
||||
@POST("/v2/roulette/refund/{id}")
|
||||
fun refundRouletteDonation(
|
||||
@Path("id") id: Long,
|
||||
@Header("Authorization") authHeader: String
|
||||
|
|
|
@ -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 = "")
|
||||
|
|
|
@ -156,7 +156,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
viewModel.roulettePreviewLiveData.observe(viewLifecycleOwner) {
|
||||
RoulettePreviewDialog(
|
||||
activity = requireActivity(),
|
||||
preview = it,
|
||||
previewList = listOf(it),
|
||||
title = "룰렛 미리보기",
|
||||
layoutInflater = layoutInflater
|
||||
).show()
|
||||
|
@ -176,7 +176,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
}
|
||||
|
||||
private fun addOption() {
|
||||
val newOption = RouletteOption("", 1)
|
||||
val newOption = RouletteOption("", "")
|
||||
viewModel.addOption(newOption)
|
||||
}
|
||||
|
||||
|
@ -199,16 +199,17 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
|
||||
val etOption = optionView.findViewById<EditText>(R.id.et_option)
|
||||
val tvOptionTitle = optionView.findViewById<TextView>(R.id.tv_option_title)
|
||||
val tvPercentage = optionView.findViewById<TextView>(R.id.tv_option_percentage)
|
||||
val ivMinus = optionView.findViewById<ImageView>(R.id.iv_minus)
|
||||
val ivPlus = optionView.findViewById<ImageView>(R.id.iv_plus)
|
||||
val etPercentage = optionView.findViewById<EditText>(R.id.et_option_percentage)
|
||||
val tvDelete = optionView.findViewById<TextView>(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<FragmentRouletteSettingsBinding>(
|
|||
}
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
etPercentage.textChanges().skip(1)
|
||||
.debounce(100, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.inputOptionPercentage(index, it.toString())
|
||||
}
|
||||
)
|
||||
|
||||
return optionView
|
||||
}
|
||||
|
||||
|
|
|
@ -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<GetNewRouletteResponse>()
|
||||
|
||||
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<RouletteOption>) {
|
||||
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<RoulettePreviewItem>()
|
||||
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<RouletteItem>()
|
||||
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<RouletteItem>()
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 996 B |
Binary file not shown.
After Width: | Height: | Size: 418 B |
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_ff14d9" />
|
||||
<corners android:radius="10dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_ff14d9" />
|
||||
</shape>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_ffcb14" />
|
||||
<corners android:radius="10dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_ffcb14" />
|
||||
</shape>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<corners android:radius="10dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_ff14d9" />
|
||||
</shape>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<corners android:radius="10dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_ffcb14" />
|
||||
</shape>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_ccc25264" />
|
||||
<corners android:radius="5.3dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_ccc25264" />
|
||||
</shape>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_ff14d9" />
|
||||
<corners android:radius="6.7dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_ff14d9" />
|
||||
</shape>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_ffcb14" />
|
||||
<corners android:radius="6.7dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_ffcb14" />
|
||||
</shape>
|
|
@ -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" />
|
||||
|
|
|
@ -9,6 +9,101 @@
|
|||
android:orientation="vertical"
|
||||
android:padding="13.3dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_select_roulette"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_select_roulette_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="14.3dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_select_roulette_1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6.7dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_select_check"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_select_roulette_1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="룰렛 1"
|
||||
android:textColor="@color/color_3bb9f1"
|
||||
android:textSize="14.7sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_select_roulette_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="13.3dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="14.3dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_select_roulette_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6.7dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_select_check_black"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_select_roulette_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="룰렛 2"
|
||||
android:textColor="@color/color_ffcb14"
|
||||
android:textSize="14.7sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_select_roulette_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="13.3dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="14.3dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_select_roulette_3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6.7dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_select_check"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_select_roulette_3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="룰렛 3"
|
||||
android:textColor="@color/color_ff14d9"
|
||||
android:textSize="14.7sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -60,33 +60,39 @@
|
|||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_option_percentage"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@drawable/bg_round_corner_6_7_222222"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:gravity="center"
|
||||
android:minWidth="60dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="16.7dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="14.7sp"
|
||||
tools:text="50%" />
|
||||
android:paddingVertical="16.7dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_minus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/btn_minus_round_rect" />
|
||||
<EditText
|
||||
android:id="@+id/et_option_percentage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:hint="0.00"
|
||||
android:importantForAutofill="no"
|
||||
android:lines="1"
|
||||
android:maxLength="5"
|
||||
android:inputType="numberDecimal|numberSigned"
|
||||
android:text=""
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_eeeeee"
|
||||
android:textSize="14.7sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_plus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/btn_plus_round_rect" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="%"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="14.7sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
<color name="color_d85e37">#D85E37</color>
|
||||
<color name="color_d38c38">#D38C38</color>
|
||||
<color name="color_59548f">#59548F</color>
|
||||
<color name="color_ffcb14">#FFCB14</color>
|
||||
<color name="color_4d6aa4">#4D6AA4</color>
|
||||
<color name="color_2d7390">#2D7390</color>
|
||||
<color name="color_548f7d">#548F7D</color>
|
||||
|
@ -118,4 +119,5 @@
|
|||
<color name="color_002abd">#002ABD</color>
|
||||
<color name="color_312827">#312827</color>
|
||||
<color name="color_f1291c">#F1291C</color>
|
||||
<color name="color_ff14d9">#FF14D9</color>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue