diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 66df27f..aac1411 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -143,7 +143,7 @@ - + diff --git a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt index 454680a..5294857 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt @@ -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( diff --git a/app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt index ed346ed..bc01df3 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt @@ -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 diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/menu/MenuConfigActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/menu/MenuConfigActivity.kt deleted file mode 100644 index df1ec69..0000000 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/menu/MenuConfigActivity.kt +++ /dev/null @@ -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::inflate -) { - override fun setupView() { - } -} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/GetMenuPresetResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/GetMenuPresetResponse.kt index 50dbc0c..5ab0732 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/GetMenuPresetResponse.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/GetMenuPresetResponse.kt @@ -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 ) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuApi.kt index dffa1d5..214c561 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuApi.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuApi.kt @@ -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>> + + @POST("/live/room/menu") + fun saveMenu( + @Body request: UpdateLiveMenuRequest, + @Header("Authorization") authHeader: String + ): Single> } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigActivity.kt new file mode 100644 index 0000000..d3e7c47 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigActivity.kt @@ -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::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 + ) + ) + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigRepository.kt new file mode 100644 index 0000000..869c818 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigRepository.kt @@ -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 + ) +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigViewModel.kt new file mode 100644 index 0000000..66973c2 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/MenuConfigViewModel.kt @@ -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 + get() = _isLoading + + private val _toastLiveData = MutableLiveData() + val toastLiveData: LiveData + get() = _toastLiveData + + private val _selectedMenuLiveData = MutableLiveData() + val selectedMenuLiveData: LiveData + get() = _selectedMenuLiveData + + private val _selectedMenuTextLiveData = MutableLiveData("") + val selectedMenuTextLiveData: LiveData + get() = _selectedMenuTextLiveData + + private var menuId = 0L + private val menuList = mutableListOf() + + 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 +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/UpdateLiveMenuRequest.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/UpdateLiveMenuRequest.kt new file mode 100644 index 0000000..853792d --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/menu/UpdateLiveMenuRequest.kt @@ -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 +) 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 index 05e4221..914ca97 100644 --- 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 @@ -59,7 +59,7 @@ class RouletteConfigActivity : BaseActivity( } override fun setupView() { - binding.tvBack.text = "룰렛설정" + binding.tvBack.text = "룰렛 설정" binding.tvBack.setOnClickListener { finish() } loadingDialog = LoadingDialog(this, layoutInflater) diff --git a/app/src/main/res/layout/activity_menu_config.xml b/app/src/main/res/layout/activity_menu_config.xml index c6a1517..d95c521 100644 --- a/app/src/main/res/layout/activity_menu_config.xml +++ b/app/src/main/res/layout/activity_menu_config.xml @@ -1,17 +1,151 @@ + android:layout_height="match_parent" + android:background="@color/black"> - + + + app:layout_constraintTop_toBottomOf="@+id/toolbar"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +