diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5d851b4..75bbdd2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -125,6 +125,7 @@
+
+ android:stopWithTask="false" />
+ android:foregroundServiceType="mediaPlayback"
+ android:stopWithTask="false" />
(ActivityLiveRoomB
}
}
+ private val rouletteConfigResult = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) { result ->
+ val resultCode = result.resultCode
+ val isActiveRoulette = result.data?.getBooleanExtra(Constants.EXTRA_RESULT_ROULETTE, false)
+
+ if (resultCode == RESULT_OK && isActiveRoulette != null) {
+ // TODO 룰렛 활성화 / 비활성화 설정 리스너에게 알림
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
agora = Agora(
context = this,
@@ -660,6 +672,16 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB
response.creatorId == SharedPreferenceManager.userId &&
SharedPreferenceManager.role == MemberRole.CREATOR.name
) {
+ binding.flRoulette.visibility = View.GONE
+ binding.flRouletteSettings.visibility = View.VISIBLE
+ binding.flRouletteSettings.setOnClickListener {
+ rouletteConfigResult.launch(
+ Intent(
+ applicationContext,
+ RouletteConfigActivity::class.java
+ )
+ )
+ }
binding.flDonationMessageList.visibility = View.VISIBLE
binding.flDonationMessageList.setOnClickListener {
LiveRoomDonationMessageDialog(
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
new file mode 100644
index 0000000..547ad30
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/GetRouletteResponse.kt
@@ -0,0 +1,14 @@
+package kr.co.vividnext.sodalive.live.roulette
+
+import com.google.gson.annotations.SerializedName
+
+data class GetRouletteResponse(
+ @SerializedName("can") val can: Int,
+ @SerializedName("isActive") val isActive: Boolean,
+ @SerializedName("items") val items: List
+)
+
+data class RouletteItem(
+ @SerializedName("title") val title: String,
+ @SerializedName("weight") val weight: Int
+)
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RouletteRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RouletteRepository.kt
new file mode 100644
index 0000000..67aa2ac
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/RouletteRepository.kt
@@ -0,0 +1,19 @@
+package kr.co.vividnext.sodalive.live.roulette
+
+import kr.co.vividnext.sodalive.live.roulette.config.CreateOrUpdateRouletteRequest
+import kr.co.vividnext.sodalive.live.roulette.config.RouletteApi
+
+class RouletteRepository(private val api: RouletteApi) {
+ fun createOrUpdateRoulette(
+ request: CreateOrUpdateRouletteRequest,
+ token: String
+ ) = api.createOrUpdateRoulette(
+ request = request,
+ authHeader = token
+ )
+
+ fun getRoulette(creatorId: Long, token: String) = api.getRoulette(
+ creatorId = creatorId,
+ authHeader = token
+ )
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/CreateOrUpdateRouletteRequest.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/CreateOrUpdateRouletteRequest.kt
new file mode 100644
index 0000000..aced332
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/CreateOrUpdateRouletteRequest.kt
@@ -0,0 +1,10 @@
+package kr.co.vividnext.sodalive.live.roulette.config
+
+import com.google.gson.annotations.SerializedName
+import kr.co.vividnext.sodalive.live.roulette.RouletteItem
+
+data class CreateOrUpdateRouletteRequest(
+ @SerializedName("can") val can: Int,
+ @SerializedName("isActive") val isActive: Boolean,
+ @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
new file mode 100644
index 0000000..f0ac76e
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteApi.kt
@@ -0,0 +1,24 @@
+package kr.co.vividnext.sodalive.live.roulette.config
+
+import io.reactivex.rxjava3.core.Single
+import kr.co.vividnext.sodalive.common.ApiResponse
+import kr.co.vividnext.sodalive.live.roulette.GetRouletteResponse
+import retrofit2.http.Body
+import retrofit2.http.GET
+import retrofit2.http.Header
+import retrofit2.http.POST
+import retrofit2.http.Query
+
+interface RouletteApi {
+ @POST("/roulette")
+ fun createOrUpdateRoulette(
+ @Body request: CreateOrUpdateRouletteRequest,
+ @Header("Authorization") authHeader: String
+ ): Single>
+
+ @GET("/roulette")
+ fun getRoulette(
+ @Query("creatorId") creatorId: Long,
+ @Header("Authorization") authHeader: String
+ ): Single>
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteConfigActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteConfigActivity.kt
new file mode 100644
index 0000000..88a0a13
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteConfigActivity.kt
@@ -0,0 +1,64 @@
+package kr.co.vividnext.sodalive.live.roulette.config
+
+import android.os.Bundle
+import com.google.android.material.tabs.TabLayout
+import kr.co.vividnext.sodalive.R
+import kr.co.vividnext.sodalive.base.BaseActivity
+import kr.co.vividnext.sodalive.databinding.ActivityRouletteConfigBinding
+
+class RouletteConfigActivity : BaseActivity(
+ ActivityRouletteConfigBinding::inflate
+) {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ changeFragment("settings")
+ }
+
+ override fun setupView() {
+ binding.toolbar.tvBack.text = "룰렛설정"
+ binding.toolbar.tvBack.setOnClickListener { finish() }
+
+ val tabs = binding.tabs
+ tabs.addTab(tabs.newTab().setText("룰렛설정").setTag("settings"))
+ tabs.addTab(tabs.newTab().setText("당첨내역").setTag("winning-details"))
+ tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
+ override fun onTabSelected(tab: TabLayout.Tab) {
+ val tag = tab.tag as String
+ changeFragment(tag)
+ }
+
+ override fun onTabUnselected(tab: TabLayout.Tab) {
+ }
+
+ override fun onTabReselected(tab: TabLayout.Tab) {
+ }
+ })
+ }
+
+ private fun changeFragment(tag: String) {
+ val fragmentManager = supportFragmentManager
+ val fragmentTransaction = fragmentManager.beginTransaction()
+
+ val currentFragment = fragmentManager.primaryNavigationFragment
+ if (currentFragment != null) {
+ fragmentTransaction.hide(currentFragment)
+ }
+
+ var fragment = fragmentManager.findFragmentByTag(tag)
+ if (fragment == null) {
+ fragment = if (tag == "settings") {
+ RouletteSettingsFragment()
+ } else {
+ RouletteWinningDetailsFragment()
+ }
+
+ fragmentTransaction.add(R.id.container, fragment, tag)
+ } else {
+ fragmentTransaction.show(fragment)
+ }
+
+ fragmentTransaction.setPrimaryNavigationFragment(fragment)
+ fragmentTransaction.setReorderingAllowed(true)
+ fragmentTransaction.commitNow()
+ }
+}
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
new file mode 100644
index 0000000..4e89fec
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteOption.kt
@@ -0,0 +1,3 @@
+package kr.co.vividnext.sodalive.live.roulette.config
+
+data class RouletteOption(var title: String, var weight: Int, var percentage: Int = 50)
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
new file mode 100644
index 0000000..f1f0e2d
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsFragment.kt
@@ -0,0 +1,163 @@
+package kr.co.vividnext.sodalive.live.roulette.config
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.app.Service
+import android.content.Intent
+import android.os.Bundle
+import android.text.InputFilter
+import android.view.LayoutInflater
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.TextView
+import com.jakewharton.rxbinding4.widget.textChanges
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.schedulers.Schedulers
+import kr.co.vividnext.sodalive.R
+import kr.co.vividnext.sodalive.base.BaseFragment
+import kr.co.vividnext.sodalive.common.Constants
+import kr.co.vividnext.sodalive.common.LoadingDialog
+import kr.co.vividnext.sodalive.databinding.FragmentRouletteSettingsBinding
+import org.koin.android.ext.android.inject
+import java.util.concurrent.TimeUnit
+
+class RouletteSettingsFragment : BaseFragment(
+ FragmentRouletteSettingsBinding::inflate
+) {
+ private val viewModel: RouletteSettingsViewModel by inject()
+
+ private lateinit var imm: InputMethodManager
+ private lateinit var loadingDialog: LoadingDialog
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setupView()
+ bindData()
+ viewModel.getRoulette()
+ }
+
+ private fun setupView() {
+ loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
+ imm = requireActivity().getSystemService(
+ Service.INPUT_METHOD_SERVICE
+ ) as InputMethodManager
+
+ binding.etSetPrice.filters = arrayOf(InputFilter { source, start, end, _, _, _ ->
+ // Only allow numeric input
+ for (i in start until end) {
+ if (!Character.isDigit(source[i])) {
+ return@InputFilter ""
+ }
+ }
+ null
+ })
+
+ binding.ivRouletteIsActive.setOnClickListener { viewModel.toggleIsActive() }
+ binding.ivAddOption.setOnClickListener { addOption() }
+
+ binding.tvPreview.setOnClickListener {
+
+ }
+
+ binding.tvSave.setOnClickListener { _ ->
+ imm.hideSoftInputFromWindow(view?.windowToken, 0)
+ viewModel.createOrUpdateRoulette {
+ val resultIntent = Intent().apply { putExtra(Constants.EXTRA_RESULT_ROULETTE, it) }
+ requireActivity().setResult(Activity.RESULT_OK, resultIntent)
+ requireActivity().finish()
+ }
+ }
+ }
+
+ private fun bindData() {
+ viewModel.isActiveLiveData.observe(viewLifecycleOwner) {
+ binding.ivRouletteIsActive.setImageResource(
+ if (it) R.drawable.btn_toggle_on_big else R.drawable.btn_toggle_off_big
+ )
+ }
+
+ viewModel.optionsLiveData.observe(viewLifecycleOwner) { updateOptionUi(it) }
+
+ viewModel.toastLiveData.observe(viewLifecycleOwner) { it?.let { showToast(it) } }
+
+ viewModel.canLiveData.observe(viewLifecycleOwner) { binding.etSetPrice.setText("$it") }
+
+ viewModel.isLoading.observe(viewLifecycleOwner) {
+ if (it) {
+ loadingDialog.show(screenWidth)
+ } else {
+ loadingDialog.dismiss()
+ }
+ }
+
+ compositeDisposable.add(
+ binding.etSetPrice.textChanges().skip(1)
+ .debounce(100, TimeUnit.MILLISECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribe {
+ if (it.trim().isNotEmpty()) {
+ viewModel.can = it.toString().toInt()
+ }
+ }
+ )
+ }
+
+ private fun addOption() {
+ val newOption = RouletteOption("", 1)
+ viewModel.addOption(newOption)
+ }
+
+ private fun updateOptionUi(options: List) {
+ binding.llRouletteOptionContainer.removeAllViews()
+ options.forEachIndexed { index, option ->
+ binding.llRouletteOptionContainer.addView(createOptionView(index, option))
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun createOptionView(index: Int, option: RouletteOption): View {
+ val optionView = LayoutInflater
+ .from(context)
+ .inflate(
+ R.layout.layout_roulette_option,
+ binding.llRouletteOptionContainer,
+ false
+ )
+
+ 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 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 (index == 0 || index == 1) {
+ tvDelete.visibility = View.GONE
+ } else {
+ tvDelete.visibility = View.VISIBLE
+ tvDelete.setOnClickListener { viewModel.deleteOption(index) }
+ }
+
+ compositeDisposable.add(
+ etOption.textChanges().skip(1)
+ .debounce(100, TimeUnit.MILLISECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribe {
+ viewModel.inputOption(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
new file mode 100644
index 0000000..eaf9ede
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteSettingsViewModel.kt
@@ -0,0 +1,201 @@
+package kr.co.vividnext.sodalive.live.roulette.config
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.orhanobut.logger.Logger
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.schedulers.Schedulers
+import kr.co.vividnext.sodalive.base.BaseViewModel
+import kr.co.vividnext.sodalive.common.SharedPreferenceManager
+import kr.co.vividnext.sodalive.live.roulette.RouletteItem
+import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
+
+class RouletteSettingsViewModel(private val repository: RouletteRepository) : BaseViewModel() {
+
+ private var _isLoading = MutableLiveData(false)
+ val isLoading: LiveData
+ get() = _isLoading
+
+ private val _toastLiveData = MutableLiveData()
+ val toastLiveData: LiveData
+ get() = _toastLiveData
+
+ private val _optionsLiveData = MutableLiveData>(listOf())
+ val optionsLiveData: LiveData>
+ get() = _optionsLiveData
+
+ private val _isActiveLiveData = MutableLiveData(false)
+ val isActiveLiveData: LiveData
+ get() = _isActiveLiveData
+
+ private val _canLiveData = MutableLiveData(5)
+ val canLiveData: LiveData
+ get() = _canLiveData
+
+ private val options = mutableListOf()
+ var can = 5
+ var isActive = false
+
+ 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 >= 6) return
+
+ options.add(newOption)
+ recalculatePercentages(options)
+ }
+
+ fun deleteOption(index: Int) {
+ val updatedOptions = options.filterIndexed { currentIndex, _ -> currentIndex != index }
+ removeAllAndAddOptions(updatedOptions)
+ recalculatePercentages(updatedOptions)
+ }
+
+ fun inputOption(optionIndex: Int, title: String) {
+ val currentOption = options[optionIndex]
+ options[optionIndex] = currentOption.copy(title = title)
+ }
+
+ private fun recalculatePercentages(options: List) {
+ val totalWeight = options.sumOf { it.weight }
+ val updatedOptions = options.asSequence().map { option ->
+ option.copy(percentage = (option.weight.toDouble() / totalWeight * 100).toInt())
+ }.toList()
+ _optionsLiveData.value = updatedOptions
+ }
+
+ fun toggleIsActive() {
+ isActive = !isActive
+ _isActiveLiveData.postValue(isActive)
+ }
+
+ fun createOrUpdateRoulette(onSuccess: (Boolean) -> Unit) {
+ if (!_isLoading.value!!) {
+ _isLoading.value = true
+
+ 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))
+ }
+
+ val request = CreateOrUpdateRouletteRequest(
+ can = can,
+ isActive = isActive,
+ items = items
+ )
+
+ compositeDisposable.add(
+ repository.createOrUpdateRoulette(
+ request = request,
+ token = "Bearer ${SharedPreferenceManager.token}"
+ )
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ {
+ _isLoading.value = false
+ if (it.success && it.data != null && it.data is Boolean) {
+ _toastLiveData.postValue("룰렛이 설정되었습니다.")
+ onSuccess(it.data)
+ } else {
+ if (it.message != null) {
+ _toastLiveData.postValue(it.message)
+ } else {
+ _toastLiveData.postValue(
+ "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+ )
+ }
+ }
+ },
+ {
+ _isLoading.value = false
+ it.message?.let { message -> Logger.e(message) }
+ _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
+ }
+ )
+ )
+ }
+ }
+
+ fun getRoulette() {
+ if (!_isLoading.value!!) {
+ _isLoading.value = true
+ compositeDisposable.add(
+ repository.getRoulette(
+ creatorId = SharedPreferenceManager.userId,
+ token = "Bearer ${SharedPreferenceManager.token}"
+ )
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ {
+ if (it.success) {
+ val data = it.data
+
+ if (data != null && data.items.isNotEmpty()) {
+ _isActiveLiveData.value = data.isActive
+ _canLiveData.value = data.can
+
+ isActive = data.isActive
+ can = data.can
+
+ val options = data.items.asSequence().map { item ->
+ RouletteOption(title = item.title, weight = item.weight)
+ }.toList()
+ removeAllAndAddOptions(options = options)
+ recalculatePercentages(options)
+ } else {
+ _isActiveLiveData.value = false
+ _canLiveData.value = 5
+
+ isActive = false
+ can = 5
+
+ options.add(RouletteOption(title = "", weight = 1))
+ options.add(RouletteOption(title = "", weight = 1))
+ recalculatePercentages(options)
+ }
+ } else {
+ if (it.message != null) {
+ _toastLiveData.postValue(it.message)
+ } else {
+ _toastLiveData.postValue(
+ "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+ )
+ }
+ }
+ _isLoading.value = false
+ },
+ {
+ _isLoading.value = false
+ it.message?.let { message -> Logger.e(message) }
+ _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
+ }
+ )
+ )
+ }
+ }
+
+ private fun removeAllAndAddOptions(options: List) {
+ this.options.clear()
+ this.options.addAll(options)
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteWinningDetailsFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteWinningDetailsFragment.kt
new file mode 100644
index 0000000..d826b32
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/live/roulette/config/RouletteWinningDetailsFragment.kt
@@ -0,0 +1,19 @@
+package kr.co.vividnext.sodalive.live.roulette.config
+
+import android.os.Bundle
+import android.view.View
+import kr.co.vividnext.sodalive.base.BaseFragment
+import kr.co.vividnext.sodalive.databinding.FragmentRouletteWinningDetailsBinding
+
+class RouletteWinningDetailsFragment : BaseFragment(
+ FragmentRouletteWinningDetailsBinding::inflate
+) {
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setupView()
+ }
+
+ private fun setupView() {
+ }
+}
diff --git a/app/src/main/res/drawable-xxhdpi/btn_add.png b/app/src/main/res/drawable-xxhdpi/btn_add.png
new file mode 100644
index 0000000..b36e9b5
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/btn_add.png differ
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
new file mode 100644
index 0000000..ae6a88e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/btn_minus_round_rect.png differ
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
new file mode 100644
index 0000000..a22155e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/btn_plus_round_rect.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_roulette.png b/app/src/main/res/drawable-xxhdpi/ic_roulette.png
new file mode 100644
index 0000000..1ab555e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_roulette.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_roulette_settings.png b/app/src/main/res/drawable-xxhdpi/ic_roulette_settings.png
new file mode 100644
index 0000000..8d10a95
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_roulette_settings.png differ
diff --git a/app/src/main/res/drawable/bg_round_corner_10_3bb9f1.xml b/app/src/main/res/drawable/bg_round_corner_10_3bb9f1.xml
new file mode 100644
index 0000000..099aa25
--- /dev/null
+++ b/app/src/main/res/drawable/bg_round_corner_10_3bb9f1.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bg_round_corner_10_transparent_3bb9f1.xml b/app/src/main/res/drawable/bg_round_corner_10_transparent_3bb9f1.xml
new file mode 100644
index 0000000..83f3219
--- /dev/null
+++ b/app/src/main/res/drawable/bg_round_corner_10_transparent_3bb9f1.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bg_round_corner_8_ff5c49.xml b/app/src/main/res/drawable/bg_round_corner_8_ff5c49.xml
new file mode 100644
index 0000000..ed5ce37
--- /dev/null
+++ b/app/src/main/res/drawable/bg_round_corner_8_ff5c49.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_live_room.xml b/app/src/main/res/layout/activity_live_room.xml
index d4bd5a2..6620e76 100644
--- a/app/src/main/res/layout/activity_live_room.xml
+++ b/app/src/main/res/layout/activity_live_room.xml
@@ -250,12 +250,12 @@
android:id="@+id/ll_view_users"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
android:background="@drawable/bg_round_corner_15_transparent_bbbbbb"
android:orientation="horizontal"
android:paddingHorizontal="11dp"
- android:visibility="gone"
android:paddingVertical="7dp"
- android:layout_marginStart="8dp"
+ android:visibility="gone"
tools:ignore="RelativeOverlap">
+
+
+
+
+
+
+
+
+
+
@@ -412,12 +446,12 @@
android:layout_height="wrap_content"
android:layout_marginBottom="13.3dp"
android:background="@drawable/bg_round_corner_10_99525252"
- android:padding="11.7dp">
+ android:padding="10dp">
@@ -429,11 +463,11 @@
android:layout_height="wrap_content"
android:layout_marginBottom="13.3dp"
android:background="@drawable/bg_round_corner_10_99525252"
- android:padding="11.7dp">
+ android:padding="10dp">
@@ -445,13 +479,13 @@
android:layout_height="wrap_content"
android:layout_marginBottom="13.3dp"
android:background="@drawable/bg_round_corner_10_99525252"
- android:padding="11.7dp"
+ android:padding="10dp"
android:visibility="gone">
diff --git a/app/src/main/res/layout/activity_roulette_config.xml b/app/src/main/res/layout/activity_roulette_config.xml
new file mode 100644
index 0000000..03d60d3
--- /dev/null
+++ b/app/src/main/res/layout/activity_roulette_config.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_roulette_settings.xml b/app/src/main/res/layout/fragment_roulette_settings.xml
new file mode 100644
index 0000000..75f1c6b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_roulette_settings.xml
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_roulette_winning_details.xml b/app/src/main/res/layout/fragment_roulette_winning_details.xml
new file mode 100644
index 0000000..1354408
--- /dev/null
+++ b/app/src/main/res/layout/fragment_roulette_winning_details.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/app/src/main/res/layout/layout_roulette_option.xml b/app/src/main/res/layout/layout_roulette_option.xml
new file mode 100644
index 0000000..12835fa
--- /dev/null
+++ b/app/src/main/res/layout/layout_roulette_option.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+