푸시메시지 터치 액션 추가

This commit is contained in:
klaus 2023-08-09 13:52:26 +09:00
parent 68f2896031
commit bb1e260a4c
8 changed files with 486 additions and 6 deletions

View File

@ -141,7 +141,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { SignUpViewModel(get()) }
viewModel { TermsViewModel(get()) }
viewModel { FindPasswordViewModel(get()) }
viewModel { MainViewModel(get()) }
viewModel { MainViewModel(get(), get(), get(), get()) }
viewModel { LiveViewModel(get(), get(), get()) }
viewModel { MyPageViewModel(get(), get()) }
viewModel { CanStatusViewModel(get()) }

View File

@ -22,6 +22,7 @@ import com.zhpan.indicator.enums.IndicatorSlideMode
import com.zhpan.indicator.enums.IndicatorStyle
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.base.BaseFragment
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
@ -94,6 +95,25 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
message = "라이브를 불러오고 있습니다."
viewModel.getSummary()
try {
val roomId = requireArguments().getLong(Constants.EXTRA_ROOM_ID)
val channelId = requireArguments().getLong(Constants.EXTRA_USER_ID)
val audioContentId = requireArguments().getLong(Constants.EXTRA_AUDIO_CONTENT_ID)
if (roomId > 0) {
enterLiveRoom(roomId)
} else if (channelId > 0) {
val nextIntent = Intent(requireContext(), UserProfileActivity::class.java)
nextIntent.putExtra(Constants.EXTRA_USER_ID, channelId)
startActivity(nextIntent)
} else if (audioContentId > 0) {
val nextIntent = Intent(requireContext(), AudioContentDetailActivity::class.java)
nextIntent.putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId)
startActivity(nextIntent)
}
} catch (_: IllegalStateException) {
}
}
private fun setupView() {

View File

@ -0,0 +1,84 @@
package kr.co.vividnext.sodalive.main
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import coil.load
import coil.transform.RoundedCornersTransformation
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.settings.event.EventItem
class EventPopupDialogFragment(
private val screenWidth: Int,
private val eventItem: EventItem,
private val onClick: () -> Unit
) : BottomSheetDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.setOnShowListener {
val d = it as BottomSheetDialog
val bottomSheet = d.findViewById<FrameLayout>(
com.google.android.material.R.id.design_bottom_sheet
)
if (bottomSheet != null) {
BottomSheetBehavior.from(bottomSheet).state = BottomSheetBehavior.STATE_EXPANDED
}
}
return dialog
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = inflater.inflate(R.layout.fragment_event_popup_dialog, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById<TextView>(R.id.tv_close).setOnClickListener {
dialog?.dismiss()
}
view.findViewById<TextView>(R.id.tv_close_always).setOnClickListener {
SharedPreferenceManager.notShowingEventPopupId = eventItem.id
dialog?.dismiss()
}
val imageView = view.findViewById<ImageView>(R.id.iv_event_popup)
val layoutParams = imageView.layoutParams as LinearLayout.LayoutParams
layoutParams.width = screenWidth
layoutParams.height = screenWidth
imageView.load(eventItem.popupImageUrl) {
crossfade(true)
transformations(
RoundedCornersTransformation(
topLeft = 16.7f.dpToPx(),
topRight = 16.7f.dpToPx(),
bottomLeft = 0f,
bottomRight = 0f
)
)
}
imageView.layoutParams = layoutParams
imageView.setOnClickListener {
dialog?.dismiss()
onClick()
}
}
}

View File

