From 666424f79b6e8f8571d22176f521aa573e2d328e Mon Sep 17 00:00:00 2001 From: klaus Date: Tue, 3 Feb 2026 11:14:10 +0900 Subject: [PATCH] =?UTF-8?q?=EC=84=B1=EC=9D=B8=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=20=EC=9E=85=EC=9E=A5=EC=97=90=20=EB=B3=B8=EC=9D=B8?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=ED=9D=90=EB=A6=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vividnext/sodalive/home/HomeFragment.kt | 30 +++++- .../vividnext/sodalive/live/LiveFragment.kt | 65 +++++++++++- .../live/now/all/LiveNowAllActivity.kt | 98 ++++++++++++++++--- app/src/main/res/values-en/strings.xml | 1 + app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 6 files changed, 176 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt index 3a0a0372..faee6368 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt @@ -201,7 +201,7 @@ class HomeFragment : BaseFragment(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::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::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( diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/LiveFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/LiveFragment.kt index df708462..70b6b129 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/LiveFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/LiveFragment.kt @@ -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::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::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::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::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( diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/now/all/LiveNowAllActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/now/all/LiveNowAllActivity.kt index 756fbf7e..b27a41d3 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/now/all/LiveNowAllActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/now/all/LiveNowAllActivity.kt @@ -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::inflate ) { private val viewModel: LiveViewModel by inject() + private val myPageViewModel: MyPageViewModel by inject() private lateinit var adapter: LiveNowAllAdapter private lateinit var loadingDialog: LoadingDialog @@ -57,19 +67,21 @@ class LiveNowAllActivity : BaseActivity( val spacing = 16.dpToPx().toInt() val recyclerView = binding.rvLive adapter = LiveNowAllAdapter(itemWidth = (screenWidth - (spacing * (spanCount + 1))) / 2) { - val detailFragment = LiveRoomDetailFragment( - it.roomId, - onClickParticipant = { enterLiveRoom(it.roomId) }, - onClickReservation = {}, - onClickModify = {}, - onClickStart = {}, - onClickCancel = {} - ) + ensureLoginAndAdultAuth(isAdult = it.isAdult) { + val detailFragment = LiveRoomDetailFragment( + it.roomId, + onClickParticipant = { enterLiveRoom(it.roomId) }, + onClickReservation = {}, + onClickModify = {}, + onClickStart = {}, + onClickCancel = {} + ) - detailFragment.show( - supportFragmentManager, - detailFragment.tag - ) + detailFragment.show( + supportFragmentManager, + detailFragment.tag + ) + } } recyclerView.layoutManager = GridLayoutManager(this, spanCount) @@ -101,6 +113,68 @@ class LiveNowAllActivity : BaseActivity( } } + 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 { diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 28a5ba89..6606eb37 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -155,6 +155,7 @@ Enter after payment Identity verification VoiceOn’s 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. + To protect minors,\nonly adults who have completed identity verification\ncan enter live rooms.\nPlease complete identity verification\nto enter the live room. Verify now Failed to find deep link. Deep link processing error: %1$s diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 87e3419a..3779af26 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -155,6 +155,7 @@ 決済して入室 本人確認 ボイスオンのオープンワールド・キャラトークは、\n青少年保護のため本人確認済みの\n成人の方のみご利用いただけます。\nサービスを利用するには本人確認をお願いします。 + 青少年保護のため、\n本人確認を完了した成人の方のみ\nライブ入場が可能です。\nライブ入場のために\n本人確認を行ってください。 本人確認へ進む ディープリンクが見つかりませんでした。 ディープリンク処理中にエラーが発生しました: %1$s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5b7abce6..195838a5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -154,6 +154,7 @@ 결제 후 입장 본인인증 보이스온의 오픈월드 캐릭터톡은\n청소년 보호를 위해 본인인증한\n성인만 이용이 가능합니다.\n캐릭터톡 서비스를 이용하시려면\n본인인증을 하고 이용해주세요. + 청소년 보호를 위해\n본인인증을 완료한\n성인만 라이브 입장이 가능합니다.\n라이브 입장을 위해\n본인인증을 진행해 주세요. 본인인증 하러가기 딥링크를 찾을 수 없습니다. 딥링크 처리 중 오류 발생: %1$s