캔 충전 화면 문자열 리소스화

This commit is contained in:
2025-12-02 14:39:30 +09:00
parent 98a6fb6637
commit 4caaeff0f0
12 changed files with 89 additions and 39 deletions

View File

@@ -53,7 +53,7 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
} }
private fun setupToolbar() { private fun setupToolbar() {
binding.toolbar.tvBack.text = "충전하기" binding.toolbar.tvBack.text = getString(R.string.screen_can_charge_title)
binding.toolbar.tvBack.setOnClickListener { finish() } binding.toolbar.tvBack.setOnClickListener { finish() }
} }
@@ -61,8 +61,8 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
val tabs = binding.tabs val tabs = binding.tabs
tabs.visibility = View.VISIBLE tabs.visibility = View.VISIBLE
tabs.addTab(tabs.newTab().setText("PG")) tabs.addTab(tabs.newTab().setText(R.string.screen_can_charge_tab_pg))
tabs.addTab(tabs.newTab().setText("인 앱 결제")) tabs.addTab(tabs.newTab().setText(R.string.screen_can_charge_tab_iap))
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) { override fun onTabSelected(tab: TabLayout.Tab) {

View File

@@ -27,7 +27,7 @@ class CanChargeIapAdapter(
val typeface = ResourcesCompat.getFont(context, R.font.gmarket_sans_medium) val typeface = ResourcesCompat.getFont(context, R.font.gmarket_sans_medium)
binding.tvTitle.text = item.name.fontSpan( binding.tvTitle.text = item.name.fontSpan(
typeface, typeface,
"" context.getString(R.string.screen_can_status_unit)
) )
binding.root.setOnClickListener { onClick(item) } binding.root.setOnClickListener { onClick(item) }

View File

@@ -21,6 +21,7 @@ import com.android.billingclient.api.Purchase
import com.android.billingclient.api.PurchasesUpdatedListener import com.android.billingclient.api.PurchasesUpdatedListener
import com.android.billingclient.api.QueryProductDetailsParams import com.android.billingclient.api.QueryProductDetailsParams
import com.android.billingclient.api.QueryPurchasesParams import com.android.billingclient.api.QueryPurchasesParams
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseFragment import kr.co.vividnext.sodalive.base.BaseFragment
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
@@ -69,7 +70,10 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
} }
viewModel.toastLiveData.observe(viewLifecycleOwner) { viewModel.toastLiveData.observe(viewLifecycleOwner) {
Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() val message = it?.resId?.let(::getString) ?: it?.message
message?.let { text ->
Toast.makeText(requireActivity(), text, Toast.LENGTH_LONG).show()
}
} }
} }
@@ -131,30 +135,30 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
} }
} else { } else {
selectedProductDetails = null selectedProductDetails = null
viewModel.showToast("구매 정보를 확인할 수 없습니다. 다시 시도해 주세요.") viewModel.showToast(resId = R.string.msg_can_charge_purchase_info_missing)
} }
} }
BillingClient.BillingResponseCode.USER_CANCELED -> { BillingClient.BillingResponseCode.USER_CANCELED -> {
selectedProductDetails = null selectedProductDetails = null
viewModel.showToast("구매를 취소했습니다.") viewModel.showToast(resId = R.string.msg_can_charge_purchase_canceled)
} }
BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED -> { BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED -> {
selectedProductDetails = null selectedProductDetails = null
queryAndConsumeUnconsumedPurchases() queryAndConsumeUnconsumedPurchases()
viewModel.showToast("이전에 완료되지 않은 구매를 정리했습니다. 다시 시도해 주세요.") viewModel.showToast(resId = R.string.msg_can_charge_purchase_cleanup)
} }
BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE, BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE,
BillingClient.BillingResponseCode.SERVICE_DISCONNECTED -> { BillingClient.BillingResponseCode.SERVICE_DISCONNECTED -> {
selectedProductDetails = null selectedProductDetails = null
viewModel.showToast("결제 서비스 연결이 원활하지 않습니다. 네트워크 상태를 확인 후 다시 시도해 주세요.") viewModel.showToast(resId = R.string.msg_can_charge_service_disconnected)
} }
else -> { else -> {
selectedProductDetails = null selectedProductDetails = null
viewModel.showToast("구매를 하지 못했습니다. 다시 시도해 주세요.") viewModel.showToast(resId = R.string.msg_can_charge_purchase_failed)
} }
} }
} }
@@ -174,7 +178,7 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
billingClient.startConnection(object : BillingClientStateListener { billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingServiceDisconnected() { override fun onBillingServiceDisconnected() {
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.") viewModel.showToast(resId = R.string.msg_can_charge_unavailable)
viewModel.setLoading(false) viewModel.setLoading(false)
} }
@@ -182,7 +186,7 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
queryAndConsumeUnconsumedPurchases() queryAndConsumeUnconsumedPurchases()
} else { } else {
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.") viewModel.showToast(resId = R.string.msg_can_charge_unavailable)
viewModel.setLoading(false) viewModel.setLoading(false)
} }
} }
@@ -216,7 +220,7 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
handler.post { adapter.addItems(result.productDetailsList) } handler.post { adapter.addItems(result.productDetailsList) }
} else { } else {
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.") viewModel.showToast(resId = R.string.msg_can_charge_unavailable)
} }
viewModel.setLoading(false) viewModel.setLoading(false)
@@ -279,7 +283,7 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
private fun onPurchaseConsumed(chargeCan: Int) { private fun onPurchaseConsumed(chargeCan: Int) {
handler.post { handler.post {
selectedProductDetails = null selectedProductDetails = null
viewModel.showToast("캔이 충전되었습니다") viewModel.showToast(resId = R.string.msg_can_charge_success)
SharedPreferenceManager.can += chargeCan SharedPreferenceManager.can += chargeCan
if (activity != null) { if (activity != null) {

View File

@@ -8,12 +8,14 @@ import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.ToastMessage
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.mypage.can.CanRepository import kr.co.vividnext.sodalive.mypage.can.CanRepository
class CanChargeIapViewModel(private val repository: CanRepository) : BaseViewModel() { class CanChargeIapViewModel(private val repository: CanRepository) : BaseViewModel() {
private val _toastLiveData = MutableLiveData<String?>() private val _toastLiveData = MutableLiveData<ToastMessage?>()
val toastLiveData: LiveData<String?> val toastLiveData: LiveData<ToastMessage?>
get() = _toastLiveData get() = _toastLiveData
private var _isLoading = MutableLiveData(false) private var _isLoading = MutableLiveData(false)
@@ -53,27 +55,26 @@ class CanChargeIapViewModel(private val repository: CanRepository) : BaseViewMod
if (it.success) { if (it.success) {
onSuccess(selectedProductDetails.description.toInt()) onSuccess(selectedProductDetails.description.toInt())
} else { } else {
if (it.message != null) { _toastLiveData.value = it.message?.let { message ->
_toastLiveData.value = it.message ToastMessage(message = message)
} else { } ?: ToastMessage(resId = R.string.common_error_unknown)
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
}
} }
}, },
{ {
_isLoading.value = false _isLoading.value = false
it.message?.let { message -> Logger.e(message) } it.message?.let { message -> Logger.e(message) }
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." _toastLiveData.value = ToastMessage(resId = R.string.common_error_unknown)
} }
) )
) )
} else { } else {
_toastLiveData.value = "구매를 하지 못했습니다.\n고객센터로 문의해 주시기 바랍니다." _toastLiveData.value =
ToastMessage(resId = R.string.msg_can_charge_purchase_not_found)
} }
} }
fun showToast(message: String) { fun showToast(message: String? = null, resId: Int? = null) {
_toastLiveData.value = message _toastLiveData.value = ToastMessage(resId = resId, message = message)
} }
fun setLoading(isLoading: Boolean) { fun setLoading(isLoading: Boolean) {

View File

@@ -28,7 +28,7 @@ class CanChargePgAdapter(
val typeface = ResourcesCompat.getFont(context, R.font.gmarket_sans_medium) val typeface = ResourcesCompat.getFont(context, R.font.gmarket_sans_medium)
binding.tvTitle.text = canCharge.title.fontSpan( binding.tvTitle.text = canCharge.title.fontSpan(
typeface, typeface,
"" context.getString(R.string.screen_can_status_unit)
) )
binding.root.setOnClickListener { onClick(canCharge) } binding.root.setOnClickListener { onClick(canCharge) }

View File

@@ -87,7 +87,10 @@ class CanChargePgFragment : BaseFragment<FragmentCanChargePgBinding>(
} }
viewModel.toastLiveData.observe(viewLifecycleOwner) { viewModel.toastLiveData.observe(viewLifecycleOwner) {
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() } val message = it?.resId?.let(::getString) ?: it?.message
message?.let { text ->
Toast.makeText(requireActivity(), text, Toast.LENGTH_LONG).show()
}
} }
viewModel.isLoading.observe(viewLifecycleOwner) { viewModel.isLoading.observe(viewLifecycleOwner) {

View File

@@ -6,7 +6,9 @@ import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.ToastMessage
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.mypage.can.CanRepository import kr.co.vividnext.sodalive.mypage.can.CanRepository
class CanChargePgViewModel(private val repository: CanRepository) : BaseViewModel() { class CanChargePgViewModel(private val repository: CanRepository) : BaseViewModel() {
@@ -14,8 +16,8 @@ class CanChargePgViewModel(private val repository: CanRepository) : BaseViewMode
val canChargeLiveData: LiveData<List<CanResponse>> val canChargeLiveData: LiveData<List<CanResponse>>
get() = _canChargesLiveData get() = _canChargesLiveData
private val _toastLiveData = MutableLiveData<String?>() private val _toastLiveData = MutableLiveData<ToastMessage?>()
val toastLiveData: LiveData<String?> val toastLiveData: LiveData<ToastMessage?>
get() = _toastLiveData get() = _toastLiveData
private var _isLoading = MutableLiveData(false) private var _isLoading = MutableLiveData(false)
@@ -33,20 +35,18 @@ class CanChargePgViewModel(private val repository: CanRepository) : BaseViewMode
_isLoading.value = false _isLoading.value = false
if (it.success && it.data != null) { if (it.success && it.data != null) {
_canChargesLiveData.postValue(it.data!!) _canChargesLiveData.postValue(it.data!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else { } else {
_toastLiveData.postValue( _toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." it.message?.let { message ->
ToastMessage(message = message)
} ?: ToastMessage(resId = R.string.common_error_unknown)
) )
} }
}
}, },
{ {
_isLoading.value = false _isLoading.value = false
it.message?.let { message -> Logger.e(message) } it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") _toastLiveData.postValue(ToastMessage(resId = R.string.common_error_unknown))
} }
) )
) )