@ -1,26 +1,41 @@
package kr.co.vividnext.sodalive.main
import android.Manifest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.ColorStateList
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.content.res.ResourcesCompat
import coil.load
import coil.transform.RoundedCornersTransformation
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.main.AudioContentMainFragment
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.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ActivityMainBinding
import kr.co.vividnext.sodalive.databinding.ItemMainTabBinding
import kr.co.vividnext.sodalive.explorer.ExplorerFragment
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.live.LiveFragment
import kr.co.vividnext.sodalive.message.MessageFragment
import kr.co.vividnext.sodalive.mypage.MyPageFragment
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
import kr.co.vividnext.sodalive.settings.notification.NotificationSettingsDialog
import org.koin.android.ext.android.inject
@ -32,17 +47,93 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
private lateinit var loadingDialog: LoadingDialog
private lateinit var notificationSettingsDialog: NotificationSettingsDialog
private val handler = Handler(Looper.getMainLooper())
private val audioContentReceiver = AudioContentReceiver()
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA)
if (bundle != null) {
try {
val roomId = bundle.getLong(Constants.EXTRA_ROOM_ID)
val channelId = bundle.getLong(Constants.EXTRA_USER_ID)
val audioContentId = bundle.getLong(Constants.EXTRA_AUDIO_CONTENT_ID)
val isLiveReservation = bundle.getBoolean(Constants.EXTRA_LIVE_RESERVATION_RESPONSE)
if (roomId > 0) {
if (isLiveReservation) {
liveFragment.reservationRoom(roomId)
} else {
handler.postDelayed({
liveFragment.enterLiveRoom(roomId)
}, 500)
}
} else if (channelId > 0) {
val nextIntent = Intent(applicationContext, UserProfileActivity::class.java)
nextIntent.putExtra(Constants.EXTRA_USER_ID, channelId)
startActivity(nextIntent)
} else if (audioContentId > 0) {
val nextIntent = Intent(
applicationContext,
AudioContentDetailActivity::class.java
)
nextIntent.putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId)
startActivity(nextIntent)
}
} catch (_: IllegalStateException) {
}
}
checkReceivedMessage(intent)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkPermissions()
pushTokenUpdate()
getMemberInfo()
getEventPopup()
checkReceivedMessage(intent)
}
override fun onResume() {
super.onResume()
val intentFilter = IntentFilter(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
registerReceiver(audioContentReceiver, intentFilter)
startService(
Intent(this, AudioContentPlayService::class.java).apply {
action = AudioContentPlayService.MusicAction.INIT.name
}
)
}
override fun onPause() {
super.onPause()
unregisterReceiver(audioContentReceiver)
}
private fun checkReceivedMessage(intent: Intent) {
handler.postDelayed({
val messageId =
intent.getBundleExtra(Constants.EXTRA_DATA)?.getLong(Constants.EXTRA_MESSAGE_ID)
if (messageId != null && messageId > 0) {
changeFragment(MainViewModel.CurrentTab.MESSAGE)
setTabSelected(binding.tabSuda, isSelected = false)
setTabSelected(binding.tabExplorer, isSelected = false)
setTabSelected(binding.tabMessage, isSelected = true)
setTabSelected(binding.tabMy, isSelected = false)
}
}, 500)
}
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
liveFragment = LiveFragment()
liveFragment = LiveFragment().apply {
arguments = intent.getBundleExtra(Constants.EXTRA_DATA)
}
notificationSettingsDialog = NotificationSettingsDialog(
this,
@ -245,4 +336,117 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
notificationSettingsDialog.show(screenWidth)
}
}
private fun getEventPopup() {
viewModel.getEventPopup {
if (SharedPreferenceManager.notShowingEventPopupId != it.id) {
val eventPopupDialog = EventPopupDialogFragment(
screenWidth = screenWidth,
eventItem = it
) {
startActivity(
Intent(
applicationContext,
EventDetailActivity::class.java
).apply {
putExtra(Constants.EXTRA_EVENT, it)
}
)
}
eventPopupDialog.show(supportFragmentManager, eventPopupDialog.tag)
}
}
}
inner class AudioContentReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val contentId = intent?.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
val title = intent?.getStringExtra(Constants.EXTRA_AUDIO_CONTENT_TITLE)
val nickname = intent?.getStringExtra(Constants.EXTRA_NICKNAME)
val coverImageUrl = intent?.getStringExtra(
Constants.EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL
)
val isPlaying = intent?.getBooleanExtra(Constants.EXTRA_AUDIO_CONTENT_PLAYING, false)
val isShowing = intent?.getBooleanExtra(Constants.EXTRA_AUDIO_CONTENT_SHOWING, false)
if (isShowing == true) {
binding.rlMiniPlayer.visibility = View.VISIBLE
if (contentId != null && contentId > 0) {
binding.rlMiniPlayer.setOnClickListener {
startActivity(
Intent(applicationContext, AudioContentDetailActivity::class.java)
.apply {
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId)
}
)
}
}
if (isPlaying == true) {
binding.ivPlayOrPause.setImageResource(R.drawable.ic_noti_pause)
binding.ivPlayOrPause.setOnClickListener {
startService(
Intent(
this@MainActivity,
AudioContentPlayService::class.java
).apply {
action = AudioContentPlayService.MusicAction.PAUSE.name
}
)
}
} else {
binding.ivPlayOrPause.setImageResource(R.drawable.ic_noti_play)
binding.ivPlayOrPause.setOnClickListener {
startService(
Intent(
this@MainActivity,
AudioContentPlayService::class.java
).apply {
action = AudioContentPlayService.MusicAction.PLAY.name
}
)
}
}
binding.ivStop.setOnClickListener {
startService(
Intent(
this@MainActivity,
AudioContentPlayService::class.java
).apply {
action = AudioContentPlayService.MusicAction.STOP.name
}
)
}
if (!title.isNullOrBlank()) {
binding.tvTitle.text = title
}
if (!nickname.isNullOrBlank()) {
binding.tvNickname.text = nickname
}
if (!coverImageUrl.isNullOrBlank()) {
binding.ivCover.load(coverImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(5.3f.dpToPx()))
}
}
} else {
handler.post {
binding.ivPlayOrPause.setImageResource(0)
binding.ivCover.setImageResource(0)
binding.tvTitle.text = ""
binding.tvNickname.text = ""
binding.rlMiniPlayer.visibility = View.GONE
binding.ivPlayOrPause.setOnClickListener {}
viewModel.addAllPlaybackTracking()
}
}
}
}
}

