콘텐츠 업로드 문자열 리소스화

This commit is contained in:
2025-12-03 18:11:54 +09:00
parent ad1c58bbf5
commit de042abd79
9 changed files with 441 additions and 140 deletions

View File

@@ -1,7 +1,6 @@
package kr.co.vividnext.sodalive.audio_content.upload
import android.Manifest
import android.annotation.SuppressLint
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.content.Intent
@@ -84,16 +83,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
} else {
Toast.makeText(
this,
"잘못된 파일입니다.\n다시 선택해 주세요.",
getString(R.string.audio_content_upload_error_invalid_file),
Toast.LENGTH_SHORT
).show()
}
} else {
binding.tvSelectContent.text = "파일 선택"
binding.tvSelectContent.text =
getString(R.string.screen_audio_content_upload_select_file)
viewModel.contentUri = null
Toast.makeText(
this,
"파일 선택을 실패했습니다.\n다시 시도해 주세요.",
getString(R.string.audio_content_upload_error_select_file),
Toast.LENGTH_SHORT
).show()
}
@@ -177,11 +177,11 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
)
binding.tvServiceDate.text = if (SharedPreferenceManager.userId == 17958L) {
"※ 이용기간 : 대여(5일) | 소장(이용 기간 1년)"
getString(R.string.screen_audio_content_upload_service_period_one_year)
} else {
"※ 이용기간 : 대여(5일) | 소장(서비스 종료시까지)"
getString(R.string.screen_audio_content_upload_service_period_until_end)
}
binding.toolbar.tvBack.text = "콘텐츠 등록"
binding.toolbar.tvBack.text = getString(R.string.screen_audio_content_upload_title)
binding.toolbar.tvBack.setOnClickListener { finish() }
binding.llTheme.setOnClickListener {
if (themeFragment.isAdded) return@setOnClickListener
@@ -200,7 +200,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
selectAudioActivityResultLauncher.launch(
Intent.createChooser(
intent,
"Select Audio"
getString(R.string.audio_content_upload_select_audio_title)
)
)
}
@@ -235,11 +235,9 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
LiveDialog(
activity = this,
layoutInflater = layoutInflater,
title = "콘텐츠 업로드",
desc = "등록한 콘텐츠가 업로드 중입니다.\n" +
"콘텐츠 등록이 완료되면 알림을 보내드립니다.\n" +
"이 페이지를 나가도 콘텐츠는 자동으로 등록됩니다.",
confirmButtonTitle = "확인",
title = getString(R.string.audio_content_upload_dialog_title),
desc = getString(R.string.audio_content_upload_dialog_desc),
confirmButtonTitle = getString(R.string.confirm),
confirmButtonClick = { finish() },
).show(screenWidth)
}
@@ -309,6 +307,13 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
timePicker.show()
}
viewModel.setReservationDate(
getString(R.string.screen_audio_content_upload_reservation_date_placeholder)
)
viewModel.setReservationTime(
getString(R.string.screen_audio_content_upload_reservation_time_placeholder)
)
}
private fun checkPermissions() {
@@ -332,8 +337,12 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
.check()
}
@SuppressLint("SetTextI18n")
private fun bindData() {
binding.tvNumberOfCharacters.text = getString(
R.string.screen_audio_content_upload_char_count_format,
binding.etDetail.text?.length ?: 0
)
compositeDisposable.add(
binding.etTitle.textChanges().skip(1)
.subscribeOn(Schedulers.io())
@@ -348,7 +357,10 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
binding.tvNumberOfCharacters.text = "${it.length}"
binding.tvNumberOfCharacters.text = getString(
R.string.screen_audio_content_upload_char_count_format,
it.length
)
viewModel.detail = it.toString()
}
)
@@ -424,13 +436,21 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
}
)
viewModel.toastLiveData.observe(this) {
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
viewModel.toastLiveData.observe(this) { toastMessage ->
toastMessage?.let {
val message = it.message ?: it.resId?.let(::getString)
message?.let { text ->
Toast.makeText(applicationContext, text, Toast.LENGTH_LONG).show()
}
}
}
viewModel.isLoading.observe(this) {
if (it) {
loadingDialog.show(screenWidth, "콘텐츠를 업로드 하는 중입니다.")
loadingDialog.show(
screenWidth,
getString(R.string.screen_audio_content_upload_loading_message)
)
} else {
loadingDialog.dismiss()
}
@@ -876,7 +896,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
private fun checkBoth() {
uncheckPurchaseOption()
binding.tvPriceTitle.text = "소장 가격"
binding.tvPriceTitle.text =
getString(R.string.screen_audio_content_upload_price_title_keep)
binding.ivBoth.visibility = View.VISIBLE
binding.tvBoth.setTextColor(
ContextCompat.getColor(
@@ -889,7 +910,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
private fun checkBuyOnly() {
uncheckPurchaseOption()
binding.tvPriceTitle.text = "소장 가격"
binding.tvPriceTitle.text =
getString(R.string.screen_audio_content_upload_price_title_keep)
binding.ivBuyOnly.visibility = View.VISIBLE
binding.tvBuyOnly.setTextColor(
ContextCompat.getColor(
@@ -902,7 +924,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
private fun checkRentOnly() {
uncheckPurchaseOption()
binding.tvPriceTitle.text = "대여 가격"
binding.tvPriceTitle.text =
getString(R.string.screen_audio_content_upload_price_title_rent)
binding.ivRentOnly.visibility = View.VISIBLE
binding.tvRentOnly.setTextColor(
ContextCompat.getColor(

View File

@@ -11,7 +11,9 @@ import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.audio_content.PurchaseOption
import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.ToastMessage
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
@@ -27,8 +29,8 @@ class AudioContentUploadViewModel(
private val repository: AudioContentRepository
) : BaseViewModel() {
private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?>
private val _toastLiveData = MutableLiveData<ToastMessage?>()
val toastLiveData: LiveData<ToastMessage?>
get() = _toastLiveData
private var _isLoading = MutableLiveData(false)
@@ -71,11 +73,11 @@ class AudioContentUploadViewModel(
val isActiveReservationLiveData: LiveData<Boolean>
get() = _isActiveReservationLiveData
private val _reservationDateLiveData = MutableLiveData("날짜를 선택해주세요")
private val _reservationDateLiveData = MutableLiveData("")
val reservationDateLiveData: LiveData<String>
get() = _reservationDateLiveData
private val _reservationTimeLiveData = MutableLiveData("시간을 설정해주세요")
private val _reservationTimeLiveData = MutableLiveData("")
val reservationTimeLiveData: LiveData<String>
get() = _reservationTimeLiveData
@@ -262,12 +264,16 @@ class AudioContentUploadViewModel(
}
if (coverImage == null) {
_toastLiveData.postValue("커버이미지를 선택해 주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_cover_required)
)
return
}
if (contentFile == null) {
_toastLiveData.postValue("오디오 콘텐츠를 선택해 주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_content_required)
)
return
}
@@ -286,10 +292,12 @@ class AudioContentUploadViewModel(
onSuccess()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
_toastLiveData.postValue(
ToastMessage(message = it.message)
)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
ToastMessage(resId = R.string.common_error_unknown)
)
}
}
@@ -299,7 +307,7 @@ class AudioContentUploadViewModel(
_isLoading.postValue(false)
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
ToastMessage(resId = R.string.common_error_unknown)
)
}
)
@@ -309,48 +317,64 @@ class AudioContentUploadViewModel(
private fun validateData(): Boolean {
if (title.isBlank()) {
_toastLiveData.postValue("제목을 입력해 주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_title_required)
)
return false
}
if (detail.isBlank() || detail.length < 5) {
_toastLiveData.postValue("내용을 5자 이상 입력해 주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_detail_min_length)
)
return false
}
if (theme == null) {
_toastLiveData.postValue("테마를 선택해 주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_theme_required)
)
return false
}
if (coverImageFile == null) {
_toastLiveData.postValue("커버이미지를 선택해 주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_cover_required)
)
return false
}
if (previewStartTime != null && previewEndTime != null) {
val startTimeArray = previewStartTime!!.split(":")
if (startTimeArray.size != 3) {
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_preview_format)
)
return false
}
for (time in startTimeArray) {
if (time.length != 2) {
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_preview_format)
)
return false
}
}
val endTimeArray = previewEndTime!!.split(":")
if (endTimeArray.size != 3) {
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_preview_format)
)
return false
}
for (time in endTimeArray) {
if (time.length != 2) {
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_preview_format)
)
return false
}
}
@@ -359,7 +383,7 @@ class AudioContentUploadViewModel(
if (timeDifference < 15000) {
_toastLiveData.postValue(
"미리 듣기의 최소 시간은 15초 입니다."
ToastMessage(resId = R.string.audio_content_upload_error_preview_minimum)
)
return false
@@ -367,7 +391,9 @@ class AudioContentUploadViewModel(
} else {
if (previewStartTime != null || previewEndTime != null) {
_toastLiveData.postValue(
"미리 듣기 시작 시간과 종료 시간 둘 다 입력을 하거나 둘 다 입력 하지 않아야 합니다."
ToastMessage(
resId = R.string.audio_content_upload_error_preview_both_required
)
)
return false
@@ -375,12 +401,16 @@ class AudioContentUploadViewModel(
}
if (contentUri == null) {
_toastLiveData.postValue("오디오 콘텐츠를 선택해 주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_content_required)
)
return false
}
if (!isPriceFreeLiveData.value!! && price < 5) {
_toastLiveData.postValue("콘텐츠의 최소금액은 5캔 입니다.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_minimum_price)
)
return false
}
@@ -388,7 +418,9 @@ class AudioContentUploadViewModel(
_isActiveReservationLiveData.value!! &&
(releaseDate.isBlank() || releaseTime.isBlank())
) {
_toastLiveData.postValue("예약날짜와 시간을 선택해주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.audio_content_upload_error_reservation_required)
)
return false
}

View File

@@ -91,7 +91,13 @@ class AudioContentThemeFragment(
@SuppressLint("NotifyDataSetChanged")
private fun bindData() {
viewModel.toastLiveData.observe(viewLifecycleOwner) {
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
it?.let { toastMessage ->
val message = toastMessage.message
?: toastMessage.resId?.let(::getString)
message?.let { text ->
Toast.makeText(requireActivity(), text, Toast.LENGTH_LONG).show()
}
}
}
viewModel.themeLiveData.observe(viewLifecycleOwner) {

View File

@@ -7,11 +7,13 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.ToastMessage
class AudioContentThemeViewModel(private val repository: AudioContentRepository) : BaseViewModel() {
private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?>
private val _toastLiveData = MutableLiveData<ToastMessage?>()
val toastLiveData: LiveData<ToastMessage?>
get() = _toastLiveData
private val _themeLiveData = MutableLiveData<List<GetAudioContentThemeResponse>>()
@@ -29,17 +31,19 @@ class AudioContentThemeViewModel(private val repository: AudioContentRepository)
_themeLiveData.postValue(it.data!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
_toastLiveData.postValue(ToastMessage(message = it.message))
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
ToastMessage(resId = R.string.common_error_unknown)
)
}
}
},
{
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
_toastLiveData.postValue(
ToastMessage(resId = R.string.common_error_unknown)
)
}
)
)