2021-11-02 17:45:01 +01:00
|
|
|
/*
|
|
|
|
* NowPlayingFragment.kt
|
|
|
|
* Copyright (C) 2009-2021 Ultrasonic developers
|
|
|
|
*
|
|
|
|
* Distributed under terms of the GNU GPLv3 license.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.moire.ultrasonic.fragment
|
|
|
|
|
|
|
|
import android.annotation.SuppressLint
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.view.MotionEvent
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewGroup
|
|
|
|
import android.widget.ImageView
|
|
|
|
import android.widget.TextView
|
|
|
|
import androidx.fragment.app.Fragment
|
|
|
|
import androidx.navigation.Navigation
|
|
|
|
import io.reactivex.rxjava3.disposables.Disposable
|
|
|
|
import java.lang.Exception
|
|
|
|
import kotlin.math.abs
|
|
|
|
import org.koin.android.ext.android.inject
|
|
|
|
import org.moire.ultrasonic.R
|
|
|
|
import org.moire.ultrasonic.domain.PlayerState
|
|
|
|
import org.moire.ultrasonic.service.MediaPlayerController
|
|
|
|
import org.moire.ultrasonic.service.RxBus
|
|
|
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
|
|
|
import org.moire.ultrasonic.util.Constants
|
|
|
|
import org.moire.ultrasonic.util.Settings
|
|
|
|
import org.moire.ultrasonic.util.Util.applyTheme
|
|
|
|
import org.moire.ultrasonic.util.Util.getDrawableFromAttribute
|
|
|
|
import org.moire.ultrasonic.util.Util.getNotificationImageSize
|
|
|
|
import timber.log.Timber
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Contains the mini-now playing information box displayed at the bottom of the screen
|
|
|
|
*/
|
2021-11-16 17:58:15 +01:00
|
|
|
@Suppress("unused")
|
2021-11-02 17:45:01 +01:00
|
|
|
class NowPlayingFragment : Fragment() {
|
|
|
|
|
|
|
|
private var downX = 0f
|
|
|
|
private var downY = 0f
|
|
|
|
|
|
|
|
private var playButton: ImageView? = null
|
|
|
|
private var nowPlayingAlbumArtImage: ImageView? = null
|
|
|
|
private var nowPlayingTrack: TextView? = null
|
|
|
|
private var nowPlayingArtist: TextView? = null
|
|
|
|
|
|
|
|
private var playerStateSubscription: Disposable? = null
|
|
|
|
private val mediaPlayerController: MediaPlayerController by inject()
|
|
|
|
private val imageLoader: ImageLoaderProvider by inject()
|
|
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
applyTheme(this.context)
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onCreateView(
|
|
|
|
inflater: LayoutInflater,
|
|
|
|
container: ViewGroup?,
|
|
|
|
savedInstanceState: Bundle?
|
|
|
|
): View? {
|
|
|
|
return inflater.inflate(R.layout.now_playing, container, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
|
|
playButton = view.findViewById(R.id.now_playing_control_play)
|
|
|
|
nowPlayingAlbumArtImage = view.findViewById(R.id.now_playing_image)
|
|
|
|
nowPlayingTrack = view.findViewById(R.id.now_playing_trackname)
|
|
|
|
nowPlayingArtist = view.findViewById(R.id.now_playing_artist)
|
|
|
|
playerStateSubscription =
|
|
|
|
RxBus.playerStateObservable.subscribe { update() }
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
|
|
|
update()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onDestroy() {
|
|
|
|
super.onDestroy()
|
|
|
|
playerStateSubscription!!.dispose()
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressLint("ClickableViewAccessibility")
|
|
|
|
private fun update() {
|
|
|
|
try {
|
|
|
|
val playerState = mediaPlayerController.playerState
|
|
|
|
|
|
|
|
if (playerState === PlayerState.PAUSED) {
|
|
|
|
playButton!!.setImageDrawable(
|
|
|
|
getDrawableFromAttribute(
|
2021-11-16 17:58:15 +01:00
|
|
|
requireContext(), R.attr.media_play
|
2021-11-02 17:45:01 +01:00
|
|
|
)
|
|
|
|
)
|
|
|
|
} else if (playerState === PlayerState.STARTED) {
|
|
|
|
playButton!!.setImageDrawable(
|
|
|
|
getDrawableFromAttribute(
|
2021-11-16 17:58:15 +01:00
|
|
|
requireContext(), R.attr.media_pause
|
2021-11-02 17:45:01 +01:00
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
val file = mediaPlayerController.currentPlaying
|
|
|
|
|
|
|
|
if (file != null) {
|
|
|
|
val song = file.song
|
|
|
|
val title = song.title
|
|
|
|
val artist = song.artist
|
|
|
|
|
|
|
|
imageLoader.getImageLoader().loadImage(
|
|
|
|
nowPlayingAlbumArtImage,
|
|
|
|
song,
|
|
|
|
false,
|
|
|
|
getNotificationImageSize(requireContext())
|
|
|
|
)
|
|
|
|
|
|
|
|
nowPlayingTrack!!.text = title
|
|
|
|
nowPlayingArtist!!.text = artist
|
|
|
|
|
|
|
|
nowPlayingAlbumArtImage!!.setOnClickListener {
|
|
|
|
val bundle = Bundle()
|
|
|
|
|
|
|
|
if (Settings.shouldUseId3Tags) {
|
2021-11-30 21:21:50 +01:00
|
|
|
bundle.putBoolean(Constants.INTENT_IS_ALBUM, true)
|
|
|
|
bundle.putString(Constants.INTENT_ID, song.albumId)
|
2021-11-02 17:45:01 +01:00
|
|
|
} else {
|
2021-11-30 21:21:50 +01:00
|
|
|
bundle.putBoolean(Constants.INTENT_IS_ALBUM, false)
|
|
|
|
bundle.putString(Constants.INTENT_ID, song.parent)
|
2021-11-02 17:45:01 +01:00
|
|
|
}
|
|
|
|
|
2021-11-30 21:21:50 +01:00
|
|
|
bundle.putString(Constants.INTENT_NAME, song.album)
|
|
|
|
bundle.putString(Constants.INTENT_NAME, song.album)
|
2021-11-02 17:45:01 +01:00
|
|
|
|
|
|
|
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
|
|
|
|
.navigate(R.id.trackCollectionFragment, bundle)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
requireView().setOnTouchListener { _: View?, event: MotionEvent ->
|
|
|
|
handleOnTouch(event)
|
|
|
|
}
|
|
|
|
|
|
|
|
// This empty onClickListener is necessary for the onTouchListener to work
|
|
|
|
requireView().setOnClickListener { }
|
|
|
|
playButton!!.setOnClickListener { mediaPlayerController.togglePlayPause() }
|
|
|
|
} catch (all: Exception) {
|
|
|
|
Timber.w(all, "Failed to get notification cover art")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun handleOnTouch(event: MotionEvent): Boolean {
|
|
|
|
when (event.action) {
|
|
|
|
MotionEvent.ACTION_DOWN -> {
|
|
|
|
downX = event.x
|
|
|
|
downY = event.y
|
|
|
|
}
|
|
|
|
|
|
|
|
MotionEvent.ACTION_UP -> {
|
|
|
|
val upX = event.x
|
|
|
|
val upY = event.y
|
|
|
|
val deltaX = downX - upX
|
|
|
|
val deltaY = downY - upY
|
|
|
|
|
|
|
|
if (abs(deltaX) > MIN_DISTANCE) {
|
|
|
|
// left or right
|
|
|
|
if (deltaX < 0) {
|
|
|
|
mediaPlayerController.previous()
|
|
|
|
}
|
|
|
|
if (deltaX > 0) {
|
|
|
|
mediaPlayerController.next()
|
|
|
|
}
|
|
|
|
} else if (abs(deltaY) > MIN_DISTANCE) {
|
|
|
|
if (deltaY < 0) {
|
|
|
|
RxBus.dismissNowPlayingCommandPublisher.onNext(Unit)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
|
|
|
|
.navigate(R.id.playerFragment)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
private const val MIN_DISTANCE = 30
|
|
|
|
}
|
|
|
|
}
|