feat(main-v2): 메인 하단 내비게이션을 추가한다
@@ -111,6 +111,7 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".main.MainActivity" />
|
||||
<activity android:name=".v2.main.MainV2Activity" />
|
||||
<activity android:name=".user.login.LoginActivity" />
|
||||
<activity android:name=".audio_content.all.AudioContentAllActivity" />
|
||||
<activity android:name=".settings.language.LanguageSettingsActivity" />
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.bumptech.glide.request.transition.Transition
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class AudioContentPlayService :
|
||||
@@ -471,7 +471,7 @@ class AudioContentPlayService :
|
||||
}
|
||||
|
||||
private fun updateNotification() {
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
val intent = Intent(this, MainV2Activity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
|
||||
@@ -32,7 +32,7 @@ import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlayli
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.Utils
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
@UnstableApi
|
||||
@@ -153,7 +153,7 @@ class AudioContentPlayerService : MediaSessionService() {
|
||||
}
|
||||
|
||||
private fun initMediaSession() {
|
||||
val contextIntent = Intent(applicationContext, MainActivity::class.java).apply {
|
||||
val contextIntent = Intent(applicationContext, MainV2Activity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
}
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
|
||||
@@ -176,6 +176,7 @@ import kr.co.vividnext.sodalive.user.UserViewModel
|
||||
import kr.co.vividnext.sodalive.user.find_password.FindPasswordViewModel
|
||||
import kr.co.vividnext.sodalive.user.login.LoginViewModel
|
||||
import kr.co.vividnext.sodalive.user.signup.SignUpViewModel
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2ViewModel
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
@@ -297,6 +298,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||
viewModel { TermsViewModel(get()) }
|
||||
viewModel { FindPasswordViewModel(get()) }
|
||||
viewModel { MainViewModel(get(), get(), get(), get(), get()) }
|
||||
viewModel { MainV2ViewModel(get(), get(), get(), get(), get()) }
|
||||
viewModel { LiveViewModel(get(), get(), get(), get(), get()) }
|
||||
viewModel { MyPageViewModel(get(), get(), get()) }
|
||||
viewModel { CanStatusViewModel(get()) }
|
||||
|
||||
@@ -9,8 +9,8 @@ import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityLiveReservationCompleteBinding
|
||||
import kr.co.vividnext.sodalive.extensions.convertDateFormat
|
||||
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationResponse
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.settings.language.LanguageManager
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
@@ -52,7 +52,7 @@ class LiveReservationCompleteActivity : BaseActivity<ActivityLiveReservationComp
|
||||
binding.tvRemainingCan.text = "${response.remainingCan}"
|
||||
|
||||
binding.tvGoHome.setOnClickListener {
|
||||
val intent = Intent(applicationContext, MainActivity::class.java)
|
||||
val intent = Intent(applicationContext, MainV2Activity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
startActivity(intent)
|
||||
|
||||
@@ -16,6 +16,7 @@ import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
|
||||
import kr.co.vividnext.sodalive.message.MessageActivity
|
||||
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentActivity
|
||||
import kr.co.vividnext.sodalive.splash.SplashActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import java.util.Locale
|
||||
|
||||
class DeepLinkActivity : AppCompatActivity() {
|
||||
@@ -63,7 +64,7 @@ class DeepLinkActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
startActivity(
|
||||
Intent(applicationContext, MainActivity::class.java).apply {
|
||||
Intent(applicationContext, MainV2Activity::class.java).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
deepLinkExtras?.let { putExtra(Constants.EXTRA_DATA, it) }
|
||||
}
|
||||
@@ -465,7 +466,7 @@ class DeepLinkActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
startActivity(
|
||||
Intent(applicationContext, MainActivity::class.java).apply {
|
||||
Intent(applicationContext, MainV2Activity::class.java).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
putExtra(Constants.EXTRA_DATA, extras)
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import kr.co.vividnext.sodalive.settings.notice.NoticeActivity
|
||||
import kr.co.vividnext.sodalive.settings.notice.NoticeDetailActivity
|
||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||
import kr.co.vividnext.sodalive.splash.SplashActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
@UnstableApi
|
||||
@@ -275,19 +276,19 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
||||
binding.rlProfileContainer.visibility = View.GONE
|
||||
binding.llProfileLoginContainer.visibility = View.VISIBLE
|
||||
binding.llProfileLoginContainer.setOnClickListener {
|
||||
(requireActivity() as MainActivity).showLoginActivity()
|
||||
showLoginActivity()
|
||||
}
|
||||
|
||||
binding.tvCanAmount.text =
|
||||
SodaLiveApplicationHolder.get().getString(R.string.common_zero)
|
||||
binding.tvCanAmount.setOnClickListener {
|
||||
(requireActivity() as MainActivity).showLoginActivity()
|
||||
showLoginActivity()
|
||||
}
|
||||
|
||||
binding.tvPointAmount.text =
|
||||
SodaLiveApplicationHolder.get().getString(R.string.common_zero)
|
||||
binding.tvPointAmount.setOnClickListener {
|
||||
(requireActivity() as MainActivity).showLoginActivity()
|
||||
showLoginActivity()
|
||||
}
|
||||
|
||||
binding.tvChargeCan.visibility = View.INVISIBLE
|
||||
@@ -499,4 +500,10 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLoginActivity() {
|
||||
when (val activity = requireActivity()) {
|
||||
is MainActivity -> activity.showLoginActivity()
|
||||
is MainV2Activity -> activity.showLoginActivity()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityCanStatusBinding
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||
import kr.co.vividnext.sodalive.mypage.can.status.charge.CanChargeStatusFragment
|
||||
import kr.co.vividnext.sodalive.mypage.can.status.use.CanUseStatusFragment
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class CanStatusActivity : BaseActivity<ActivityCanStatusBinding>(
|
||||
@@ -137,7 +137,7 @@ class CanStatusActivity : BaseActivity<ActivityCanStatusBinding>(
|
||||
}
|
||||
|
||||
private fun onClickBackButton() {
|
||||
val intent = Intent(applicationContext, MainActivity::class.java)
|
||||
val intent = Intent(applicationContext, MainV2Activity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
startActivity(intent)
|
||||
|
||||
@@ -11,9 +11,9 @@ import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityPointStatusBinding
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.mypage.point.reward.PointRewardStatusFragment
|
||||
import kr.co.vividnext.sodalive.mypage.point.use.PointUseStatusFragment
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class PointStatusActivity : BaseActivity<ActivityPointStatusBinding>(
|
||||
@@ -120,7 +120,7 @@ class PointStatusActivity : BaseActivity<ActivityPointStatusBinding>(
|
||||
}
|
||||
|
||||
private fun onClickBackButton() {
|
||||
val intent = Intent(applicationContext, MainActivity::class.java)
|
||||
val intent = Intent(applicationContext, MainV2Activity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
startActivity(intent)
|
||||
|
||||
@@ -20,7 +20,7 @@ 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.databinding.ActivitySplashBinding
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
|
||||
@SuppressLint("CustomSplashScreen")
|
||||
class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding::inflate) {
|
||||
@@ -174,7 +174,7 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
|
||||
private fun showMainActivity(extras: Bundle?) {
|
||||
handler.postDelayed({
|
||||
startActivity(
|
||||
Intent(applicationContext, MainActivity::class.java).apply {
|
||||
Intent(applicationContext, MainV2Activity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_DATA, extras)
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.user.login
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
@@ -45,9 +44,9 @@ import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityLoginBinding
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.user.find_password.FindPasswordActivity
|
||||
import kr.co.vividnext.sodalive.user.signup.SignUpActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.UUID
|
||||
import androidx.core.net.toUri
|
||||
@@ -434,7 +433,7 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::i
|
||||
}
|
||||
|
||||
private fun navigateToMain() {
|
||||
val nextIntent = Intent(this@LoginActivity, MainActivity::class.java)
|
||||
val nextIntent = Intent(this@LoginActivity, MainV2Activity::class.java)
|
||||
val extras = intent.getBundleExtra(Constants.EXTRA_DATA)
|
||||
?: if (intent.extras != null) {
|
||||
intent.extras
|
||||
|
||||
@@ -17,8 +17,8 @@ import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.databinding.ActivitySignupBinding
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.settings.terms.TermsActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
@@ -152,7 +152,7 @@ class SignUpActivity : BaseActivity<ActivitySignupBinding>(ActivitySignupBinding
|
||||
}
|
||||
|
||||
private fun navigateToMain() {
|
||||
val nextIntent = Intent(this@SignUpActivity, MainActivity::class.java)
|
||||
val nextIntent = Intent(this@SignUpActivity, MainV2Activity::class.java)
|
||||
val extras = intent.getBundleExtra(Constants.EXTRA_DATA)
|
||||
?: if (intent.extras != null) {
|
||||
intent.extras
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.v2.main
|
||||
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentV2MainChatBinding
|
||||
|
||||
class ChatMainFragment : BaseFragment<FragmentV2MainChatBinding>(
|
||||
FragmentV2MainChatBinding::inflate
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.v2.main
|
||||
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentV2MainContentBinding
|
||||
|
||||
class ContentMainFragment : BaseFragment<FragmentV2MainContentBinding>(
|
||||
FragmentV2MainContentBinding::inflate
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.v2.main
|
||||
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentV2MainHomeBinding
|
||||
|
||||
class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
FragmentV2MainHomeBinding::inflate
|
||||
)
|
||||
@@ -0,0 +1,654 @@
|
||||
package kr.co.vividnext.sodalive.v2.main
|
||||
|
||||
import android.Manifest
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.MediaMetadata
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.session.MediaController
|
||||
import androidx.media3.session.SessionToken
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import com.gun0912.tedpermission.PermissionListener
|
||||
import com.gun0912.tedpermission.normal.TedPermission
|
||||
import com.orhanobut.logger.Logger
|
||||
import kr.co.vividnext.sodalive.R
|
||||
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.AudioContentPlayerFragment
|
||||
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||
import kr.co.vividnext.sodalive.audition.AuditionActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityMainV2Binding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
|
||||
import kr.co.vividnext.sodalive.main.EventPopupDialogFragment
|
||||
import kr.co.vividnext.sodalive.message.MessageActivity
|
||||
import kr.co.vividnext.sodalive.mypage.MyPageFragment
|
||||
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
|
||||
import kr.co.vividnext.sodalive.settings.notification.NotificationSettingsDialog
|
||||
import kr.co.vividnext.sodalive.user.login.LoginActivity
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.Locale
|
||||
import kotlin.math.max
|
||||
|
||||
@UnstableApi
|
||||
class MainV2Activity : BaseActivity<ActivityMainV2Binding>(ActivityMainV2Binding::inflate) {
|
||||
|
||||
private val viewModel: MainV2ViewModel by inject()
|
||||
|
||||
private lateinit var notificationSettingsDialog: NotificationSettingsDialog
|
||||
private var mediaController: MediaController? = null
|
||||
private var mediaControllerFuture: ListenableFuture<MediaController>? = null
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val showMiniPlayerRunnable = Runnable { initAndVisibleMiniPlayer() }
|
||||
private var playerStateJob: Job? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
overrideRootWindowInsets()
|
||||
|
||||
checkPermissions()
|
||||
trackAppLaunchIfNeeded()
|
||||
pushTokenUpdate()
|
||||
|
||||
if (isLoggedIn()) {
|
||||
updatePidAndGaid()
|
||||
getEventPopup()
|
||||
observePlayerState()
|
||||
handler.postDelayed({ executeDeeplink(intent) }, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
private fun overrideRootWindowInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
|
||||
|
||||
val left = max(systemBars.left, ime.left)
|
||||
val top = systemBars.top
|
||||
val right = max(systemBars.right, ime.right)
|
||||
v.setPadding(left, top, right, 0)
|
||||
|
||||
insets
|
||||
}
|
||||
ViewCompat.requestApplyInsets(binding.root)
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
setIntent(intent)
|
||||
|
||||
if (isLoggedIn()) {
|
||||
executeDeeplink(intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
getMemberInfo()
|
||||
startService(
|
||||
Intent(this, AudioContentPlayService::class.java).apply {
|
||||
action = AudioContentPlayService.MusicAction.INIT.name
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
deInitMiniPlayer()
|
||||
playerStateJob?.cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
notificationSettingsDialog = NotificationSettingsDialog(
|
||||
this,
|
||||
layoutInflater
|
||||
) { isNotifiedLive, isNotifiedUploadContent, isNotifiedMessage ->
|
||||
viewModel.updateNotificationSettings(
|
||||
isNotifiedLive,
|
||||
isNotifiedUploadContent,
|
||||
isNotifiedMessage
|
||||
)
|
||||
}
|
||||
|
||||
setupBottomNavigation()
|
||||
}
|
||||
|
||||
fun showLoginActivity() {
|
||||
if (SharedPreferenceManager.token.isBlank()) {
|
||||
val extras = intent.extras
|
||||
startActivity(
|
||||
Intent(applicationContext, LoginActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_DATA, extras)
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun openChatTab() {
|
||||
viewModel.clickTab(MainV2Tab.CHAT)
|
||||
}
|
||||
|
||||
private fun setupBottomNavigation() {
|
||||
binding.bottomNavigation.setOnItemSelectedListener { item ->
|
||||
when (item.itemId) {
|
||||
R.id.menu_main_v2_home -> viewModel.clickTab(MainV2Tab.HOME)
|
||||
R.id.menu_main_v2_content -> viewModel.clickTab(MainV2Tab.CONTENT)
|
||||
R.id.menu_main_v2_chat -> viewModel.clickTab(MainV2Tab.CHAT)
|
||||
R.id.menu_main_v2_my -> viewModel.clickTab(MainV2Tab.MY)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
binding.bottomNavigation.apply {
|
||||
itemIconTintList = null
|
||||
}
|
||||
|
||||
viewModel.currentTab.observe(this) { tab ->
|
||||
val itemId = when (tab) {
|
||||
MainV2Tab.HOME -> R.id.menu_main_v2_home
|
||||
MainV2Tab.CONTENT -> R.id.menu_main_v2_content
|
||||
MainV2Tab.CHAT -> R.id.menu_main_v2_chat
|
||||
MainV2Tab.MY -> R.id.menu_main_v2_my
|
||||
}
|
||||
|
||||
if (binding.bottomNavigation.selectedItemId != itemId) {
|
||||
binding.bottomNavigation.selectedItemId = itemId
|
||||
}
|
||||
|
||||
changeFragment(tab)
|
||||
}
|
||||
}
|
||||
|
||||
private fun changeFragment(currentTab: MainV2Tab) {
|
||||
val tag = currentTab.toString()
|
||||
val fragmentManager = supportFragmentManager
|
||||
val fragmentTransaction = fragmentManager.beginTransaction()
|
||||
|
||||
fragmentManager.primaryNavigationFragment?.let {
|
||||
fragmentTransaction.hide(it)
|
||||
}
|
||||
|
||||
var fragment = fragmentManager.findFragmentByTag(tag)
|
||||
if (fragment == null) {
|
||||
fragment = when (currentTab) {
|
||||
MainV2Tab.HOME -> HomeMainFragment()
|
||||
MainV2Tab.CONTENT -> ContentMainFragment()
|
||||
MainV2Tab.CHAT -> ChatMainFragment()
|
||||
MainV2Tab.MY -> MyPageFragment()
|
||||
}
|
||||
fragmentTransaction.add(R.id.fl_container, fragment, tag)
|
||||
} else {
|
||||
fragmentTransaction.show(fragment)
|
||||
}
|
||||
|
||||
fragmentTransaction.setPrimaryNavigationFragment(fragment)
|
||||
fragmentTransaction.setReorderingAllowed(true)
|
||||
fragmentTransaction.commitNow()
|
||||
}
|
||||
|
||||
private fun observePlayerState() {
|
||||
playerStateJob = lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
SharedPreferenceManager.isPlayerServiceRunningFlow.collect { isRunning ->
|
||||
if (isRunning) {
|
||||
handler.removeCallbacks(showMiniPlayerRunnable)
|
||||
handler.postDelayed(showMiniPlayerRunnable, 1500)
|
||||
} else {
|
||||
deInitMiniPlayer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initAndVisibleMiniPlayer() {
|
||||
binding.clMiniPlayer.visibility = View.VISIBLE
|
||||
binding.clMiniPlayer.setOnClickListener { showPlayerFragment() }
|
||||
binding.ivPlayerStop.setOnClickListener {
|
||||
startService(
|
||||
Intent(applicationContext, AudioContentPlayerService::class.java).apply {
|
||||
action = "STOP_SERVICE"
|
||||
}
|
||||
)
|
||||
}
|
||||
connectPlayerService()
|
||||
}
|
||||
|
||||
private fun connectPlayerService() {
|
||||
if (mediaController != null || mediaControllerFuture != null) {
|
||||
return
|
||||
}
|
||||
|
||||
val componentName = ComponentName(applicationContext, AudioContentPlayerService::class.java)
|
||||
val sessionToken = SessionToken(applicationContext, componentName)
|
||||
val controllerFuture =
|
||||
MediaController.Builder(applicationContext, sessionToken).buildAsync()
|
||||
mediaControllerFuture = controllerFuture
|
||||
controllerFuture.addListener(
|
||||
{
|
||||
try {
|
||||
if (mediaController != null) {
|
||||
controllerFuture.get().release()
|
||||
return@addListener
|
||||
}
|
||||
|
||||
mediaController = controllerFuture.get()
|
||||
setupMediaController()
|
||||
updateMediaMetadata(mediaController?.mediaMetadata)
|
||||
|
||||
binding.ivPlayerPlayOrPause.setImageResource(
|
||||
if (mediaController?.isPlaying == true) {
|
||||
R.drawable.ic_player_pause
|
||||
} else {
|
||||
R.drawable.ic_player_play
|
||||
}
|
||||
)
|
||||
|
||||
binding.ivPlayerPlayOrPause.setOnClickListener {
|
||||
mediaController?.let {
|
||||
if (it.playWhenReady) {
|
||||
it.pause()
|
||||
} else {
|
||||
it.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
Logger.e(throwable, "Failed to connect player service")
|
||||
} finally {
|
||||
mediaControllerFuture = null
|
||||
}
|
||||
},
|
||||
ContextCompat.getMainExecutor(applicationContext)
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateMediaMetadata(metadata: MediaMetadata?) {
|
||||
metadata?.let {
|
||||
binding.tvPlayerTitle.text = it.title
|
||||
binding.tvPlayerNickname.text = it.artist
|
||||
|
||||
binding.ivPlayerCover.load(it.artworkUri) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(RoundedCornersTransformation(4f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMediaController() {
|
||||
if (mediaController == null) {
|
||||
deInitMiniPlayer()
|
||||
return
|
||||
}
|
||||
|
||||
mediaController!!.addListener(object : Player.Listener {
|
||||
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||
updateMediaMetadata(mediaItem?.mediaMetadata)
|
||||
}
|
||||
|
||||
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
|
||||
binding.ivPlayerPlayOrPause.setImageResource(
|
||||
if (playWhenReady) {
|
||||
R.drawable.ic_player_pause
|
||||
} else {
|
||||
R.drawable.ic_player_play
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun deInitMiniPlayer() {
|
||||
handler.removeCallbacks(showMiniPlayerRunnable)
|
||||
binding.clMiniPlayer.visibility = View.GONE
|
||||
mediaControllerFuture?.cancel(true)
|
||||
mediaControllerFuture = null
|
||||
mediaController?.release()
|
||||
mediaController = null
|
||||
}
|
||||
|
||||
private fun showPlayerFragment() {
|
||||
val playerFragment = AudioContentPlayerFragment(screenWidth, arrayListOf())
|
||||
playerFragment.show(supportFragmentManager, playerFragment.tag)
|
||||
}
|
||||
|
||||
private fun checkPermissions() {
|
||||
val permissions = mutableListOf(Manifest.permission.RECORD_AUDIO)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
permissions.add(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
|
||||
TedPermission.create()
|
||||
.setPermissionListener(object : PermissionListener {
|
||||
override fun onPermissionGranted() {
|
||||
}
|
||||
|
||||
override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {
|
||||
}
|
||||
})
|
||||
.setDeniedMessage(R.string.record_audio_permission_denied_message)
|
||||
.setPermissions(*permissions.toTypedArray())
|
||||
.check()
|
||||
}
|
||||
|
||||
private fun trackAppLaunchIfNeeded() {
|
||||
handler.postDelayed({
|
||||
val alreadyTrackingAppLaunch = SharedPreferenceManager.alreadyTrackingAppLaunch
|
||||
val pid = SharedPreferenceManager.marketingPid
|
||||
|
||||
if (!alreadyTrackingAppLaunch && pid.isNotBlank()) {
|
||||
SharedPreferenceManager.alreadyTrackingAppLaunch = true
|
||||
viewModel.adTrackingAppLaunch(pid = pid)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
private fun pushTokenUpdate() {
|
||||
FirebaseMessaging.getInstance().token.addOnCompleteListener {
|
||||
if (!it.isSuccessful) {
|
||||
Logger.v("Fetching FCM registration token failed", it.exception)
|
||||
return@addOnCompleteListener
|
||||
}
|
||||
|
||||
val pushToken = it.result
|
||||
if (pushToken != null) {
|
||||
SharedPreferenceManager.pushToken = pushToken
|
||||
if (isLoggedIn()) {
|
||||
viewModel.pushTokenUpdate(pushToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePidAndGaid() {
|
||||
handler.postDelayed({
|
||||
viewModel.fetchAndUpdateGaidAndPid(context = applicationContext)
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
private fun getMemberInfo() {
|
||||
if (isLoggedIn()) {
|
||||
viewModel.getMemberInfo(context = applicationContext) {
|
||||
notificationSettingsDialog.show(screenWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getEventPopup() {
|
||||
viewModel.getEventPopup {
|
||||
if (SharedPreferenceManager.notShowingEventPopupId != it.id) {
|
||||
EventPopupDialogFragment(
|
||||
screenWidth = screenWidth,
|
||||
eventItem = it
|
||||
) {
|
||||
startActivity(
|
||||
Intent(applicationContext, EventDetailActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_EVENT, it)
|
||||
}
|
||||
)
|
||||
}.show(supportFragmentManager, EventPopupDialogFragment::class.java.simpleName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeDeeplink(intent: Intent) {
|
||||
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA) ?: return
|
||||
val deepLinkUrl = bundle.getString("deep_link")
|
||||
val routeBundle = if (!deepLinkUrl.isNullOrBlank()) {
|
||||
buildBundleFromDeepLinkUrl(deepLinkUrl) ?: bundle
|
||||
} else {
|
||||
bundle
|
||||
}
|
||||
|
||||
if (executeBundleRoute(routeBundle)) {
|
||||
clearDeferredDeepLink()
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildBundleFromDeepLinkUrl(deepLinkUrl: String): Bundle? {
|
||||
val data = runCatching { deepLinkUrl.toUri() }.getOrNull() ?: return null
|
||||
val extras = Bundle().apply {
|
||||
putString("deep_link", deepLinkUrl)
|
||||
}
|
||||
|
||||
fun putQuery(key: String) {
|
||||
val value = data.getQueryParameter(key)
|
||||
if (!value.isNullOrBlank()) {
|
||||
extras.putString(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
putQuery("channel_id")
|
||||
putQuery("message_id")
|
||||
putQuery("audition_id")
|
||||
putQuery("content_id")
|
||||
putQuery("deep_link_value")
|
||||
putQuery("deep_link_sub5")
|
||||
putQuery(Constants.EXTRA_COMMUNITY_CREATOR_ID)
|
||||
putQuery(Constants.EXTRA_COMMUNITY_POST_ID)
|
||||
|
||||
applyPathDeepLink(data = data) { key, value ->
|
||||
if (!value.isNullOrBlank() && !extras.containsKey(key)) {
|
||||
extras.putString(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
return extras
|
||||
}
|
||||
|
||||
private fun applyPathDeepLink(
|
||||
data: android.net.Uri,
|
||||
putIfAbsent: (key: String, value: String?) -> Unit
|
||||
) {
|
||||
val host = data.host?.lowercase(Locale.ROOT).orEmpty()
|
||||
val pathSegments = data.pathSegments.filter { it.isNotBlank() }
|
||||
val pathType: String
|
||||
val pathId: String?
|
||||
|
||||
if (host.isNotBlank() && host != "payverse") {
|
||||
pathType = host
|
||||
pathId = pathSegments.firstOrNull()
|
||||
} else if (pathSegments.isNotEmpty()) {
|
||||
pathType = pathSegments[0].lowercase(Locale.ROOT)
|
||||
pathId = pathSegments.getOrNull(1)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
when (pathType) {
|
||||
"content" -> {
|
||||
putIfAbsent("content_id", pathId)
|
||||
putIfAbsent("deep_link_value", "content")
|
||||
putIfAbsent("deep_link_sub5", pathId)
|
||||
}
|
||||
|
||||
"series" -> {
|
||||
putIfAbsent("deep_link_value", "series")
|
||||
putIfAbsent("deep_link_sub5", pathId)
|
||||
}
|
||||
|
||||
"community" -> {
|
||||
putIfAbsent("deep_link_value", "community")
|
||||
putIfAbsent(Constants.EXTRA_COMMUNITY_CREATOR_ID, pathId)
|
||||
putIfAbsent("deep_link_sub5", pathId)
|
||||
}
|
||||
|
||||
"message" -> {
|
||||
putIfAbsent("deep_link_value", "message")
|
||||
putIfAbsent("message_id", pathId)
|
||||
putIfAbsent("deep_link_sub5", pathId)
|
||||
}
|
||||
|
||||
"audition" -> {
|
||||
putIfAbsent("deep_link_value", "audition")
|
||||
putIfAbsent("audition_id", pathId)
|
||||
putIfAbsent("deep_link_sub5", pathId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeBundleRoute(bundle: Bundle): Boolean {
|
||||
val channelId = bundle.getString("channel_id")?.toLongOrNull()
|
||||
?: bundle.getLong(Constants.EXTRA_USER_ID).takeIf { it > 0 }
|
||||
val messageId = bundle.getString("message_id")?.toLongOrNull()
|
||||
?: bundle.getLong(Constants.EXTRA_MESSAGE_ID).takeIf { it > 0 }
|
||||
val contentId = bundle.getString("content_id")?.toLongOrNull()
|
||||
?: bundle.getLong(Constants.EXTRA_AUDIO_CONTENT_ID).takeIf { it > 0 }
|
||||
val auditionId = bundle.getString("audition_id")?.toLongOrNull()
|
||||
?: bundle.getLong(Constants.EXTRA_AUDITION_ID).takeIf { it > 0 }
|
||||
val communityCreatorId = bundle.getString(Constants.EXTRA_COMMUNITY_CREATOR_ID)?.toLongOrNull()
|
||||
?: bundle.getLong(Constants.EXTRA_COMMUNITY_CREATOR_ID).takeIf { it > 0 }
|
||||
val communityPostId = bundle.getString(Constants.EXTRA_COMMUNITY_POST_ID)?.toLongOrNull()
|
||||
?: bundle.getLong(Constants.EXTRA_COMMUNITY_POST_ID).takeIf { it > 0 }
|
||||
|
||||
when {
|
||||
channelId != null && channelId > 0 -> {
|
||||
startActivity(
|
||||
Intent(applicationContext, UserProfileActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_USER_ID, channelId)
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
contentId != null && contentId > 0 -> {
|
||||
startActivity(
|
||||
Intent(applicationContext, AudioContentDetailActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId)
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
messageId != null && messageId > 0 -> {
|
||||
startActivity(Intent(applicationContext, MessageActivity::class.java))
|
||||
return true
|
||||
}
|
||||
|
||||
communityCreatorId != null && communityCreatorId > 0 -> {
|
||||
startActivity(
|
||||
Intent(applicationContext, CreatorCommunityAllActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, communityCreatorId)
|
||||
if (communityPostId != null && communityPostId > 0) {
|
||||
putExtra(Constants.EXTRA_COMMUNITY_POST_ID, communityPostId)
|
||||
}
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
auditionId != null && auditionId > 0 -> {
|
||||
startActivity(Intent(applicationContext, AuditionActivity::class.java))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
val deepLinkValue = bundle.getString("deep_link_value")
|
||||
val deepLinkValueId = bundle.getString("deep_link_sub5")?.toLongOrNull()
|
||||
return !deepLinkValue.isNullOrBlank() && routeByDeepLinkValue(deepLinkValue, deepLinkValueId)
|
||||
}
|
||||
|
||||
private fun routeByDeepLinkValue(deepLinkValue: String, deepLinkValueId: Long?): Boolean {
|
||||
return when (deepLinkValue.lowercase(Locale.ROOT)) {
|
||||
"series" -> {
|
||||
if (deepLinkValueId == null || deepLinkValueId <= 0) {
|
||||
return false
|
||||
}
|
||||
startActivity(
|
||||
Intent(applicationContext, SeriesDetailActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_SERIES_ID, deepLinkValueId)
|
||||
}
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
"content" -> {
|
||||
if (deepLinkValueId == null || deepLinkValueId <= 0) {
|
||||
return false
|
||||
}
|
||||
startActivity(
|
||||
Intent(applicationContext, AudioContentDetailActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, deepLinkValueId)
|
||||
}
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
"channel" -> {
|
||||
if (deepLinkValueId == null || deepLinkValueId <= 0) {
|
||||
return false
|
||||
}
|
||||
startActivity(
|
||||
Intent(applicationContext, UserProfileActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_USER_ID, deepLinkValueId)
|
||||
}
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
"community" -> {
|
||||
if (deepLinkValueId == null || deepLinkValueId <= 0) {
|
||||
return false
|
||||
}
|
||||
startActivity(
|
||||
Intent(applicationContext, CreatorCommunityAllActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, deepLinkValueId)
|
||||
}
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
"message" -> {
|
||||
startActivity(Intent(applicationContext, MessageActivity::class.java))
|
||||
true
|
||||
}
|
||||
|
||||
"audition" -> {
|
||||
startActivity(Intent(applicationContext, AuditionActivity::class.java))
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearDeferredDeepLink() {
|
||||
SharedPreferenceManager.marketingUtmSource = ""
|
||||
SharedPreferenceManager.marketingUtmMedium = ""
|
||||
SharedPreferenceManager.marketingUtmCampaign = ""
|
||||
SharedPreferenceManager.marketingLinkValue = ""
|
||||
SharedPreferenceManager.marketingLinkValueId = 0
|
||||
}
|
||||
|
||||
private fun isLoggedIn(): Boolean {
|
||||
return SharedPreferenceManager.token.isNotBlank() && SharedPreferenceManager.token.length > 10
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.v2.main
|
||||
|
||||
enum class MainV2Tab {
|
||||
HOME,
|
||||
CONTENT,
|
||||
CHAT,
|
||||
MY
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
package kr.co.vividnext.sodalive.v2.main
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.google.android.gms.ads.identifier.AdvertisingIdClient
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.AddAllPlaybackTrackingRequest
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.PlaybackTrackingData
|
||||
import kr.co.vividnext.sodalive.audio_content.PlaybackTrackingRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.main.MarketingInfoUpdateRequest
|
||||
import kr.co.vividnext.sodalive.main.PushTokenUpdateRequest
|
||||
import kr.co.vividnext.sodalive.settings.ContentType
|
||||
import kr.co.vividnext.sodalive.settings.event.EventItem
|
||||
import kr.co.vividnext.sodalive.settings.event.EventRepository
|
||||
import kr.co.vividnext.sodalive.settings.notification.UpdateNotificationSettingRequest
|
||||
import kr.co.vividnext.sodalive.tracking.AdTrackingRepository
|
||||
import kr.co.vividnext.sodalive.tracking.FirebaseTracking
|
||||
import kr.co.vividnext.sodalive.tracking.NotiflyClient
|
||||
import kr.co.vividnext.sodalive.user.UserRepository
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class MainV2ViewModel(
|
||||
private val userRepository: UserRepository,
|
||||
private val eventRepository: EventRepository,
|
||||
private val adTrackingRepository: AdTrackingRepository,
|
||||
private val audioContentRepository: AudioContentRepository,
|
||||
private val playbackTrackingRepository: PlaybackTrackingRepository
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val _currentTab = MutableLiveData(MainV2Tab.HOME)
|
||||
val currentTab: LiveData<MainV2Tab>
|
||||
get() = _currentTab
|
||||
|
||||
fun clickTab(tab: MainV2Tab) {
|
||||
if (_currentTab.value != tab) {
|
||||
_currentTab.postValue(tab)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateNotificationSettings(
|
||||
isNotifiedLive: Boolean,
|
||||
isNotifiedUploadContent: Boolean,
|
||||
isNotifiedMessage: Boolean
|
||||
) {
|
||||
compositeDisposable.add(
|
||||
userRepository.updateNotificationSettings(
|
||||
request = UpdateNotificationSettingRequest(
|
||||
isNotifiedLive,
|
||||
isNotifiedUploadContent,
|
||||
isNotifiedMessage
|
||||
),
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({}, {})
|
||||
)
|
||||
}
|
||||
|
||||
fun pushTokenUpdate(pushToken: String) {
|
||||
compositeDisposable.add(
|
||||
userRepository
|
||||
.updatePushToken(
|
||||
PushTokenUpdateRequest(pushToken = pushToken),
|
||||
"Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({}, {})
|
||||
)
|
||||
}
|
||||
|
||||
fun getMemberInfo(context: Context, showNotificationSettingsDialog: () -> Unit) {
|
||||
compositeDisposable.add(
|
||||
userRepository.getMemberInfo(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
val data = it.data
|
||||
SharedPreferenceManager.can = data.can
|
||||
SharedPreferenceManager.point = data.point
|
||||
SharedPreferenceManager.role = data.role.name
|
||||
SharedPreferenceManager.isAuth = data.isAuth
|
||||
|
||||
val localCountryCode = SharedPreferenceManager.countryCode.ifBlank { "KR" }
|
||||
val resolvedCountryCode = data.countryCode?.ifBlank { "KR" } ?: localCountryCode
|
||||
val resolvedIsAdultContentVisible =
|
||||
data.isAdultContentVisible ?: SharedPreferenceManager.isAdultContentVisible
|
||||
val resolvedContentType =
|
||||
data.contentType
|
||||
?: ContentType.entries.getOrNull(SharedPreferenceManager.contentPreference)
|
||||
?: ContentType.ALL
|
||||
|
||||
SharedPreferenceManager.countryCode = resolvedCountryCode
|
||||
SharedPreferenceManager.isAdultContentVisible = resolvedIsAdultContentVisible
|
||||
SharedPreferenceManager.contentPreference = resolvedContentType.ordinal
|
||||
SharedPreferenceManager.isAuditionNotification =
|
||||
data.auditionNotice ?: false
|
||||
if (
|
||||
data.followingChannelUploadContentNotice == null &&
|
||||
data.followingChannelLiveNotice == null &&
|
||||
data.messageNotice == null
|
||||
) {
|
||||
showNotificationSettingsDialog()
|
||||
}
|
||||
|
||||
val dateFormat = SimpleDateFormat(
|
||||
"yyyy-MM-dd, HH:mm:ss",
|
||||
Locale.getDefault()
|
||||
)
|
||||
val lastActiveDate = dateFormat.format(Date())
|
||||
|
||||
val params = mutableMapOf(
|
||||
"nickname" to SharedPreferenceManager.nickname,
|
||||
"last_active_date" to lastActiveDate,
|
||||
"charge_count" to data.chargeCount,
|
||||
"signup_date" to data.signupDate,
|
||||
"is_auth" to data.isAuth,
|
||||
"gender" to data.gender,
|
||||
"can" to data.can
|
||||
)
|
||||
|
||||
NotiflyClient.setUser(
|
||||
context = context,
|
||||
userId = SharedPreferenceManager.userId,
|
||||
params = params
|
||||
)
|
||||
FirebaseTracking.login("email")
|
||||
}
|
||||
},
|
||||
{}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun addAllPlaybackTracking() {
|
||||
val trackingDataList = playbackTrackingRepository.getAllPlaybackTracking()
|
||||
.filter { it.endPosition != null }
|
||||
.filter { it.endPosition!! - it.startPosition >= 4000 }
|
||||
.map {
|
||||
PlaybackTrackingData(it.contentId, it.playDateTime, it.isPreview)
|
||||
}
|
||||
|
||||
if (trackingDataList.isNotEmpty()) {
|
||||
compositeDisposable.add(
|
||||
audioContentRepository.addAllPlaybackTracking(
|
||||
request = AddAllPlaybackTrackingRequest(trackingDataList = trackingDataList),
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success) {
|
||||
playbackTrackingRepository.removeAllPlaybackTracking()
|
||||
}
|
||||
},
|
||||
{}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getEventPopup(onSuccess: (EventItem) -> Unit) {
|
||||
compositeDisposable.add(
|
||||
eventRepository.getEventPopup(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
onSuccess(it.data)
|
||||
}
|
||||
},
|
||||
{}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun fetchAndUpdateGaidAndPid(context: Context) {
|
||||
Executors.newSingleThreadExecutor().execute {
|
||||
try {
|
||||
val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)
|
||||
val request = MarketingInfoUpdateRequest(
|
||||
adid = adInfo.id.orEmpty(),
|
||||
pid = SharedPreferenceManager.marketingPid
|
||||
)
|
||||
updateMarketingInfo(request)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
updateMarketingInfo(
|
||||
MarketingInfoUpdateRequest(
|
||||
adid = "",
|
||||
pid = SharedPreferenceManager.marketingPid
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun adTrackingAppLaunch(pid: String) {
|
||||
compositeDisposable.add(
|
||||
adTrackingRepository.appLaunch(pid)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({}, {})
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateMarketingInfo(request: MarketingInfoUpdateRequest) {
|
||||
compositeDisposable.add(
|
||||
userRepository.updateMarketingInfo(
|
||||
request,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({}, {})
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/white" android:state_checked="true" />
|
||||
<item android:color="@color/white" android:state_selected="true" />
|
||||
<item android:color="@color/gray_600" />
|
||||
</selector>
|
||||
BIN
app/src/main/res/drawable-mdpi/ic_nav_chat.png
Normal file
|
After Width: | Height: | Size: 602 B |
BIN
app/src/main/res/drawable-mdpi/ic_nav_chat_selected.png
Normal file
|
After Width: | Height: | Size: 446 B |
BIN
app/src/main/res/drawable-mdpi/ic_nav_content.png
Normal file
|
After Width: | Height: | Size: 537 B |
BIN
app/src/main/res/drawable-mdpi/ic_nav_content_selected.png
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
app/src/main/res/drawable-mdpi/ic_nav_home.png
Normal file
|
After Width: | Height: | Size: 564 B |
BIN
app/src/main/res/drawable-mdpi/ic_nav_home_selected.png
Normal file
|
After Width: | Height: | Size: 408 B |
BIN
app/src/main/res/drawable-mdpi/ic_nav_my.png
Normal file
|
After Width: | Height: | Size: 723 B |
5
app/src/main/res/drawable/ic_nav_chat_tab.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_nav_chat_selected" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/ic_nav_chat" />
|
||||
</selector>
|
||||
5
app/src/main/res/drawable/ic_nav_content_tab.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_nav_content_selected" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/ic_nav_content" />
|
||||
</selector>
|
||||
5
app/src/main/res/drawable/ic_nav_home_tab.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_nav_home_selected" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/ic_nav_home" />
|
||||
</selector>
|
||||
5
app/src/main/res/drawable/ic_nav_my_tab.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_tabbar_my_selected" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/ic_nav_my" />
|
||||
</selector>
|
||||
108
app/src/main/res/layout/activity_main_v2.xml
Normal file
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/cl_mini_player"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/cl_mini_player"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/color_222222"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="10.7dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottom_navigation"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_player_cover"
|
||||
android:layout_width="36.7dp"
|
||||
android:layout_height="36.7dp"
|
||||
android:contentDescription="@null"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@mipmap/ic_launcher" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_player_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10.7dp"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="@font/medium"
|
||||
android:maxLines="2"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/iv_player_play_or_pause"
|
||||
app:layout_constraintStart_toEndOf="@+id/iv_player_cover"
|
||||
app:layout_constraintTop_toTopOf="@+id/iv_player_cover"
|
||||
tools:text="JFLA 커버곡 Avicii for your self" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_player_nickname"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2.3dp"
|
||||
android:fontFamily="@font/medium"
|
||||
android:textColor="@color/color_d2d2d2"
|
||||
android:textSize="11sp"
|
||||
app:layout_constraintEnd_toEndOf="@+id/tv_player_title"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_player_title"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_player_title"
|
||||
tools:ignore="SmallSp"
|
||||
tools:text="JFLA 커버곡 Avicii for your self" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_player_play_or_pause"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:contentDescription="@null"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/iv_player_stop"
|
||||
app:layout_constraintEnd_toStartOf="@+id/iv_player_stop"
|
||||
app:layout_constraintTop_toTopOf="@+id/iv_player_stop"
|
||||
tools:src="@drawable/btn_bar_play" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_player_stop"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_noti_stop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bottom_navigation"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/black"
|
||||
app:itemActiveIndicatorStyle="@null"
|
||||
app:itemIconTint="@null"
|
||||
app:itemTextAppearanceActive="@style/Typography.Caption3"
|
||||
app:itemTextAppearanceActiveBoldEnabled="false"
|
||||
app:itemTextAppearanceInactive="@style/Typography.Caption3"
|
||||
app:itemTextColor="@color/color_main_v2_bottom_navigation_label"
|
||||
app:labelVisibilityMode="labeled"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:menu="@menu/menu_main_v2_bottom_navigation" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -2,6 +2,7 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/black"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
|
||||
5
app/src/main/res/layout/fragment_v2_main_chat.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black" />
|
||||
5
app/src/main/res/layout/fragment_v2_main_content.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black" />
|
||||
5
app/src/main/res/layout/fragment_v2_main_home.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black" />
|
||||
19
app/src/main/res/menu/menu_main_v2_bottom_navigation.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/menu_main_v2_home"
|
||||
android:icon="@drawable/ic_nav_home_tab"
|
||||
android:title="@string/tab_home" />
|
||||
<item
|
||||
android:id="@+id/menu_main_v2_content"
|
||||
android:icon="@drawable/ic_nav_content_tab"
|
||||
android:title="@string/tab_content" />
|
||||
<item
|
||||
android:id="@+id/menu_main_v2_chat"
|
||||
android:icon="@drawable/ic_nav_chat_tab"
|
||||
android:title="@string/tab_chat" />
|
||||
<item
|
||||
android:id="@+id/menu_main_v2_my"
|
||||
android:icon="@drawable/ic_nav_my_tab"
|
||||
android:title="@string/tab_my" />
|
||||
</menu>
|
||||
@@ -137,6 +137,7 @@
|
||||
|
||||
<!-- Main / Home -->
|
||||
<string name="tab_home">Home</string>
|
||||
<string name="tab_content">Content</string>
|
||||
<string name="tab_chat">Chat</string>
|
||||
<string name="tab_live">Live</string>
|
||||
<string name="tab_my">My</string>
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
|
||||
<!-- Main / Home -->
|
||||
<string name="tab_home">ホーム</string>
|
||||
<string name="tab_content">コンテンツ</string>
|
||||
<string name="tab_chat">チャット</string>
|
||||
<string name="tab_live">ライブ</string>
|
||||
<string name="tab_my">マイ</string>
|
||||
|
||||
@@ -136,6 +136,7 @@
|
||||
|
||||
<!-- Main / Home -->
|
||||
<string name="tab_home">홈</string>
|
||||
<string name="tab_content">콘텐츠</string>
|
||||
<string name="tab_chat">채팅</string>
|
||||
<string name="tab_live">라이브</string>
|
||||
<string name="tab_my">마이</string>
|
||||
|
||||