라이브 메뉴 설정 페이지 추가

This commit is contained in:
klaus 2024-10-08 15:51:19 +09:00
parent 38e4122570
commit 8cee9fb019
12 changed files with 521 additions and 22 deletions

View File

@ -143,7 +143,7 @@
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
<activity android:name=".audio_content.all.by_theme.AudioContentAllByThemeActivity" />
<activity android:name=".live.roulette.config.RouletteConfigActivity" />
<activity android:name=".live.menu.MenuConfigActivity" />
<activity android:name=".live.room.menu.MenuConfigActivity" />
<activity android:name=".audio_content.series.SeriesListAllActivity" />
<activity android:name=".audio_content.series.detail.SeriesDetailActivity" />
<activity android:name=".audio_content.series.content.SeriesContentAllActivity" />

View File

@ -59,6 +59,8 @@ import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailViewModel
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewModel
import kr.co.vividnext.sodalive.live.room.menu.MenuApi
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigRepository
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigViewModel
import kr.co.vividnext.sodalive.live.room.tag.LiveTagRepository
import kr.co.vividnext.sodalive.live.room.tag.LiveTagViewModel
import kr.co.vividnext.sodalive.live.room.update.LiveRoomEditViewModel
@ -260,6 +262,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { AlarmListViewModel(get()) }
viewModel { BlockMemberViewModel(get()) }
viewModel { UserViewModel(get(), get()) }
viewModel { MenuConfigViewModel(get()) }
}
private val repositoryModule = module {
@ -287,6 +290,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
factory { RouletteRepository(get()) }
factory { CreatorCommunityRepository(get()) }
factory { AlarmListRepository(get()) }
factory { MenuConfigRepository(get()) }
}
private val moduleList = listOf(

View File

@ -52,7 +52,7 @@ import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.loadUrl
import kr.co.vividnext.sodalive.extensions.moneyFormat
import kr.co.vividnext.sodalive.live.LiveViewModel
import kr.co.vividnext.sodalive.live.menu.MenuConfigActivity
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigActivity
import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationCompleteActivity
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog

View File

@ -1,11 +0,0 @@
package kr.co.vividnext.sodalive.live.menu
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.databinding.ActivityMenuConfigBinding
class MenuConfigActivity : BaseActivity<ActivityMenuConfigBinding>(
ActivityMenuConfigBinding::inflate
) {
override fun setupView() {
}
}

View File

@ -6,6 +6,6 @@ import com.google.gson.annotations.SerializedName
@Keep
data class GetMenuPresetResponse(
@SerializedName("id") val id: Long,
@SerializedName("menu") val menu: String,
@SerializedName("menu") var menu: String,
@SerializedName("isActive") val isActive: Boolean
)

View File

@ -2,8 +2,10 @@ package kr.co.vividnext.sodalive.live.room.menu
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.common.ApiResponse
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.Query
interface MenuApi {
@ -12,4 +14,10 @@ interface MenuApi {
@Query("creatorId") creatorId: Long,
@Header("Authorization") authHeader: String
): Single<ApiResponse<List<GetMenuPresetResponse>>>
@POST("/live/room/menu")
fun saveMenu(
@Body request: UpdateLiveMenuRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<Any>>
}

View File

@ -0,0 +1,186 @@
package kr.co.vividnext.sodalive.live.room.menu
import android.app.Service
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
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.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityMenuConfigBinding
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
import org.koin.android.ext.android.inject
import java.util.concurrent.TimeUnit
class MenuConfigActivity : BaseActivity<ActivityMenuConfigBinding>(
ActivityMenuConfigBinding::inflate
) {
private val viewModel: MenuConfigViewModel by inject()
private lateinit var imm: InputMethodManager
private lateinit var loadingDialog: LoadingDialog
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindData()
viewModel.getAllMenuPreset()
}
override fun setupView() {
binding.toolbar.tvBack.text = "메뉴 설정"
binding.toolbar.tvBack.setOnClickListener { finish() }
loadingDialog = LoadingDialog(this, layoutInflater)
imm = getSystemService(
Service.INPUT_METHOD_SERVICE
) as InputMethodManager
binding.tvSave.setOnClickListener {
handler.postDelayed({
imm.hideSoftInputFromWindow(currentFocus?.windowToken, 0)
}, 100)
// 저장 액션
viewModel.saveMenu()
}
binding.llSelectMenu1.setOnClickListener {
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_1)
}
binding.llSelectMenu2.setOnClickListener {
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_2)
}
binding.llSelectMenu3.setOnClickListener {
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_3)
}
}
private fun bindData() {
viewModel.toastLiveData.observe(this) { it?.let { showToast(it) } }
viewModel.isLoading.observe(this) {
if (it) {
loadingDialog.show(screenWidth)
} else {
loadingDialog.dismiss()
}
}
viewModel.selectedMenuLiveData.observe(this) {
deselectAllMenuPreset()
when (it) {
LiveRoomCreateViewModel.SelectedMenu.MENU_2 -> selectMenuPresetButton(
binding.ivSelectMenu2,
binding.llSelectMenu2,
binding.tvSelectMenu2
)
LiveRoomCreateViewModel.SelectedMenu.MENU_3 -> selectMenuPresetButton(
binding.ivSelectMenu3,
binding.llSelectMenu3,
binding.tvSelectMenu3
)
else -> selectMenuPresetButton(
binding.ivSelectMenu1,
binding.llSelectMenu1,
binding.tvSelectMenu1
)
}
}
viewModel.selectedMenuTextLiveData.observe(this) {
binding.etMenu.setText(it)
}
compositeDisposable.add(
binding.etMenu.textChanges().skip(1)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe {
viewModel.menuText = it.toString()
}
)
}
private fun deselectAllMenuPreset() {
binding.ivSelectMenu1.visibility = View.GONE
binding.ivSelectMenu2.visibility = View.GONE
binding.ivSelectMenu3.visibility = View.GONE
binding.llSelectMenu1.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectMenu1.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_3bb9f1
)
)
if (viewModel.countMenu() > 0) {
binding.llSelectMenu2.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectMenu2.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_3bb9f1
)
)
} else {
binding.llSelectMenu2.setBackgroundResource(R.drawable.bg_round_corner_6_7_777777)
binding.tvSelectMenu2.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_555555
)
)
}
if (viewModel.countMenu() > 1) {
binding.llSelectMenu3.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectMenu3.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_3bb9f1
)
)
} else {
binding.llSelectMenu3.setBackgroundResource(R.drawable.bg_round_corner_6_7_777777)
binding.tvSelectMenu3.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_555555
)
)
}
}
private fun selectMenuPresetButton(
ivSelectMenuPreset: ImageView,
llSelectMenuPreset: LinearLayout,
tvSelectMenuPreset: TextView
) {
ivSelectMenuPreset.visibility = View.VISIBLE
llSelectMenuPreset.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
tvSelectMenuPreset.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_eeeeee
)
)
}
}