View File

@@ -78,7 +78,10 @@ class CanChargeStatusFragment(
} }
viewModel.toastLiveData.observe(viewLifecycleOwner) { viewModel.toastLiveData.observe(viewLifecycleOwner) {
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() } val message = it?.resId?.let(::getString) ?: it?.message
message?.let { text ->
Toast.makeText(requireContext(), text, Toast.LENGTH_LONG).show()
}
} }
} }
} }

View File

@@ -77,7 +77,10 @@ class CanUseStatusFragment(
} }
viewModel.toastLiveData.observe(viewLifecycleOwner) { viewModel.toastLiveData.observe(viewLifecycleOwner) {
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() } val message = it?.resId?.let(::getString) ?: it?.message
message?.let { text ->
Toast.makeText(requireContext(), text, Toast.LENGTH_LONG).show()
}
} }
} }
} }

View File

@@ -370,6 +370,18 @@
<string name="screen_can_status_label_reward">Reward cans</string> <string name="screen_can_status_label_reward">Reward cans</string>
<string name="screen_can_status_unit">cans</string> <string name="screen_can_status_unit">cans</string>
<string name="screen_can_status_charge_action">Top up</string> <string name="screen_can_status_charge_action">Top up</string>
<!-- Can Charge -->
<string name="screen_can_charge_title">Top up</string>
<string name="screen_can_charge_tab_pg">PG</string>
<string name="screen_can_charge_tab_iap">In-app purchase</string>
<string name="msg_can_charge_purchase_info_missing">Could not confirm purchase info. Please try again.</string>
<string name="msg_can_charge_purchase_canceled">Purchase cancelled.</string>
<string name="msg_can_charge_purchase_cleanup">Cleaned up unfinished purchases. Please try again.</string>
<string name="msg_can_charge_service_disconnected">Payment service is unstable. Check your network and try again.</string>
<string name="msg_can_charge_purchase_failed">Purchase failed. Please try again.</string>
<string name="msg_can_charge_unavailable">In-app purchases are unavailable. Please try again.</string>
<string name="msg_can_charge_success">Cans charged.</string>
<string name="msg_can_charge_purchase_not_found">Purchase failed.\nPlease contact customer support.</string>
<!-- Service Center --> <!-- Service Center -->
<string name="screen_service_center_title">Customer service</string> <string name="screen_service_center_title">Customer service</string>
<string name="screen_service_center_logo_label">VoiceOn Customer Service</string> <string name="screen_service_center_logo_label">VoiceOn Customer Service</string>

