성인 라이브 입장에 본인인증 흐름 추가

This commit is contained in:
2026-02-03 11:14:10 +09:00
parent 9496a57b3c
commit 666424f79b
6 changed files with 176 additions and 20 deletions

View File

@@ -201,7 +201,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
private fun setupLiveView() {
liveAdapter = HomeLiveAdapter {
if (SharedPreferenceManager.token.isNotBlank()) {
ensureLoginAndAdultAuth(isAdult = it.isAdult) {
val detailFragment = LiveRoomDetailFragment(
it.roomId,
onClickParticipant = { enterLiveRoom(it.roomId) },
@@ -210,14 +210,12 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
onClickStart = {},
onClickCancel = {}
)
if (detailFragment.isAdded) return@HomeLiveAdapter
if (detailFragment.isAdded) return@ensureLoginAndAdultAuth
detailFragment.show(
requireActivity().supportFragmentManager,
detailFragment.tag
)
} else {
(requireActivity() as MainActivity).showLoginActivity()
}
}
@@ -1358,6 +1356,30 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
onAuthed()
}
private fun ensureLoginAndAdultAuth(isAdult: Boolean, onAuthed: () -> Unit) {
if (SharedPreferenceManager.token.isBlank()) {
(requireActivity() as MainActivity).showLoginActivity()
return
}
if (isAdult && !SharedPreferenceManager.isAuth) {
SodaDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
title = getString(R.string.auth_title),
desc = getString(R.string.auth_desc_live),
confirmButtonTitle = getString(R.string.auth_go),
confirmButtonClick = { startAuthFlow() },
cancelButtonTitle = getString(R.string.cancel),
cancelButtonClick = {},
descGravity = Gravity.CENTER
).show(screenWidth)
return
}
onAuthed()
}
private fun startAuthFlow() {
Auth.auth(requireActivity(), requireContext()) { json ->
val bootpayResponse = Gson().fromJson(

View File

@@ -8,6 +8,7 @@ import android.graphics.Rect
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.Gravity
import android.view.View
import android.widget.LinearLayout
import android.widget.Toast
@@ -18,6 +19,7 @@ import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.gson.Gson
import com.zhpan.bannerview.BaseBannerAdapter
import com.zhpan.indicator.enums.IndicatorSlideMode
import com.zhpan.indicator.enums.IndicatorStyle
@@ -26,6 +28,7 @@ import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
import kr.co.vividnext.sodalive.base.BaseFragment
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
@@ -54,11 +57,16 @@ import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
import kr.co.vividnext.sodalive.live.room.update.LiveRoomEditActivity
import kr.co.vividnext.sodalive.main.MainActivity
import kr.co.vividnext.sodalive.message.MessageActivity
import kr.co.vividnext.sodalive.mypage.MyPageViewModel
import kr.co.vividnext.sodalive.mypage.auth.Auth
import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
import kr.co.vividnext.sodalive.search.SearchActivity
import kr.co.vividnext.sodalive.settings.language.LanguageManager
import kr.co.vividnext.sodalive.settings.language.LocaleHelper
import kr.co.vividnext.sodalive.settings.notification.MemberRole
import kr.co.vividnext.sodalive.splash.SplashActivity
import org.koin.android.ext.android.inject
import java.text.SimpleDateFormat
import java.util.Date
@@ -69,6 +77,7 @@ import kotlin.math.roundToInt
@UnstableApi
class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::inflate) {
private val viewModel: LiveViewModel by inject()
private val myPageViewModel: MyPageViewModel by inject()
private lateinit var liveNowAdapter: LiveNowAdapter
private lateinit var liveReservationAdapter: LiveReservationAdapter
@@ -510,7 +519,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
.rvLiveNow
liveNowAdapter = LiveNowAdapter {
if (SharedPreferenceManager.token.isNotBlank()) {
ensureLoginAndAdultAuth(isAdult = it.isAdult) {
val detailFragment = LiveRoomDetailFragment(
it.roomId,
onClickParticipant = { enterLiveRoom(it.roomId) },
@@ -519,14 +528,12 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
onClickStart = {},
onClickCancel = {}
)
if (detailFragment.isAdded) return@LiveNowAdapter
if (detailFragment.isAdded) return@ensureLoginAndAdultAuth
detailFragment.show(
requireActivity().supportFragmentManager,
detailFragment.tag
)
} else {
(requireActivity() as MainActivity).showLoginActivity()
}
}
@@ -857,6 +864,56 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
)
}
private fun ensureLoginAndAdultAuth(isAdult: Boolean, onAuthed: () -> Unit) {
if (SharedPreferenceManager.token.isBlank()) {
(requireActivity() as MainActivity).showLoginActivity()
return
}
if (isAdult && !SharedPreferenceManager.isAuth) {
SodaDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
title = getString(R.string.auth_title),
desc = getString(R.string.auth_desc_live),
confirmButtonTitle = getString(R.string.auth_go),
confirmButtonClick = { startAuthFlow() },
cancelButtonTitle = getString(R.string.cancel),
cancelButtonClick = {},
descGravity = Gravity.CENTER
).show(screenWidth)
return
}
onAuthed()
}
private fun startAuthFlow() {
Auth.auth(requireActivity(), requireContext()) { json ->
val bootpayResponse = Gson().fromJson(
json,
BootpayResponse::class.java
)
val request = AuthVerifyRequest(receiptId = bootpayResponse.data.receiptId)
requireActivity().runOnUiThread {
myPageViewModel.authVerify(request) {
startActivity(
Intent(
requireContext(),
SplashActivity::class.java
).apply {
addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TASK or
Intent.FLAG_ACTIVITY_NEW_TASK
)
}
)
requireActivity().finish()
}
}
}
}
@UnstableApi
fun enterLiveRoom(roomId: Long) {
requireContext().startService(

View File

@@ -3,16 +3,19 @@ package kr.co.vividnext.sodalive.live.now.all
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.widget.Toast
import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.gson.Gson
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.GridSpacingItemDecoration
import kr.co.vividnext.sodalive.common.LoadingDialog
@@ -24,8 +27,14 @@ import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
import kr.co.vividnext.sodalive.mypage.MyPageViewModel
import kr.co.vividnext.sodalive.mypage.auth.Auth
import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
import kr.co.vividnext.sodalive.settings.language.LanguageManager
import kr.co.vividnext.sodalive.settings.language.LocaleHelper
import kr.co.vividnext.sodalive.splash.SplashActivity
import kr.co.vividnext.sodalive.user.login.LoginActivity
import org.koin.android.ext.android.inject
import java.text.SimpleDateFormat
import java.util.Date
@@ -37,6 +46,7 @@ class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
ActivityLiveNowAllBinding::inflate
) {
private val viewModel: LiveViewModel by inject()
private val myPageViewModel: MyPageViewModel by inject()
private lateinit var adapter: LiveNowAllAdapter
private lateinit var loadingDialog: LoadingDialog
@@ -57,6 +67,7 @@ class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
val spacing = 16.dpToPx().toInt()
val recyclerView = binding.rvLive
adapter = LiveNowAllAdapter(itemWidth = (screenWidth - (spacing * (spanCount + 1))) / 2) {
ensureLoginAndAdultAuth(isAdult = it.isAdult) {
val detailFragment = LiveRoomDetailFragment(
it.roomId,
onClickParticipant = { enterLiveRoom(it.roomId) },
@@ -71,6 +82,7 @@ class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
detailFragment.tag
)
}
}
recyclerView.layoutManager = GridLayoutManager(this, spanCount)
recyclerView.addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, false))
@@ -101,6 +113,68 @@ class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
}
}
private fun ensureLoginAndAdultAuth(isAdult: Boolean, onAuthed: () -> Unit) {
if (SharedPreferenceManager.token.isBlank()) {
showLoginActivity()
return
}
if (isAdult && !SharedPreferenceManager.isAuth) {
SodaDialog(
activity = this,
layoutInflater = layoutInflater,
title = getString(R.string.auth_title),
desc = getString(R.string.auth_desc_live),
confirmButtonTitle = getString(R.string.auth_go),
confirmButtonClick = { startAuthFlow() },
cancelButtonTitle = getString(R.string.cancel),
cancelButtonClick = {},
descGravity = Gravity.CENTER
).show(screenWidth)
return
}
onAuthed()
}
private fun showLoginActivity() {
if (SharedPreferenceManager.token.isBlank()) {
startActivity(
Intent(applicationContext, LoginActivity::class.java).apply {
putExtra(Constants.EXTRA_DATA, intent.extras)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
)
}
}
private fun startAuthFlow() {
Auth.auth(this, applicationContext) { json ->
val bootpayResponse = Gson().fromJson(
json,
BootpayResponse::class.java
)
val request = AuthVerifyRequest(receiptId = bootpayResponse.data.receiptId)
runOnUiThread {
myPageViewModel.authVerify(request) {
startActivity(
Intent(
applicationContext,
SplashActivity::class.java
).apply {
addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TASK or
Intent.FLAG_ACTIVITY_NEW_TASK
)
}
)
finish()
}
}
}
}
private fun enterLiveRoom(roomId: Long) {
startService(
Intent(applicationContext, AudioContentPlayService::class.java).apply {

View File

@@ -155,6 +155,7 @@
<string name="live_paid_confirm">Enter after payment</string>
<string name="auth_title">Identity verification</string>
<string name="auth_desc">VoiceOns Open World Character Chat\nis available only to adults who have completed identity verification to protect minors.\nTo use the character chat service, please complete identity verification.</string>
<string name="auth_desc_live">To protect minors,\nonly adults who have completed identity verification\ncan enter live rooms.\nPlease complete identity verification\nto enter the live room.</string>
<string name="auth_go">Verify now</string>
<string name="deeplink_not_found">Failed to find deep link.</string>
<string name="deeplink_error">Deep link processing error: %1$s</string>

View File

@@ -155,6 +155,7 @@
<string name="live_paid_confirm">決済して入室</string>
<string name="auth_title">本人確認</string>
<string name="auth_desc">ボイスオンのオープンワールド・キャラトークは、\n青少年保護のため本人確認済みの\n成人の方のみご利用いただけます。\nサービスを利用するには本人確認をお願いします。</string>
<string name="auth_desc_live">青少年保護のため、\n本人確認を完了した成人の方のみ\nライブ入場が可能です。\nライブ入場のために\n本人確認を行ってください。</string>
<string name="auth_go">本人確認へ進む</string>
<string name="deeplink_not_found">ディープリンクが見つかりませんでした。</string>
<string name="deeplink_error">ディープリンク処理中にエラーが発生しました: %1$s</string>

View File

@@ -154,6 +154,7 @@
<string name="live_paid_confirm">결제 후 입장</string>
<string name="auth_title">본인인증</string>
<string name="auth_desc">보이스온의 오픈월드 캐릭터톡은\n청소년 보호를 위해 본인인증한\n성인만 이용이 가능합니다.\n캐릭터톡 서비스를 이용하시려면\n본인인증을 하고 이용해주세요.</string>
<string name="auth_desc_live">청소년 보호를 위해\n본인인증을 완료한\n성인만 라이브 입장이 가능합니다.\n라이브 입장을 위해\n본인인증을 진행해 주세요.</string>
<string name="auth_go">본인인증 하러가기</string>
<string name="deeplink_not_found">딥링크를 찾을 수 없습니다.</string>
<string name="deeplink_error">딥링크 처리 중 오류 발생: %1$s</string>