View File

@ -0,0 +1,17 @@
package kr.co.vividnext.sodalive.live.room.menu
class MenuConfigRepository(private val api: MenuApi) {
fun getAllMenu(creatorId: Long, token: String) = api.getAllMenu(
creatorId = creatorId,
authHeader = token
)
fun saveMenu(menuId: Long, menu: String, token: String) = api.saveMenu(
request = UpdateLiveMenuRequest(
id = menuId,
menu = menu,
isActive = false
),
authHeader = token
)
}

View File

@ -0,0 +1,147 @@
package kr.co.vividnext.sodalive.live.room.menu
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.room.create.LiveRoomCreateViewModel
class MenuConfigViewModel(private val repository: MenuConfigRepository) : BaseViewModel() {
private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean>
get() = _isLoading
private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?>
get() = _toastLiveData
private val _selectedMenuLiveData = MutableLiveData<LiveRoomCreateViewModel.SelectedMenu>()
val selectedMenuLiveData: LiveData<LiveRoomCreateViewModel.SelectedMenu>
get() = _selectedMenuLiveData
private val _selectedMenuTextLiveData = MutableLiveData("")
val selectedMenuTextLiveData: LiveData<String>
get() = _selectedMenuTextLiveData
private var menuId = 0L
private val menuList = mutableListOf<GetMenuPresetResponse>()
var menuText: String = ""
fun getAllMenuPreset(selectedMenu: LiveRoomCreateViewModel.SelectedMenu = LiveRoomCreateViewModel.SelectedMenu.MENU_1) {
_isLoading.value = true
compositeDisposable.add(
repository.getAllMenu(
creatorId = SharedPreferenceManager.userId,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success) {
val data = it.data ?: listOf()
menuList.clear()
menuList.addAll(data)
selectMenuPreset(selectedMenu)
} 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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun selectMenuPreset(selectedMenuPreset: LiveRoomCreateViewModel.SelectedMenu) {
if (
menuList.isEmpty() &&
(
selectedMenuPreset == LiveRoomCreateViewModel.SelectedMenu.MENU_2 ||
selectedMenuPreset == LiveRoomCreateViewModel.SelectedMenu.MENU_3
)
) {
_toastLiveData.value = "메뉴 1을 먼저 설정하세요"
return
}
if (menuList.size == 1 && selectedMenuPreset == LiveRoomCreateViewModel.SelectedMenu.MENU_3) {
_toastLiveData.value = "메뉴 1과 메뉴 2를 먼저 설정하세요"
return
}
if (_selectedMenuLiveData.value != selectedMenuPreset) {
_selectedMenuLiveData.value = selectedMenuPreset
if (menuList.size > selectedMenuPreset.ordinal) {
val menuPreset = menuList[selectedMenuPreset.ordinal]
menuText = menuPreset.menu
menuId = menuPreset.id
_selectedMenuTextLiveData.value = menuPreset.menu
} else {
menuText = ""
menuId = 0
_selectedMenuTextLiveData.value = ""
}
}
}
fun saveMenu() {
if (menuText == _selectedMenuTextLiveData.value) {
_toastLiveData.postValue("저장되었습니다.")
return
}
_isLoading.value = true
compositeDisposable.add(
repository.saveMenu(
menuId = menuId,
menu = menuText,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success) {
_toastLiveData.postValue("저장되었습니다.")
getAllMenuPreset(selectedMenu = _selectedMenuLiveData.value!!)
} 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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun countMenu() = menuList.size
}

View File

@ -0,0 +1,14 @@
package kr.co.vividnext.sodalive.live.room.menu
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
@Keep
data class UpdateLiveMenuRequest(
@SerializedName("id")
val id: Long,
@SerializedName("menu")
val menu: String,
@SerializedName("isActive")
val isActive: Boolean = false
)

View File

@ -59,7 +59,7 @@ class RouletteConfigActivity : BaseActivity<ActivityRouletteConfigBinding>(
}
override fun setupView() {
binding.tvBack.text = "룰렛설정"
binding.tvBack.text = "룰렛 설정"
binding.tvBack.setOnClickListener { finish() }
loadingDialog = LoadingDialog(this, layoutInflater)

View File

@ -1,17 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@color/black">
<TextView
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:text="메뉴 설정"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/ll_select_menu_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_menu_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_menu_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_menu_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_777777"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_select_menu_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"
android:visibility="gone" />
<TextView
android:id="@+id/tv_select_menu_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="메뉴 2"
android:textColor="@color/color_555555"
android:textSize="14.7sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_select_menu_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_777777"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_select_menu_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_menu_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="메뉴 3"
android:textColor="@color/color_555555"
android:textSize="14.7sp" />
</LinearLayout>
</LinearLayout>
<EditText
android:id="@+id/et_menu"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="13.3dp"
android:background="@drawable/bg_round_corner_6_7_222222"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="top"
android:hint="메뉴판을 작성해주세요."
android:importantForAutofill="no"
android:inputType="textMultiLine"
android:overScrollMode="always"
android:padding="20dp"
android:scrollbarStyle="insideInset"
android:scrollbars="vertical"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_777777"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="13.3sp"
tools:ignore="LabelFor" />
<TextView
android:id="@+id/tv_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:background="@drawable/bg_round_corner_10_3bb9f1"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="메뉴 저장"
android:textColor="@color/white"
android:textSize="18.3sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>