View File

@@ -370,6 +370,18 @@
<string name="screen_can_status_label_reward">リワードCAN</string> <string name="screen_can_status_label_reward">リワードCAN</string>
<string name="screen_can_status_unit">CAN</string> <string name="screen_can_status_unit">CAN</string>
<string name="screen_can_status_charge_action">チャージする</string> <string name="screen_can_status_charge_action">チャージする</string>
<!-- Can Charge -->
<string name="screen_can_charge_title">チャージ</string>
<string name="screen_can_charge_tab_pg">PG</string>
<string name="screen_can_charge_tab_iap">アプリ内決済</string>
<string name="msg_can_charge_purchase_info_missing">購入情報を確認できません。もう一度お試しください。</string>
<string name="msg_can_charge_purchase_canceled">購入をキャンセルしました。</string>
<string name="msg_can_charge_purchase_cleanup">完了していない購入を整理しました。もう一度お試しください。</string>
<string name="msg_can_charge_service_disconnected">決済サービスに接続できません。ネットワーク状態を確認してもう一度お試しください。</string>
<string name="msg_can_charge_purchase_failed">購入に失敗しました。もう一度お試しください。</string>
<string name="msg_can_charge_unavailable">アプリ内決済を利用できません。もう一度お試しください。</string>
<string name="msg_can_charge_success">CANをチャージしました。</string>
<string name="msg_can_charge_purchase_not_found">購入に失敗しました。\nカスタマーセンターにお問い合わせください。</string>
<!-- Service Center --> <!-- Service Center -->
<string name="screen_service_center_title">カスタマーセンター</string> <string name="screen_service_center_title">カスタマーセンター</string>
<string name="screen_service_center_logo_label">VoiceOn カスタマーセンター</string> <string name="screen_service_center_logo_label">VoiceOn カスタマーセンター</string>