View File

@ -5,13 +5,22 @@ import androidx.lifecycle.MutableLiveData
import com.google.gson.annotations.SerializedName
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.settings.event.EventItem
import kr.co.vividnext.sodalive.settings.event.EventRepository
import kr.co.vividnext.sodalive.settings.notification.UpdateNotificationSettingRequest
import kr.co.vividnext.sodalive.user.UserRepository
class MainViewModel(
private val userRepository: UserRepository,
private val eventRepository: EventRepository,
private val audioContentRepository: AudioContentRepository,
private val playbackTrackingRepository: PlaybackTrackingRepository
) : BaseViewModel() {
enum class CurrentTab {
@SerializedName("CONTENT")
@ -99,4 +108,59 @@ class MainViewModel(
)
)
}
fun addAllPlaybackTracking() {
val playbackTrackingList = playbackTrackingRepository.getAllPlaybackTracking()
val trackingDataList = playbackTrackingList
.filter { it.endPosition != null }
.filter {
if (it.isFree) {
// 무료 콘텐츠의 경우
// 러닝타임의 30% 이상 재생된 데이터
it.endPosition!! - it.startPosition > it.totalDuration * 0.3
} else {
// 유료 콘텐츠의 경우
// 러닝타임의 20% 이상 재생된 데이터
it.endPosition!! - it.startPosition > it.totalDuration * 0.2
}
}
.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)
}
},
{}
)
)
}
}

View File

@ -183,8 +183,8 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
startActivity(
Intent(applicationContext, MainActivity::class.java).apply {
putExtra(Constants.EXTRA_DATA, extras)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
)
finish()
@ -196,8 +196,8 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
startActivity(
Intent(applicationContext, LoginActivity::class.java).apply {
putExtra(Constants.EXTRA_DATA, extras)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
)
finish()

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
@ -12,6 +13,73 @@
android:layout_above="@+id/ll_tab"
android:layout_alignParentTop="true" />
<RelativeLayout
android:id="@+id/rl_mini_player"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/ll_tab"
android:background="@color/color_222222"
android:paddingHorizontal="13.3dp"
android:paddingVertical="10.7dp">
<ImageView
android:id="@+id/iv_cover"
android:layout_width="36.7dp"
android:layout_height="36.7dp"
android:layout_centerVertical="true"
android:contentDescription="@null"
tools:src="@drawable/ic_noti" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginHorizontal="10.7dp"
android:layout_toStartOf="@+id/iv_play_or_pause"
android:layout_toEndOf="@+id/iv_cover"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/color_eeeeee"
android:textSize="13sp"
tools:text="JFLA 커버곡 Avicii for your self" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2.3dp"
android:textColor="@color/color_d2d2d2"
android:textSize="11sp"
tools:ignore="SmallSp"
tools:text="JFLA 커버곡 Avicii for your self" />
</LinearLayout>
<ImageView
android:id="@+id/iv_play_or_pause"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_marginEnd="16dp"
android:layout_toStartOf="@+id/iv_stop"
android:contentDescription="@null"
tools:src="@drawable/btn_bar_play" />
<ImageView
android:id="@+id/iv_stop"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/ic_noti_stop" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_tab"
android:layout_width="match_parent"

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_event_popup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:scaleType="centerCrop" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="26.7dp"
android:paddingVertical="13.3dp">
<TextView
android:id="@+id/tv_close_always"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="다시보지 않기"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
<TextView
android:id="@+id/tv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:fontFamily="@font/gmarket_sans_medium"
android:text="닫기"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
</RelativeLayout>
</LinearLayout>