Skip to content

Commit

Permalink
Merge pull request #3335 from Bnyro/audio-mini-player
Browse files Browse the repository at this point in the history
Audio mini player
  • Loading branch information
Bnyro authored Mar 21, 2023
2 parents 2cba327 + 5b97c01 commit a5f44c4
Show file tree
Hide file tree
Showing 8 changed files with 387 additions and 205 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.enums.PlaylistType
import com.github.libretube.extensions.toID
import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.fragments.AudioPlayerFragment
import com.github.libretube.ui.fragments.PlayerFragment
import com.github.libretube.ui.views.SingleViewTouchableMotionLayout

Expand Down Expand Up @@ -117,7 +118,9 @@ object NavigationHelper {
*/
fun startAudioPlayer(context: Context) {
val activity = unwrap(context)
activity.navController.navigate(R.id.audioPlayerFragment)
activity.supportFragmentManager.commitNow {
replace<AudioPlayerFragment>(R.id.container)
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ class MainActivity : BaseActivity() {
true
}
R.id.action_audio -> {
navController.navigate(R.id.audioPlayerFragment)
NavigationHelper.startAudioPlayer(this)
true
}
else -> super.onOptionsItemSelected(item)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import android.text.format.DateUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.commit
import androidx.navigation.fragment.findNavController
import com.github.libretube.R
import com.github.libretube.api.obj.StreamItem
Expand All @@ -31,14 +34,22 @@ import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.ui.interfaces.AudioPlayerOptions
import com.github.libretube.ui.listeners.AudioPlayerThumbnailListener
import com.github.libretube.ui.models.PlayerViewModel
import com.github.libretube.ui.sheets.PlaybackOptionsSheet
import com.github.libretube.ui.sheets.PlayingQueueSheet
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
import com.github.libretube.util.PlayingQueue
import kotlin.math.abs

class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
private lateinit var binding: FragmentAudioPlayerBinding
private lateinit var audioHelper: AudioHelper
private val mainActivity get() = context as MainActivity
private val viewModel: PlayerViewModel by activityViewModels()

// for the transition
private var sId: Int = 0
private var eId: Int = 0

private val onTrackChangeListener: (StreamItem) -> Unit = {
updateStreamInfo()
Expand All @@ -57,16 +68,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
handleServiceConnection()
}

override fun onServiceDisconnected(arg0: ComponentName) {
val mainActivity = activity as MainActivity
if (mainActivity.navController.currentDestination?.id == R.id.audioPlayerFragment) {
mainActivity.navController.popBackStack()
} else {
mainActivity.navController.backQueue.removeIf {
it.destination.id == R.id.audioPlayerFragment
}
}
}
override fun onServiceDisconnected(arg0: ComponentName) {}
}

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -91,6 +93,8 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

initializeTransitionLayout()

// select the title TV in order for it to automatically scroll
binding.title.isSelected = true
binding.uploader.isSelected = true
Expand Down Expand Up @@ -142,7 +146,13 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
binding.close.setOnClickListener {
activity?.unbindService(connection)
BackgroundHelper.stopBackgroundPlay(requireContext())
findNavController().popBackStack()
killFragment()
}

binding.miniPlayerClose.setOnClickListener {
activity?.unbindService(connection)
BackgroundHelper.stopBackgroundPlay(requireContext())
killFragment()
}

val listener = AudioPlayerThumbnailListener(requireContext(), this)
Expand All @@ -155,6 +165,10 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
if (isPaused) playerService?.play() else playerService?.pause()
}

binding.miniPlayerPause.setOnClickListener {
if (isPaused) playerService?.play() else playerService?.pause()
}

// load the stream info into the UI
updateStreamInfo()

Expand All @@ -164,6 +178,63 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
}
}

private fun killFragment() {
viewModel.isFullscreen.value = false
binding.playerMotionLayout.transitionToEnd()
mainActivity.supportFragmentManager.commit {
remove(this@AudioPlayerFragment)
}

onDestroy()
}

@SuppressLint("ClickableViewAccessibility")
private fun initializeTransitionLayout() {
mainActivity.binding.container.visibility = View.VISIBLE
val mainMotionLayout = mainActivity.binding.mainMotionLayout

binding.playerMotionLayout.addTransitionListener(object : MotionLayout.TransitionListener {
override fun onTransitionStarted(
motionLayout: MotionLayout?,
startId: Int,
endId: Int
) {
}

override fun onTransitionChange(
motionLayout: MotionLayout?,
startId: Int,
endId: Int,
progress: Float
) {
mainMotionLayout.progress = abs(progress)
eId = endId
sId = startId
}

override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
if (currentId == eId) {
viewModel.isMiniPlayerVisible.value = true
mainMotionLayout.progress = 1F
} else if (currentId == sId) {
viewModel.isMiniPlayerVisible.value = false
mainMotionLayout.progress = 0F
}
}

override fun onTransitionTrigger(
MotionLayout: MotionLayout?,
triggerId: Int,
positive: Boolean,
progress: Float
) {
}
})

binding.playerMotionLayout.progress = 1.toFloat()
binding.playerMotionLayout.transitionToStart()
}

/**
* Load the information from a new stream into the UI
*/
Expand All @@ -172,6 +243,8 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
current ?: return

binding.title.text = current.title
binding.miniPlayerTitle.text = current.title

binding.uploader.text = current.uploaderName
binding.uploader.setOnClickListener {
NavigationHelper.navigateChannel(requireContext(), current.uploaderUrl?.toID())
Expand All @@ -188,6 +261,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {

ImageHelper.getAsync(requireContext(), thumbnailUrl) {
binding.thumbnail.setImageBitmap(it)
binding.miniPlayerThumbnail.setImageBitmap(it)
binding.thumbnail.visibility = View.VISIBLE
binding.progress.visibility = View.GONE
}
Expand Down Expand Up @@ -232,9 +306,9 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {

private fun handleServiceConnection() {
playerService?.onIsPlayingChanged = { isPlaying ->
binding.playPause.setIconResource(
if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play
)
val iconResource = if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play
binding.playPause.setIconResource(iconResource)
binding.miniPlayerPause.setImageResource(iconResource)
isPaused = !isPlaying
}
initializeSeekBar()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class SingleViewTouchableMotionLayout(context: Context, attributeSet: AttributeS
MotionLayout(context, attributeSet) {

private val viewToDetectTouch by lazy {
findViewById<View>(R.id.main_container) // TODO move to Attributes
findViewById<View>(R.id.main_container) ?: findViewById(R.id.audio_player_container)
}
private val viewRect = Rect()
private var touchStarted = false
Expand Down
Loading

0 comments on commit a5f44c4

Please sign in to comment.