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 @@ + + + + + + + + + + + + + + + + + + + + +