View File

@@ -369,6 +369,18 @@
<string name="screen_can_status_label_reward">리워드 캔</string> <string name="screen_can_status_label_reward">리워드 캔</string>
<string name="screen_can_status_unit"></string> <string name="screen_can_status_unit"></string>
<string name="screen_can_status_charge_action">충전하기</string> <string name="screen_can_status_charge_action">충전하기</string>
<!-- Can Charge -->
<string name="screen_can_charge_title">충전하기</string>
<string name="screen_can_charge_tab_pg">PG</string>
<string name="screen_can_charge_tab_iap">인 앱 결제</string>
<string name="msg_can_charge_purchase_info_missing">구매 정보를 확인할 수 없습니다. 다시 시도해 주세요.</string>
<string name="msg_can_charge_purchase_canceled">구매를 취소했습니다.</string>
<string name="msg_can_charge_purchase_cleanup">이전에 완료되지 않은 구매를 정리했습니다. 다시 시도해 주세요.</string>
<string name="msg_can_charge_service_disconnected">결제 서비스 연결이 원활하지 않습니다. 네트워크 상태를 확인 후 다시 시도해 주세요.</string>
<string name="msg_can_charge_purchase_failed">구매를 하지 못했습니다. 다시 시도해 주세요.</string>
<string name="msg_can_charge_unavailable">인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.</string>
<string name="msg_can_charge_success">캔이 충전되었습니다</string>
<string name="msg_can_charge_purchase_not_found">구매를 하지 못했습니다.\n고객센터로 문의해 주시기 바랍니다.</string>
<!-- Service Center --> <!-- Service Center -->
<string name="screen_service_center_title">고객센터</string> <string name="screen_service_center_title">고객센터</string>
<string name="screen_service_center_logo_label">보이스온 고객센터</string> <string name="screen_service_center_logo_label">보이스온 고객센터</string>