From 29595670af72a4a74bc551ea945f61e0a033472b Mon Sep 17 00:00:00 2001 From: klaus Date: Fri, 13 Dec 2024 22:26:48 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A9=94=EC=9D=B8=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=20-=20=ED=95=98=EB=8B=A8=EC=97=90=20=EB=AF=B8=EB=8B=88=20?= =?UTF-8?q?=ED=94=8C=EB=A0=88=EC=9D=B4=EC=96=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../player/AudioContentPlayerFragment.kt | 9 ++ .../player/AudioContentPlayerService.kt | 3 +- .../player/AudioContentPlayerViewModel.kt | 8 +- .../AudioContentPlaylistDetailActivity.kt | 37 +++-- .../java/kr/co/vividnext/sodalive/di/AppDI.kt | 2 +- .../vividnext/sodalive/live/LiveFragment.kt | 1 + .../live/now/all/LiveNowAllActivity.kt | 2 +- .../vividnext/sodalive/main/MainActivity.kt | 135 ++++++++++++++++++ .../sodalive/settings/SettingsActivity.kt | 2 +- app/src/main/res/layout/activity_main.xml | 70 +++++++++ 10 files changed, 246 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerFragment.kt index e7386df..0bab0c6 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerFragment.kt @@ -139,6 +139,7 @@ class AudioContentPlayerFragment( } private fun startPlayerService(context: Context) { + Toast.makeText(requireContext(), "startPlayerService", Toast.LENGTH_LONG).show() val serviceIntent = Intent(context, AudioContentPlayerService::class.java) context.startService(serviceIntent) } @@ -232,6 +233,14 @@ class AudioContentPlayerFragment( } private fun updatePlayerUI() { + binding.ivPlayOrPause.setImageResource( + if (mediaController!!.isPlaying) { + R.drawable.ic_player_pause + } else { + R.drawable.ic_player_play + } + ) + binding.ivPlayOrPause.setOnClickListener { mediaController?.let { if (it.playWhenReady) { diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerService.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerService.kt index 55281f0..59b3615 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerService.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerService.kt @@ -47,8 +47,6 @@ class AudioContentPlayerService : MediaSessionService() { super.onCreate() try { - SharedPreferenceManager.isPlayerServiceRunning = true - initPlayer() initMediaSession() } catch (e: Exception) { @@ -121,6 +119,7 @@ class AudioContentPlayerService : MediaSessionService() { session: MediaSession, controller: MediaSession.ControllerInfo ): MediaSession.ConnectionResult { + SharedPreferenceManager.isPlayerServiceRunning = true val allowedCommands = MediaSession.ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(SessionCommand("UPDATE_PLAYLIST", Bundle.EMPTY)) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerViewModel.kt index ddf5d7b..88cd254 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerViewModel.kt @@ -2,15 +2,9 @@ package kr.co.vividnext.sodalive.audio_content.player import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.orhanobut.logger.Logger -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.schedulers.Schedulers import kr.co.vividnext.sodalive.base.BaseViewModel -import kr.co.vividnext.sodalive.common.SharedPreferenceManager -class AudioContentPlayerViewModel( - private val repository: AudioContentGenerateUrlRepository -) : BaseViewModel() { +class AudioContentPlayerViewModel : BaseViewModel() { private val _toastLiveData = MutableLiveData() val toastLiveData: LiveData get() = _toastLiveData diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/detail/AudioContentPlaylistDetailActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/detail/AudioContentPlaylistDetailActivity.kt index 1d8c017..899f2f9 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/detail/AudioContentPlaylistDetailActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/detail/AudioContentPlaylistDetailActivity.kt @@ -14,6 +14,7 @@ import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat 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 @@ -73,7 +74,7 @@ class AudioContentPlaylistDetailActivity : BaseActivity(FragmentLiveBinding::inflate) { private val viewModel: LiveViewModel by inject() 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 48ee37d..7ed7daf 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 @@ -28,6 +28,7 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +@UnstableApi class LiveNowAllActivity : BaseActivity( ActivityLiveNowAllBinding::inflate ) { @@ -96,7 +97,6 @@ class LiveNowAllActivity : BaseActivity( } } - @UnstableApi private fun enterLiveRoom(roomId: Long) { startService( Intent(applicationContext, AudioContentPlayService::class.java).apply { diff --git a/app/src/main/java/kr/co/vividnext/sodalive/main/MainActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/main/MainActivity.kt index eb2c06d..db5854b 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/main/MainActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/main/MainActivity.kt @@ -2,9 +2,11 @@ package kr.co.vividnext.sodalive.main import android.Manifest import android.content.BroadcastReceiver +import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.content.SharedPreferences import android.content.res.ColorStateList import android.os.Build import android.os.Bundle @@ -13,6 +15,12 @@ import android.os.Looper import android.view.View import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat +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.firebase.messaging.FirebaseMessaging @@ -23,6 +31,8 @@ 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.audio_content.player.AudioContentPlayerFragment +import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.LoadingDialog @@ -39,6 +49,7 @@ import kr.co.vividnext.sodalive.settings.event.EventDetailActivity import kr.co.vividnext.sodalive.settings.notification.NotificationSettingsDialog import org.koin.android.ext.android.inject +@UnstableApi class MainActivity : BaseActivity(ActivityMainBinding::inflate) { private val viewModel: MainViewModel by inject() @@ -47,9 +58,115 @@ class MainActivity : BaseActivity(ActivityMainBinding::infl private lateinit var loadingDialog: LoadingDialog private lateinit var notificationSettingsDialog: NotificationSettingsDialog + private var mediaController: MediaController? = null private val handler = Handler(Looper.getMainLooper()) private val audioContentReceiver = AudioContentReceiver() + private val preferenceChangeListener = + SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key -> + // 특정 키에 대한 값이 변경될 때 UI 업데이트 + if (key == Constants.PREF_IS_PLAYER_SERVICE_RUNNING) { + handler.postDelayed( + { + if (sharedPreferences.getBoolean(key, false)) { + initAndVisibleMiniPlayer() + } else { + deInitMiniPlayer() + } + }, + 2000 + ) + } + } + + 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() { + val componentName = ComponentName(applicationContext, AudioContentPlayerService::class.java) + val sessionToken = SessionToken(applicationContext, componentName) + val mediaControllerFuture = + MediaController.Builder(applicationContext, sessionToken).buildAsync() + mediaControllerFuture.addListener( + { + mediaController = mediaControllerFuture.get() + setupMediaController() + updateMediaMetadata(mediaController?.mediaMetadata) + + binding.ivPlayerPlayOrPause.setImageResource( + if (mediaController!!.isPlaying) { + R.drawable.ic_player_pause + } else { + R.drawable.ic_player_play + } + ) + + binding.ivPlayerPlayOrPause.setOnClickListener { + mediaController?.let { + if (it.playWhenReady) { + it.pause() + } else { + it.play() + } + } + } + }, + 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() { + binding.clMiniPlayer.visibility = View.GONE + mediaController?.release() + mediaController = null + } + override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) executeDeeplink(intent) @@ -64,9 +181,27 @@ class MainActivity : BaseActivity(ActivityMainBinding::infl getMemberInfo() getEventPopup() + SharedPreferenceManager.registerOnSharedPreferenceChangeListener(preferenceChangeListener) + if (SharedPreferenceManager.isPlayerServiceRunning) { + initAndVisibleMiniPlayer() + } else { + deInitMiniPlayer() + } + handler.postDelayed({ executeDeeplink(intent) }, 500) } + override fun onDestroy() { + deInitMiniPlayer() + SharedPreferenceManager.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener) + super.onDestroy() + } + + private fun showPlayerFragment() { + val playerFragment = AudioContentPlayerFragment(screenWidth, arrayListOf()) + playerFragment.show(supportFragmentManager, playerFragment.tag) + } + override fun onResume() { super.onResume() val intentFilter = IntentFilter(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/settings/SettingsActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/settings/SettingsActivity.kt index 1e39c7c..9bd0040 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/settings/SettingsActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/settings/SettingsActivity.kt @@ -27,6 +27,7 @@ import kr.co.vividnext.sodalive.settings.terms.TermsActivity import kr.co.vividnext.sodalive.splash.SplashActivity import org.koin.android.ext.android.inject +@UnstableApi class SettingsActivity : BaseActivity(ActivitySettingsBinding::inflate) { private val logoutDialog: SodaDialog by lazy { SodaDialog( @@ -159,7 +160,6 @@ class SettingsActivity : BaseActivity(ActivitySettingsB } } - @UnstableApi private fun logout() { startService( Intent(applicationContext, AudioContentPlayService::class.java).apply { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index f3805ac..b2f5dda 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -81,6 +81,76 @@ android:src="@drawable/ic_noti_stop" /> + + + + + + + + + + + + +