2021-06-19 23:09:38 +02:00
|
|
|
/*
|
|
|
|
* PlayerFragment.kt
|
|
|
|
* Copyright (C) 2009-2021 Ultrasonic developers
|
|
|
|
*
|
|
|
|
* Distributed under terms of the GNU GPLv3 license.
|
|
|
|
*/
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
package org.moire.ultrasonic.fragment
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
import android.annotation.SuppressLint
|
2021-06-19 20:05:38 +02:00
|
|
|
import android.app.AlertDialog
|
|
|
|
import android.graphics.Point
|
|
|
|
import android.graphics.drawable.Drawable
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.os.Handler
|
|
|
|
import android.view.ContextMenu
|
|
|
|
import android.view.ContextMenu.ContextMenuInfo
|
|
|
|
import android.view.GestureDetector
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.view.Menu
|
|
|
|
import android.view.MenuInflater
|
|
|
|
import android.view.MenuItem
|
|
|
|
import android.view.MotionEvent
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewGroup
|
|
|
|
import android.view.WindowManager
|
|
|
|
import android.view.animation.AnimationUtils
|
|
|
|
import android.widget.AdapterView.AdapterContextMenuInfo
|
|
|
|
import android.widget.EditText
|
|
|
|
import android.widget.ImageView
|
|
|
|
import android.widget.LinearLayout
|
|
|
|
import android.widget.SeekBar
|
|
|
|
import android.widget.SeekBar.OnSeekBarChangeListener
|
|
|
|
import android.widget.TextView
|
|
|
|
import android.widget.ViewFlipper
|
2021-10-08 17:34:52 +02:00
|
|
|
import androidx.core.view.isVisible
|
2021-06-19 20:05:38 +02:00
|
|
|
import androidx.fragment.app.Fragment
|
|
|
|
import androidx.navigation.Navigation
|
|
|
|
import com.mobeta.android.dslv.DragSortListView
|
|
|
|
import com.mobeta.android.dslv.DragSortListView.DragSortListener
|
2021-06-19 23:09:38 +02:00
|
|
|
import java.text.DateFormat
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.util.ArrayList
|
|
|
|
import java.util.Date
|
|
|
|
import java.util.LinkedList
|
|
|
|
import java.util.Locale
|
|
|
|
import java.util.concurrent.Executors
|
|
|
|
import java.util.concurrent.ScheduledExecutorService
|
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
import kotlin.math.abs
|
|
|
|
import kotlin.math.max
|
|
|
|
import org.koin.android.ext.android.inject
|
|
|
|
import org.koin.core.component.KoinComponent
|
|
|
|
import org.koin.core.component.get
|
2021-06-19 20:05:38 +02:00
|
|
|
import org.moire.ultrasonic.R
|
|
|
|
import org.moire.ultrasonic.audiofx.EqualizerController
|
|
|
|
import org.moire.ultrasonic.audiofx.VisualizerController
|
|
|
|
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
|
|
|
import org.moire.ultrasonic.domain.MusicDirectory
|
|
|
|
import org.moire.ultrasonic.domain.PlayerState
|
|
|
|
import org.moire.ultrasonic.domain.RepeatMode
|
|
|
|
import org.moire.ultrasonic.featureflags.Feature
|
|
|
|
import org.moire.ultrasonic.featureflags.FeatureStorage
|
|
|
|
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
|
|
|
import org.moire.ultrasonic.service.DownloadFile
|
2021-06-19 23:09:38 +02:00
|
|
|
import org.moire.ultrasonic.service.LocalMediaPlayer
|
2021-06-19 20:05:38 +02:00
|
|
|
import org.moire.ultrasonic.service.MediaPlayerController
|
|
|
|
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
|
|
|
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
|
|
|
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
|
|
|
|
import org.moire.ultrasonic.subsonic.ShareHandler
|
|
|
|
import org.moire.ultrasonic.util.CancellationToken
|
|
|
|
import org.moire.ultrasonic.util.Constants
|
2021-09-24 18:20:53 +02:00
|
|
|
import org.moire.ultrasonic.util.Settings
|
2021-06-19 23:09:38 +02:00
|
|
|
import org.moire.ultrasonic.util.SilentBackgroundTask
|
2021-06-19 20:05:38 +02:00
|
|
|
import org.moire.ultrasonic.util.Util
|
|
|
|
import org.moire.ultrasonic.view.AutoRepeatButton
|
|
|
|
import org.moire.ultrasonic.view.SongListAdapter
|
|
|
|
import org.moire.ultrasonic.view.VisualizerView
|
|
|
|
import timber.log.Timber
|
2021-02-05 21:45:50 +01:00
|
|
|
|
2021-02-25 18:40:41 +01:00
|
|
|
/**
|
|
|
|
* Contains the Music Player screen of Ultrasonic with playback controls and the playlist
|
2021-06-19 23:09:38 +02:00
|
|
|
*
|
|
|
|
* TODO: This class was more or less straight converted from Java legacy code.
|
|
|
|
* There are many places where further cleanup would be nice.
|
|
|
|
* The usage of threads and SilentBackgroundTask can be replaced with Coroutines.
|
2021-02-25 18:40:41 +01:00
|
|
|
*/
|
2021-06-19 20:42:03 +02:00
|
|
|
@Suppress("LargeClass", "TooManyFunctions", "MagicNumber")
|
|
|
|
class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinComponent {
|
|
|
|
// Settings
|
2021-06-19 20:05:38 +02:00
|
|
|
private var currentRevision: Long = 0
|
|
|
|
private var swipeDistance = 0
|
|
|
|
private var swipeVelocity = 0
|
|
|
|
private var jukeboxAvailable = false
|
|
|
|
private var useFiveStarRating = false
|
|
|
|
private var isEqualizerAvailable = false
|
|
|
|
private var isVisualizerAvailable = false
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
// Detectors & Callbacks
|
|
|
|
private lateinit var gestureScanner: GestureDetector
|
|
|
|
private lateinit var cancellationToken: CancellationToken
|
|
|
|
|
|
|
|
// Data & Services
|
|
|
|
private val networkAndStorageChecker: NetworkAndStorageChecker by inject()
|
|
|
|
private val mediaPlayerController: MediaPlayerController by inject()
|
2021-06-19 23:09:38 +02:00
|
|
|
private val localMediaPlayer: LocalMediaPlayer by inject()
|
2021-06-19 20:42:03 +02:00
|
|
|
private val shareHandler: ShareHandler by inject()
|
|
|
|
private val imageLoaderProvider: ImageLoaderProvider by inject()
|
|
|
|
private lateinit var executorService: ScheduledExecutorService
|
|
|
|
private var currentPlaying: DownloadFile? = null
|
|
|
|
private var currentSong: MusicDirectory.Entry? = null
|
|
|
|
private var onProgressChangedTask: SilentBackgroundTask<Void?>? = null
|
|
|
|
|
|
|
|
// Views and UI Elements
|
|
|
|
private lateinit var visualizerViewLayout: LinearLayout
|
|
|
|
private lateinit var visualizerView: VisualizerView
|
|
|
|
private lateinit var playlistNameView: EditText
|
|
|
|
private lateinit var starMenuItem: MenuItem
|
|
|
|
private lateinit var fiveStar1ImageView: ImageView
|
|
|
|
private lateinit var fiveStar2ImageView: ImageView
|
|
|
|
private lateinit var fiveStar3ImageView: ImageView
|
|
|
|
private lateinit var fiveStar4ImageView: ImageView
|
|
|
|
private lateinit var fiveStar5ImageView: ImageView
|
|
|
|
private lateinit var playlistFlipper: ViewFlipper
|
|
|
|
private lateinit var emptyTextView: TextView
|
|
|
|
private lateinit var songTitleTextView: TextView
|
|
|
|
private lateinit var albumTextView: TextView
|
|
|
|
private lateinit var artistTextView: TextView
|
|
|
|
private lateinit var albumArtImageView: ImageView
|
|
|
|
private lateinit var playlistView: DragSortListView
|
|
|
|
private lateinit var positionTextView: TextView
|
|
|
|
private lateinit var downloadTrackTextView: TextView
|
|
|
|
private lateinit var downloadTotalDurationTextView: TextView
|
|
|
|
private lateinit var durationTextView: TextView
|
|
|
|
private lateinit var pauseButton: View
|
|
|
|
private lateinit var stopButton: View
|
|
|
|
private lateinit var startButton: View
|
|
|
|
private lateinit var repeatButton: ImageView
|
|
|
|
private lateinit var hollowStar: Drawable
|
|
|
|
private lateinit var fullStar: Drawable
|
2021-06-19 23:09:38 +02:00
|
|
|
private lateinit var progressBar: SeekBar
|
2021-06-19 20:05:38 +02:00
|
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
Util.applyTheme(this.context)
|
|
|
|
super.onCreate(savedInstanceState)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onCreateView(
|
2021-06-19 23:09:38 +02:00
|
|
|
inflater: LayoutInflater,
|
|
|
|
container: ViewGroup?,
|
2021-06-19 20:05:38 +02:00
|
|
|
savedInstanceState: Bundle?
|
|
|
|
): View? {
|
|
|
|
return inflater.inflate(R.layout.current_playing, container, false)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-10-08 17:34:52 +02:00
|
|
|
private fun findViews(view: View) {
|
2021-06-19 20:05:38 +02:00
|
|
|
playlistFlipper = view.findViewById(R.id.current_playing_playlist_flipper)
|
|
|
|
emptyTextView = view.findViewById(R.id.playlist_empty)
|
|
|
|
songTitleTextView = view.findViewById(R.id.current_playing_song)
|
|
|
|
albumTextView = view.findViewById(R.id.current_playing_album)
|
|
|
|
artistTextView = view.findViewById(R.id.current_playing_artist)
|
|
|
|
albumArtImageView = view.findViewById(R.id.current_playing_album_art_image)
|
|
|
|
positionTextView = view.findViewById(R.id.current_playing_position)
|
|
|
|
downloadTrackTextView = view.findViewById(R.id.current_playing_track)
|
|
|
|
downloadTotalDurationTextView = view.findViewById(R.id.current_total_duration)
|
|
|
|
durationTextView = view.findViewById(R.id.current_playing_duration)
|
|
|
|
progressBar = view.findViewById(R.id.current_playing_progress_bar)
|
|
|
|
playlistView = view.findViewById(R.id.playlist_view)
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
pauseButton = view.findViewById(R.id.button_pause)
|
|
|
|
stopButton = view.findViewById(R.id.button_stop)
|
|
|
|
startButton = view.findViewById(R.id.button_start)
|
|
|
|
repeatButton = view.findViewById(R.id.button_repeat)
|
|
|
|
visualizerViewLayout = view.findViewById(R.id.current_playing_visualizer_layout)
|
|
|
|
fiveStar1ImageView = view.findViewById(R.id.song_five_star_1)
|
|
|
|
fiveStar2ImageView = view.findViewById(R.id.song_five_star_2)
|
|
|
|
fiveStar3ImageView = view.findViewById(R.id.song_five_star_3)
|
|
|
|
fiveStar4ImageView = view.findViewById(R.id.song_five_star_4)
|
|
|
|
fiveStar5ImageView = view.findViewById(R.id.song_five_star_5)
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Suppress("LongMethod")
|
|
|
|
@SuppressLint("ClickableViewAccessibility")
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
|
|
cancellationToken = CancellationToken()
|
|
|
|
setTitle(this, R.string.common_appname)
|
|
|
|
val windowManager = requireActivity().windowManager
|
|
|
|
val display = windowManager.defaultDisplay
|
|
|
|
val size = Point()
|
|
|
|
display.getSize(size)
|
|
|
|
val width = size.x
|
|
|
|
val height = size.y
|
|
|
|
setHasOptionsMenu(true)
|
|
|
|
useFiveStarRating = get<FeatureStorage>().isFeatureEnabled(Feature.FIVE_STAR_RATING)
|
|
|
|
swipeDistance = (width + height) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100
|
|
|
|
swipeVelocity = swipeDistance
|
|
|
|
gestureScanner = GestureDetector(context, this)
|
|
|
|
|
2021-06-19 23:09:38 +02:00
|
|
|
// The secondary progress is an indicator of how far the song is cached.
|
|
|
|
localMediaPlayer.secondaryProgress.observe(
|
|
|
|
viewLifecycleOwner,
|
|
|
|
{
|
|
|
|
progressBar.secondaryProgress = it
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
findViews(view)
|
|
|
|
val previousButton: AutoRepeatButton = view.findViewById(R.id.button_previous)
|
|
|
|
val nextButton: AutoRepeatButton = view.findViewById(R.id.button_next)
|
|
|
|
val shuffleButton = view.findViewById<View>(R.id.button_shuffle)
|
|
|
|
val ratingLinearLayout = view.findViewById<LinearLayout>(R.id.song_rating)
|
2021-10-08 17:34:52 +02:00
|
|
|
if (!useFiveStarRating) ratingLinearLayout.isVisible = false
|
2021-06-19 20:05:38 +02:00
|
|
|
hollowStar = Util.getDrawableFromAttribute(view.context, R.attr.star_hollow)
|
|
|
|
fullStar = Util.getDrawableFromAttribute(context, R.attr.star_full)
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
fiveStar1ImageView.setOnClickListener { setSongRating(1) }
|
|
|
|
fiveStar2ImageView.setOnClickListener { setSongRating(2) }
|
|
|
|
fiveStar3ImageView.setOnClickListener { setSongRating(3) }
|
|
|
|
fiveStar4ImageView.setOnClickListener { setSongRating(4) }
|
|
|
|
fiveStar5ImageView.setOnClickListener { setSongRating(5) }
|
|
|
|
|
|
|
|
albumArtImageView.setOnTouchListener { _, me ->
|
|
|
|
gestureScanner.onTouchEvent(me)
|
|
|
|
}
|
|
|
|
|
|
|
|
albumArtImageView.setOnClickListener {
|
|
|
|
toggleFullScreenAlbumArt()
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
previousButton.setOnClickListener {
|
2021-06-19 20:42:03 +02:00
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
object : SilentBackgroundTask<Void?>(activity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
|
|
|
mediaPlayerController.previous()
|
2021-06-19 20:05:38 +02:00
|
|
|
return null
|
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Void?) {
|
2021-06-19 20:05:38 +02:00
|
|
|
onCurrentChanged()
|
|
|
|
onSliderProgressChanged()
|
|
|
|
}
|
|
|
|
}.execute()
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
previousButton.setOnRepeatListener {
|
2021-09-24 18:20:53 +02:00
|
|
|
val incrementTime = Settings.incrementTime
|
2021-06-19 20:05:38 +02:00
|
|
|
changeProgress(-incrementTime)
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
nextButton.setOnClickListener {
|
2021-06-19 20:42:03 +02:00
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
object : SilentBackgroundTask<Boolean?>(activity) {
|
|
|
|
override fun doInBackground(): Boolean {
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.next()
|
2021-06-19 20:05:38 +02:00
|
|
|
return true
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Boolean?) {
|
|
|
|
if (result == true) {
|
2021-06-19 20:05:38 +02:00
|
|
|
onCurrentChanged()
|
|
|
|
onSliderProgressChanged()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
|
|
|
}.execute()
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
nextButton.setOnRepeatListener {
|
2021-09-24 18:20:53 +02:00
|
|
|
val incrementTime = Settings.incrementTime
|
2021-06-19 20:05:38 +02:00
|
|
|
changeProgress(incrementTime)
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
pauseButton.setOnClickListener {
|
2021-06-19 20:05:38 +02:00
|
|
|
object : SilentBackgroundTask<Void?>(activity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
|
|
|
mediaPlayerController.pause()
|
2021-06-19 20:05:38 +02:00
|
|
|
return null
|
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Void?) {
|
2021-06-19 20:05:38 +02:00
|
|
|
onCurrentChanged()
|
|
|
|
onSliderProgressChanged()
|
|
|
|
}
|
|
|
|
}.execute()
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|
|
|
|
stopButton.setOnClickListener {
|
2021-06-19 20:05:38 +02:00
|
|
|
object : SilentBackgroundTask<Void?>(activity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
|
|
|
mediaPlayerController.reset()
|
2021-06-19 20:05:38 +02:00
|
|
|
return null
|
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Void?) {
|
2021-06-19 20:05:38 +02:00
|
|
|
onCurrentChanged()
|
|
|
|
onSliderProgressChanged()
|
|
|
|
}
|
|
|
|
}.execute()
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|
|
|
|
startButton.setOnClickListener {
|
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
object : SilentBackgroundTask<Void?>(activity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
2021-06-19 20:05:38 +02:00
|
|
|
start()
|
|
|
|
return null
|
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Void?) {
|
2021-06-19 20:05:38 +02:00
|
|
|
onCurrentChanged()
|
|
|
|
onSliderProgressChanged()
|
|
|
|
}
|
|
|
|
}.execute()
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
shuffleButton.setOnClickListener {
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.shuffle()
|
2021-06-19 20:05:38 +02:00
|
|
|
Util.toast(activity, R.string.download_menu_shuffle_notification)
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
repeatButton.setOnClickListener {
|
2021-07-16 17:29:21 +02:00
|
|
|
val repeatMode = mediaPlayerController.repeatMode.next()
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.repeatMode = repeatMode
|
2021-06-19 20:05:38 +02:00
|
|
|
onDownloadListChanged()
|
|
|
|
when (repeatMode) {
|
|
|
|
RepeatMode.OFF -> Util.toast(
|
|
|
|
context, R.string.download_repeat_off
|
|
|
|
)
|
|
|
|
RepeatMode.ALL -> Util.toast(
|
|
|
|
context, R.string.download_repeat_all
|
|
|
|
)
|
|
|
|
RepeatMode.SINGLE -> Util.toast(
|
|
|
|
context, R.string.download_repeat_single
|
|
|
|
)
|
|
|
|
else -> {
|
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|
|
|
|
|
2021-06-19 23:09:38 +02:00
|
|
|
progressBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
|
|
|
object : SilentBackgroundTask<Void?>(activity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
2021-06-19 23:09:38 +02:00
|
|
|
mediaPlayerController.seekTo(progressBar.progress)
|
2021-06-19 20:05:38 +02:00
|
|
|
return null
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Void?) {
|
2021-06-19 20:05:38 +02:00
|
|
|
onSliderProgressChanged()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
}.execute()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
|
|
|
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {}
|
|
|
|
})
|
2021-06-19 23:09:38 +02:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistView.setOnItemClickListener { _, _, position, _ ->
|
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
object : SilentBackgroundTask<Void?>(activity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
|
|
|
mediaPlayerController.play(position)
|
2021-06-19 20:05:38 +02:00
|
|
|
return null
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Void?) {
|
2021-06-19 20:05:38 +02:00
|
|
|
onCurrentChanged()
|
|
|
|
onSliderProgressChanged()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
}.execute()
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
registerForContextMenu(playlistView)
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
if (arguments != null && requireArguments().getBoolean(
|
2021-06-19 23:09:38 +02:00
|
|
|
Constants.INTENT_EXTRA_NAME_SHUFFLE,
|
|
|
|
false
|
|
|
|
)
|
2021-06-19 20:05:38 +02:00
|
|
|
) {
|
2021-06-19 20:42:03 +02:00
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
mediaPlayerController.isShufflePlayEnabled = true
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-10-08 17:34:52 +02:00
|
|
|
visualizerViewLayout.isVisible = false
|
2021-06-19 23:09:38 +02:00
|
|
|
VisualizerController.get().observe(
|
|
|
|
requireActivity(),
|
|
|
|
{ visualizerController ->
|
|
|
|
if (visualizerController != null) {
|
|
|
|
Timber.d("VisualizerController Observer.onChanged received controller")
|
|
|
|
visualizerView = VisualizerView(context)
|
|
|
|
visualizerViewLayout.addView(
|
|
|
|
visualizerView,
|
|
|
|
LinearLayout.LayoutParams(
|
|
|
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
|
|
LinearLayout.LayoutParams.MATCH_PARENT
|
|
|
|
)
|
2021-06-19 20:05:38 +02:00
|
|
|
)
|
2021-10-08 17:34:52 +02:00
|
|
|
|
|
|
|
visualizerViewLayout.isVisible = visualizerView.isActive
|
|
|
|
|
2021-06-19 23:09:38 +02:00
|
|
|
visualizerView.setOnTouchListener { _, _ ->
|
|
|
|
visualizerView.isActive = !visualizerView.isActive
|
|
|
|
mediaPlayerController.showVisualization = visualizerView.isActive
|
|
|
|
true
|
|
|
|
}
|
|
|
|
isVisualizerAvailable = true
|
2021-06-19 20:05:38 +02:00
|
|
|
} else {
|
2021-06-19 23:09:38 +02:00
|
|
|
Timber.d("VisualizerController Observer.onChanged has no controller")
|
2021-10-08 17:34:52 +02:00
|
|
|
visualizerViewLayout.isVisible = false
|
2021-06-19 23:09:38 +02:00
|
|
|
isVisualizerAvailable = false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
2021-06-19 23:09:38 +02:00
|
|
|
)
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 23:09:38 +02:00
|
|
|
EqualizerController.get().observe(
|
|
|
|
requireActivity(),
|
|
|
|
{ equalizerController ->
|
|
|
|
isEqualizerAvailable = if (equalizerController != null) {
|
|
|
|
Timber.d("EqualizerController Observer.onChanged received controller")
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
Timber.d("EqualizerController Observer.onChanged has no controller")
|
|
|
|
false
|
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
2021-06-19 23:09:38 +02:00
|
|
|
)
|
2021-06-19 20:05:38 +02:00
|
|
|
Thread {
|
|
|
|
try {
|
2021-06-19 20:42:03 +02:00
|
|
|
jukeboxAvailable = mediaPlayerController.isJukeboxAvailable
|
|
|
|
} catch (all: Exception) {
|
|
|
|
Timber.e(all)
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
|
|
|
}.start()
|
2021-06-19 20:42:03 +02:00
|
|
|
view.setOnTouchListener { _, event -> gestureScanner.onTouchEvent(event) }
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
2021-06-19 20:42:03 +02:00
|
|
|
if (mediaPlayerController.currentPlaying == null) {
|
|
|
|
playlistFlipper.displayedChild = 1
|
2021-06-19 20:05:38 +02:00
|
|
|
} else {
|
2021-02-05 21:45:50 +01:00
|
|
|
// Download list and Album art must be updated when Resumed
|
2021-06-19 20:05:38 +02:00
|
|
|
onDownloadListChanged()
|
|
|
|
onCurrentChanged()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
val handler = Handler()
|
|
|
|
val runnable = Runnable { handler.post { update(cancellationToken) } }
|
|
|
|
executorService = Executors.newSingleThreadScheduledExecutor()
|
|
|
|
executorService.scheduleWithFixedDelay(runnable, 0L, 250L, TimeUnit.MILLISECONDS)
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
if (mediaPlayerController.keepScreenOn) {
|
|
|
|
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
2021-06-19 20:05:38 +02:00
|
|
|
} else {
|
2021-06-19 20:42:03 +02:00
|
|
|
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 23:09:38 +02:00
|
|
|
if (::visualizerView.isInitialized) {
|
|
|
|
visualizerView.isActive = mediaPlayerController.showVisualization
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
requireActivity().invalidateOptionsMenu()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-08-27 23:53:31 +02:00
|
|
|
// Scroll to current playing.
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun scrollToCurrent() {
|
2021-06-19 20:42:03 +02:00
|
|
|
val adapter = playlistView.adapter
|
2021-06-19 20:05:38 +02:00
|
|
|
if (adapter != null) {
|
|
|
|
val count = adapter.count
|
|
|
|
for (i in 0 until count) {
|
2021-06-19 20:42:03 +02:00
|
|
|
if (currentPlaying == playlistView.getItemAtPosition(i)) {
|
|
|
|
playlistView.smoothScrollToPositionFromTop(i, 40)
|
2021-06-19 20:05:38 +02:00
|
|
|
return
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onPause() {
|
|
|
|
super.onPause()
|
2021-06-19 20:42:03 +02:00
|
|
|
executorService.shutdown()
|
2021-06-19 23:09:38 +02:00
|
|
|
if (::visualizerView.isInitialized) {
|
|
|
|
visualizerView.isActive = mediaPlayerController.showVisualization
|
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onDestroyView() {
|
2021-06-19 20:42:03 +02:00
|
|
|
cancellationToken.cancel()
|
2021-06-19 20:05:38 +02:00
|
|
|
super.onDestroyView()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
|
|
|
inflater.inflate(R.menu.nowplaying, menu)
|
|
|
|
super.onCreateOptionsMenu(menu, inflater)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
@Suppress("ComplexMethod", "LongMethod", "NestedBlockDepth")
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
|
|
|
super.onPrepareOptionsMenu(menu)
|
|
|
|
val screenOption = menu.findItem(R.id.menu_item_screen_on_off)
|
|
|
|
val jukeboxOption = menu.findItem(R.id.menu_item_jukebox)
|
|
|
|
val equalizerMenuItem = menu.findItem(R.id.menu_item_equalizer)
|
|
|
|
val visualizerMenuItem = menu.findItem(R.id.menu_item_visualizer)
|
|
|
|
val shareMenuItem = menu.findItem(R.id.menu_item_share)
|
2021-10-08 17:34:52 +02:00
|
|
|
val shareSongMenuItem = menu.findItem(R.id.menu_item_share_song)
|
2021-06-19 20:05:38 +02:00
|
|
|
starMenuItem = menu.findItem(R.id.menu_item_star)
|
|
|
|
val bookmarkMenuItem = menu.findItem(R.id.menu_item_bookmark_set)
|
|
|
|
val bookmarkRemoveMenuItem = menu.findItem(R.id.menu_item_bookmark_delete)
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
if (isOffline()) {
|
|
|
|
if (shareMenuItem != null) {
|
|
|
|
shareMenuItem.isVisible = false
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
starMenuItem.isVisible = false
|
2021-06-19 20:05:38 +02:00
|
|
|
if (bookmarkMenuItem != null) {
|
|
|
|
bookmarkMenuItem.isVisible = false
|
|
|
|
}
|
|
|
|
if (bookmarkRemoveMenuItem != null) {
|
|
|
|
bookmarkRemoveMenuItem.isVisible = false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
if (equalizerMenuItem != null) {
|
|
|
|
equalizerMenuItem.isEnabled = isEqualizerAvailable
|
|
|
|
equalizerMenuItem.isVisible = isEqualizerAvailable
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
if (visualizerMenuItem != null) {
|
|
|
|
visualizerMenuItem.isEnabled = isVisualizerAvailable
|
|
|
|
visualizerMenuItem.isVisible = isVisualizerAvailable
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
val mediaPlayerController = mediaPlayerController
|
|
|
|
val downloadFile = mediaPlayerController.currentPlaying
|
2021-10-08 17:34:52 +02:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
if (downloadFile != null) {
|
|
|
|
currentSong = downloadFile.song
|
|
|
|
}
|
2021-10-08 17:34:52 +02:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
if (useFiveStarRating) starMenuItem.isVisible = false
|
2021-10-08 17:34:52 +02:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
if (currentSong != null) {
|
|
|
|
starMenuItem.icon = if (currentSong!!.starred) fullStar else hollowStar
|
2021-10-08 17:34:52 +02:00
|
|
|
shareSongMenuItem.isVisible = true
|
2021-06-19 20:42:03 +02:00
|
|
|
} else {
|
|
|
|
starMenuItem.icon = hollowStar
|
2021-10-08 17:34:52 +02:00
|
|
|
shareSongMenuItem.isVisible = false
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|
2021-10-08 17:34:52 +02:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
if (mediaPlayerController.keepScreenOn) {
|
|
|
|
screenOption?.setTitle(R.string.download_menu_screen_off)
|
|
|
|
} else {
|
|
|
|
screenOption?.setTitle(R.string.download_menu_screen_on)
|
|
|
|
}
|
2021-10-08 17:34:52 +02:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
if (jukeboxOption != null) {
|
|
|
|
jukeboxOption.isEnabled = jukeboxAvailable
|
|
|
|
jukeboxOption.isVisible = jukeboxAvailable
|
|
|
|
if (mediaPlayerController.isJukeboxEnabled) {
|
|
|
|
jukeboxOption.setTitle(R.string.download_menu_jukebox_off)
|
2021-06-19 20:05:38 +02:00
|
|
|
} else {
|
2021-06-19 20:42:03 +02:00
|
|
|
jukeboxOption.setTitle(R.string.download_menu_jukebox_on)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) {
|
|
|
|
super.onCreateContextMenu(menu, view, menuInfo)
|
|
|
|
if (view === playlistView) {
|
|
|
|
val info = menuInfo as AdapterContextMenuInfo?
|
2021-06-19 20:42:03 +02:00
|
|
|
val downloadFile = playlistView.getItemAtPosition(info!!.position) as DownloadFile
|
|
|
|
val menuInflater = requireActivity().menuInflater
|
2021-06-19 20:05:38 +02:00
|
|
|
menuInflater.inflate(R.menu.nowplaying_context, menu)
|
2021-06-19 20:42:03 +02:00
|
|
|
val song: MusicDirectory.Entry?
|
|
|
|
|
|
|
|
song = downloadFile.song
|
|
|
|
|
|
|
|
if (song.parent == null) {
|
2021-06-19 20:05:38 +02:00
|
|
|
val menuItem = menu.findItem(R.id.menu_show_album)
|
|
|
|
if (menuItem != null) {
|
|
|
|
menuItem.isVisible = false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-09-24 18:20:53 +02:00
|
|
|
if (isOffline() || !Settings.shouldUseId3Tags) {
|
2021-06-19 20:42:03 +02:00
|
|
|
menu.findItem(R.id.menu_show_artist)?.isVisible = false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
if (isOffline()) {
|
2021-06-19 20:42:03 +02:00
|
|
|
menu.findItem(R.id.menu_lyrics)?.isVisible = false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onContextItemSelected(menuItem: MenuItem): Boolean {
|
|
|
|
val info = menuItem.menuInfo as AdapterContextMenuInfo
|
2021-06-19 20:42:03 +02:00
|
|
|
val downloadFile = playlistView.getItemAtPosition(info.position) as DownloadFile
|
2021-06-19 20:05:38 +02:00
|
|
|
return menuItemSelected(menuItem.itemId, downloadFile) || super.onContextItemSelected(
|
|
|
|
menuItem
|
|
|
|
)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
|
|
return menuItemSelected(item.itemId, null) || super.onOptionsItemSelected(item)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
@Suppress("ComplexMethod", "LongMethod", "ReturnCount")
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun menuItemSelected(menuItemId: Int, song: DownloadFile?): Boolean {
|
|
|
|
var entry: MusicDirectory.Entry? = null
|
|
|
|
val bundle: Bundle
|
|
|
|
if (song != null) {
|
|
|
|
entry = song.song
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
when (menuItemId) {
|
|
|
|
R.id.menu_show_artist -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
if (entry == null) return false
|
|
|
|
|
2021-09-24 18:20:53 +02:00
|
|
|
if (Settings.shouldUseId3Tags) {
|
2021-06-19 20:42:03 +02:00
|
|
|
bundle = Bundle()
|
|
|
|
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.artistId)
|
|
|
|
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.artist)
|
|
|
|
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.artistId)
|
|
|
|
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true)
|
2021-06-19 23:09:38 +02:00
|
|
|
Navigation.findNavController(requireView())
|
|
|
|
.navigate(R.id.playerToSelectAlbum, bundle)
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|
|
|
|
return true
|
2021-02-14 15:55:16 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_show_album -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
if (entry == null) return false
|
|
|
|
|
2021-09-24 18:20:53 +02:00
|
|
|
val albumId = if (Settings.shouldUseId3Tags) entry.albumId else entry.parent
|
2021-06-19 20:05:38 +02:00
|
|
|
bundle = Bundle()
|
2021-06-19 20:42:03 +02:00
|
|
|
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, albumId)
|
|
|
|
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.album)
|
|
|
|
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.parent)
|
|
|
|
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, true)
|
2021-06-19 23:09:38 +02:00
|
|
|
Navigation.findNavController(requireView())
|
|
|
|
.navigate(R.id.playerToSelectAlbum, bundle)
|
2021-06-19 20:42:03 +02:00
|
|
|
return true
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_lyrics -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
if (entry == null) return false
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
bundle = Bundle()
|
|
|
|
bundle.putString(Constants.INTENT_EXTRA_NAME_ARTIST, entry.artist)
|
|
|
|
bundle.putString(Constants.INTENT_EXTRA_NAME_TITLE, entry.title)
|
2021-06-19 23:09:38 +02:00
|
|
|
Navigation.findNavController(requireView()).navigate(R.id.playerToLyrics, bundle)
|
2021-06-19 20:42:03 +02:00
|
|
|
return true
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_remove -> {
|
2021-08-27 23:53:31 +02:00
|
|
|
mediaPlayerController.removeFromPlaylist(song!!)
|
2021-06-19 20:42:03 +02:00
|
|
|
onDownloadListChanged()
|
|
|
|
return true
|
2021-02-14 15:55:16 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_item_screen_on_off -> {
|
2021-06-19 23:09:38 +02:00
|
|
|
val window = requireActivity().window
|
2021-06-19 20:42:03 +02:00
|
|
|
if (mediaPlayerController.keepScreenOn) {
|
2021-06-19 23:09:38 +02:00
|
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.keepScreenOn = false
|
|
|
|
} else {
|
2021-06-19 23:09:38 +02:00
|
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.keepScreenOn = true
|
|
|
|
}
|
|
|
|
return true
|
2021-02-14 15:55:16 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_shuffle -> {
|
|
|
|
mediaPlayerController.shuffle()
|
|
|
|
Util.toast(context, R.string.download_menu_shuffle_notification)
|
|
|
|
return true
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_item_equalizer -> {
|
2021-06-19 23:09:38 +02:00
|
|
|
Navigation.findNavController(requireView()).navigate(R.id.playerToEqualizer)
|
2021-06-19 20:42:03 +02:00
|
|
|
return true
|
2021-02-14 15:55:16 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_item_visualizer -> {
|
|
|
|
val active = !visualizerView.isActive
|
|
|
|
visualizerView.isActive = active
|
2021-10-08 17:34:52 +02:00
|
|
|
|
|
|
|
visualizerViewLayout.isVisible = visualizerView.isActive
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.showVisualization = visualizerView.isActive
|
|
|
|
Util.toast(
|
|
|
|
context,
|
2021-06-19 23:09:38 +02:00
|
|
|
if (active) R.string.download_visualizer_on
|
|
|
|
else R.string.download_visualizer_off
|
2021-06-19 20:42:03 +02:00
|
|
|
)
|
2021-06-19 20:05:38 +02:00
|
|
|
return true
|
2021-02-14 15:55:16 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_item_jukebox -> {
|
|
|
|
val jukeboxEnabled = !mediaPlayerController.isJukeboxEnabled
|
|
|
|
mediaPlayerController.isJukeboxEnabled = jukeboxEnabled
|
|
|
|
Util.toast(
|
|
|
|
context,
|
2021-06-19 23:09:38 +02:00
|
|
|
if (jukeboxEnabled) R.string.download_jukebox_on
|
|
|
|
else R.string.download_jukebox_off,
|
2021-06-19 20:42:03 +02:00
|
|
|
false
|
|
|
|
)
|
|
|
|
return true
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_item_toggle_list -> {
|
|
|
|
toggleFullScreenAlbumArt()
|
2021-06-19 20:05:38 +02:00
|
|
|
return true
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_item_clear_playlist -> {
|
|
|
|
mediaPlayerController.isShufflePlayEnabled = false
|
|
|
|
mediaPlayerController.clear()
|
|
|
|
onDownloadListChanged()
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
R.id.menu_item_save_playlist -> {
|
|
|
|
if (mediaPlayerController.playlistSize > 0) {
|
|
|
|
showSavePlaylistDialog()
|
2021-02-14 15:55:16 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
return true
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_item_star -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
if (currentSong == null) return true
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
val isStarred = currentSong!!.starred
|
|
|
|
val id = currentSong!!.id
|
|
|
|
if (isStarred) {
|
|
|
|
starMenuItem.icon = hollowStar
|
|
|
|
currentSong!!.starred = false
|
|
|
|
} else {
|
|
|
|
starMenuItem.icon = fullStar
|
|
|
|
currentSong!!.starred = true
|
|
|
|
}
|
|
|
|
Thread {
|
|
|
|
val musicService = getMusicService()
|
|
|
|
try {
|
|
|
|
if (isStarred) {
|
|
|
|
musicService.unstar(id, null, null)
|
|
|
|
} else {
|
|
|
|
musicService.star(id, null, null)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
} catch (all: Exception) {
|
|
|
|
Timber.e(all)
|
|
|
|
}
|
|
|
|
}.start()
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
R.id.menu_item_bookmark_set -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
if (currentSong == null) return true
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
val songId = currentSong!!.id
|
|
|
|
val playerPosition = mediaPlayerController.playerPosition
|
|
|
|
currentSong!!.bookmarkPosition = playerPosition
|
|
|
|
val bookmarkTime = Util.formatTotalDuration(playerPosition.toLong(), true)
|
|
|
|
Thread {
|
|
|
|
val musicService = getMusicService()
|
|
|
|
try {
|
|
|
|
musicService.createBookmark(songId, playerPosition)
|
|
|
|
} catch (all: Exception) {
|
|
|
|
Timber.e(all)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
}.start()
|
2021-06-19 23:09:38 +02:00
|
|
|
val msg = resources.getString(
|
|
|
|
R.string.download_bookmark_set_at_position,
|
|
|
|
bookmarkTime
|
|
|
|
)
|
2021-06-19 20:42:03 +02:00
|
|
|
Util.toast(context, msg)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
R.id.menu_item_bookmark_delete -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
if (currentSong == null) return true
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
val bookmarkSongId = currentSong!!.id
|
|
|
|
currentSong!!.bookmarkPosition = 0
|
|
|
|
Thread {
|
|
|
|
val musicService = getMusicService()
|
|
|
|
try {
|
|
|
|
musicService.deleteBookmark(bookmarkSongId)
|
|
|
|
} catch (all: Exception) {
|
|
|
|
Timber.e(all)
|
|
|
|
}
|
|
|
|
}.start()
|
|
|
|
Util.toast(context, R.string.download_bookmark_removed)
|
|
|
|
return true
|
2021-02-14 15:55:16 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
R.id.menu_item_share -> {
|
|
|
|
val mediaPlayerController = mediaPlayerController
|
|
|
|
val entries: MutableList<MusicDirectory.Entry?> = ArrayList()
|
|
|
|
val downloadServiceSongs = mediaPlayerController.playList
|
|
|
|
for (downloadFile in downloadServiceSongs) {
|
|
|
|
val playlistEntry = downloadFile.song
|
|
|
|
entries.add(playlistEntry)
|
|
|
|
}
|
|
|
|
shareHandler.createShare(this, entries, null, cancellationToken)
|
|
|
|
return true
|
|
|
|
}
|
2021-10-08 17:34:52 +02:00
|
|
|
R.id.menu_item_share_song -> {
|
|
|
|
if (currentSong == null) return true
|
|
|
|
|
|
|
|
val entries: MutableList<MusicDirectory.Entry?> = ArrayList()
|
|
|
|
entries.add(currentSong)
|
|
|
|
|
|
|
|
shareHandler.createShare(this, entries, null, cancellationToken)
|
|
|
|
return true
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
else -> return false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun update(cancel: CancellationToken?) {
|
|
|
|
if (cancel!!.isCancellationRequested) return
|
2021-06-19 20:42:03 +02:00
|
|
|
val mediaPlayerController = mediaPlayerController
|
2021-06-19 20:05:38 +02:00
|
|
|
if (currentRevision != mediaPlayerController.playListUpdateRevision) {
|
|
|
|
onDownloadListChanged()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
if (currentPlaying != mediaPlayerController.currentPlaying) {
|
|
|
|
onCurrentChanged()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
onSliderProgressChanged()
|
2021-06-19 20:42:03 +02:00
|
|
|
requireActivity().invalidateOptionsMenu()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun savePlaylistInBackground(playlistName: String) {
|
|
|
|
Util.toast(context, resources.getString(R.string.download_playlist_saving, playlistName))
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.suggestedPlaylistName = playlistName
|
2021-06-19 20:05:38 +02:00
|
|
|
object : SilentBackgroundTask<Void?>(activity) {
|
|
|
|
@Throws(Throwable::class)
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
2021-06-19 20:05:38 +02:00
|
|
|
val entries: MutableList<MusicDirectory.Entry> = LinkedList()
|
2021-06-19 20:42:03 +02:00
|
|
|
for (downloadFile in mediaPlayerController.playList) {
|
2021-06-19 20:05:38 +02:00
|
|
|
entries.add(downloadFile.song)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
val musicService = getMusicService()
|
|
|
|
musicService.createPlaylist(null, playlistName, entries)
|
|
|
|
return null
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Void?) {
|
2021-06-19 20:05:38 +02:00
|
|
|
Util.toast(context, R.string.download_playlist_done)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun error(error: Throwable) {
|
|
|
|
Timber.e(error, "Exception has occurred in savePlaylistInBackground")
|
2021-06-19 23:09:38 +02:00
|
|
|
val msg = String.format(
|
|
|
|
Locale.ROOT,
|
2021-06-19 20:05:38 +02:00
|
|
|
"%s %s",
|
|
|
|
resources.getString(R.string.download_playlist_error),
|
|
|
|
getErrorMessage(error)
|
|
|
|
)
|
|
|
|
Util.toast(context, msg)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
}.execute()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun toggleFullScreenAlbumArt() {
|
2021-06-19 20:42:03 +02:00
|
|
|
if (playlistFlipper.displayedChild == 1) {
|
|
|
|
playlistFlipper.inAnimation =
|
2021-06-19 20:05:38 +02:00
|
|
|
AnimationUtils.loadAnimation(context, R.anim.push_down_in)
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistFlipper.outAnimation =
|
2021-06-19 20:05:38 +02:00
|
|
|
AnimationUtils.loadAnimation(context, R.anim.push_down_out)
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistFlipper.displayedChild = 0
|
2021-06-19 20:05:38 +02:00
|
|
|
} else {
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistFlipper.inAnimation =
|
2021-06-19 20:05:38 +02:00
|
|
|
AnimationUtils.loadAnimation(context, R.anim.push_up_in)
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistFlipper.outAnimation =
|
2021-06-19 20:05:38 +02:00
|
|
|
AnimationUtils.loadAnimation(context, R.anim.push_up_out)
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistFlipper.displayedChild = 1
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
scrollToCurrent()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun start() {
|
2021-06-19 20:42:03 +02:00
|
|
|
val service = mediaPlayerController
|
2021-06-19 20:05:38 +02:00
|
|
|
val state = service.playerState
|
2021-06-19 23:09:38 +02:00
|
|
|
if (state === PlayerState.PAUSED ||
|
|
|
|
state === PlayerState.COMPLETED || state === PlayerState.STOPPED
|
|
|
|
) {
|
2021-06-19 20:05:38 +02:00
|
|
|
service.start()
|
|
|
|
} else if (state === PlayerState.IDLE) {
|
2021-06-19 20:42:03 +02:00
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
|
|
|
val current = mediaPlayerController.currentPlayingNumberOnPlaylist
|
2021-06-19 20:05:38 +02:00
|
|
|
if (current == -1) {
|
|
|
|
service.play(0)
|
|
|
|
} else {
|
|
|
|
service.play(current)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun onDownloadListChanged() {
|
2021-06-19 20:42:03 +02:00
|
|
|
val mediaPlayerController = mediaPlayerController
|
2021-06-19 20:05:38 +02:00
|
|
|
val list = mediaPlayerController.playList
|
2021-06-19 20:42:03 +02:00
|
|
|
emptyTextView.setText(R.string.download_empty)
|
2021-06-19 20:05:38 +02:00
|
|
|
val adapter = SongListAdapter(context, list)
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistView.adapter = adapter
|
|
|
|
playlistView.setDragSortListener(object : DragSortListener {
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun drop(from: Int, to: Int) {
|
|
|
|
if (from != to) {
|
|
|
|
val item = adapter.getItem(from)
|
|
|
|
adapter.remove(item)
|
|
|
|
adapter.notifyDataSetChanged()
|
|
|
|
adapter.insert(item, to)
|
|
|
|
adapter.notifyDataSetChanged()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun drag(from: Int, to: Int) {}
|
|
|
|
override fun remove(which: Int) {
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
val item = adapter.getItem(which) ?: return
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
val currentPlaying = mediaPlayerController.currentPlaying
|
|
|
|
if (currentPlaying == item) {
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.next()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
adapter.remove(item)
|
|
|
|
adapter.notifyDataSetChanged()
|
|
|
|
val songRemoved = String.format(
|
|
|
|
resources.getString(R.string.download_song_removed),
|
|
|
|
item.song.title
|
|
|
|
)
|
|
|
|
Util.toast(context, songRemoved)
|
|
|
|
onDownloadListChanged()
|
|
|
|
onCurrentChanged()
|
|
|
|
}
|
|
|
|
})
|
2021-10-08 17:34:52 +02:00
|
|
|
|
|
|
|
emptyTextView.isVisible = list.isEmpty()
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
currentRevision = mediaPlayerController.playListUpdateRevision
|
|
|
|
when (mediaPlayerController.repeatMode) {
|
2021-06-19 20:42:03 +02:00
|
|
|
RepeatMode.OFF -> repeatButton.setImageDrawable(
|
2021-06-19 20:05:38 +02:00
|
|
|
Util.getDrawableFromAttribute(
|
|
|
|
context, R.attr.media_repeat_off
|
|
|
|
)
|
|
|
|
)
|
2021-06-19 20:42:03 +02:00
|
|
|
RepeatMode.ALL -> repeatButton.setImageDrawable(
|
2021-06-19 20:05:38 +02:00
|
|
|
Util.getDrawableFromAttribute(
|
|
|
|
context, R.attr.media_repeat_all
|
|
|
|
)
|
|
|
|
)
|
2021-06-19 20:42:03 +02:00
|
|
|
RepeatMode.SINGLE -> repeatButton.setImageDrawable(
|
2021-06-19 20:05:38 +02:00
|
|
|
Util.getDrawableFromAttribute(
|
|
|
|
context, R.attr.media_repeat_single
|
|
|
|
)
|
|
|
|
)
|
|
|
|
else -> {
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun onCurrentChanged() {
|
|
|
|
currentPlaying = mediaPlayerController.currentPlaying
|
|
|
|
scrollToCurrent()
|
|
|
|
val totalDuration = mediaPlayerController.playListDuration
|
|
|
|
val totalSongs = mediaPlayerController.playlistSize.toLong()
|
|
|
|
val currentSongIndex = mediaPlayerController.currentPlayingNumberOnPlaylist + 1
|
|
|
|
val duration = Util.formatTotalDuration(totalDuration)
|
|
|
|
val trackFormat =
|
|
|
|
String.format(Locale.getDefault(), "%d / %d", currentSongIndex, totalSongs)
|
|
|
|
if (currentPlaying != null) {
|
|
|
|
currentSong = currentPlaying!!.song
|
2021-06-19 20:42:03 +02:00
|
|
|
songTitleTextView.text = currentSong!!.title
|
|
|
|
albumTextView.text = currentSong!!.album
|
|
|
|
artistTextView.text = currentSong!!.artist
|
|
|
|
downloadTrackTextView.text = trackFormat
|
|
|
|
downloadTotalDurationTextView.text = duration
|
|
|
|
imageLoaderProvider.getImageLoader()
|
2021-06-19 20:05:38 +02:00
|
|
|
.loadImage(albumArtImageView, currentSong, true, 0)
|
|
|
|
displaySongRating()
|
|
|
|
} else {
|
|
|
|
currentSong = null
|
2021-06-19 20:42:03 +02:00
|
|
|
songTitleTextView.text = null
|
|
|
|
albumTextView.text = null
|
|
|
|
artistTextView.text = null
|
|
|
|
downloadTrackTextView.text = null
|
|
|
|
downloadTotalDurationTextView.text = null
|
|
|
|
imageLoaderProvider.getImageLoader()
|
|
|
|
.loadImage(albumArtImageView, null, true, 0)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun onSliderProgressChanged() {
|
2021-06-19 20:42:03 +02:00
|
|
|
if (onProgressChangedTask != null) {
|
2021-06-19 20:05:38 +02:00
|
|
|
return
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
onProgressChangedTask = object : SilentBackgroundTask<Void?>(activity) {
|
|
|
|
var isJukeboxEnabled = false
|
|
|
|
var millisPlayed = 0
|
|
|
|
var duration: Int? = null
|
|
|
|
var playerState: PlayerState? = null
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
|
|
|
isJukeboxEnabled = mediaPlayerController.isJukeboxEnabled
|
|
|
|
millisPlayed = max(0, mediaPlayerController.playerPosition)
|
|
|
|
duration = mediaPlayerController.playerDuration
|
|
|
|
playerState = mediaPlayerController.playerState
|
2021-06-19 20:05:38 +02:00
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
@Suppress("LongMethod")
|
|
|
|
override fun done(result: Void?) {
|
|
|
|
if (cancellationToken.isCancellationRequested) return
|
2021-06-19 20:05:38 +02:00
|
|
|
if (currentPlaying != null) {
|
|
|
|
val millisTotal = if (duration == null) 0 else duration!!
|
2021-06-19 20:42:03 +02:00
|
|
|
positionTextView.text = Util.formatTotalDuration(millisPlayed.toLong(), true)
|
|
|
|
durationTextView.text = Util.formatTotalDuration(millisTotal.toLong(), true)
|
2021-06-19 23:09:38 +02:00
|
|
|
progressBar.max =
|
2021-06-19 20:05:38 +02:00
|
|
|
if (millisTotal == 0) 100 else millisTotal // Work-around for apparent bug.
|
2021-06-19 23:09:38 +02:00
|
|
|
progressBar.progress = millisPlayed
|
|
|
|
progressBar.isEnabled = currentPlaying!!.isWorkDone || isJukeboxEnabled
|
2021-06-19 20:05:38 +02:00
|
|
|
} else {
|
2021-06-19 20:42:03 +02:00
|
|
|
positionTextView.setText(R.string.util_zero_time)
|
|
|
|
durationTextView.setText(R.string.util_no_time)
|
2021-06-19 23:09:38 +02:00
|
|
|
progressBar.progress = 0
|
|
|
|
progressBar.max = 0
|
|
|
|
progressBar.isEnabled = false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
when (playerState) {
|
|
|
|
PlayerState.DOWNLOADING -> {
|
|
|
|
val progress =
|
|
|
|
if (currentPlaying != null) currentPlaying!!.progress.value!! else 0
|
|
|
|
val downloadStatus = resources.getString(
|
|
|
|
R.string.download_playerstate_downloading,
|
|
|
|
Util.formatPercentage(progress)
|
|
|
|
)
|
|
|
|
setTitle(this@PlayerFragment, downloadStatus)
|
|
|
|
}
|
|
|
|
PlayerState.PREPARING -> setTitle(
|
|
|
|
this@PlayerFragment,
|
|
|
|
R.string.download_playerstate_buffering
|
|
|
|
)
|
|
|
|
PlayerState.STARTED -> {
|
2021-06-19 20:42:03 +02:00
|
|
|
if (mediaPlayerController.isShufflePlayEnabled) {
|
2021-06-19 20:05:38 +02:00
|
|
|
setTitle(
|
|
|
|
this@PlayerFragment,
|
|
|
|
R.string.download_playerstate_playing_shuffle
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
setTitle(this@PlayerFragment, R.string.common_appname)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
PlayerState.IDLE,
|
|
|
|
PlayerState.PREPARED,
|
|
|
|
PlayerState.STOPPED,
|
|
|
|
PlayerState.PAUSED,
|
|
|
|
PlayerState.COMPLETED -> {
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
|
|
|
else -> setTitle(this@PlayerFragment, R.string.common_appname)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
when (playerState) {
|
|
|
|
PlayerState.STARTED -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
pauseButton.isVisible = true
|
|
|
|
stopButton.isVisible = false
|
|
|
|
startButton.isVisible = false
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
|
|
|
PlayerState.DOWNLOADING, PlayerState.PREPARING -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
pauseButton.isVisible = false
|
|
|
|
stopButton.isVisible = true
|
|
|
|
startButton.isVisible = false
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
|
|
|
else -> {
|
2021-10-08 17:34:52 +02:00
|
|
|
pauseButton.isVisible = false
|
|
|
|
stopButton.isVisible = false
|
|
|
|
startButton.isVisible = true
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
// TODO: It would be a lot nicer if MediaPlayerController would send an event
|
|
|
|
// when this is necessary instead of updating every time
|
2021-06-19 20:05:38 +02:00
|
|
|
displaySongRating()
|
|
|
|
onProgressChangedTask = null
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
onProgressChangedTask!!.execute()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun changeProgress(ms: Int) {
|
|
|
|
object : SilentBackgroundTask<Void?>(activity) {
|
|
|
|
var msPlayed = 0
|
|
|
|
var duration: Int? = null
|
|
|
|
var seekTo = 0
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun doInBackground(): Void? {
|
|
|
|
msPlayed = max(0, mediaPlayerController.playerPosition)
|
2021-06-19 20:05:38 +02:00
|
|
|
duration = mediaPlayerController.playerDuration
|
|
|
|
val msTotal = duration!!
|
2021-06-19 20:42:03 +02:00
|
|
|
seekTo = (msPlayed + ms).coerceAtMost(msTotal)
|
2021-06-19 20:05:38 +02:00
|
|
|
mediaPlayerController.seekTo(seekTo)
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
override fun done(result: Void?) {
|
2021-06-19 23:09:38 +02:00
|
|
|
progressBar.progress = seekTo
|
2021-06-19 20:05:38 +02:00
|
|
|
}
|
|
|
|
}.execute()
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onDown(me: MotionEvent): Boolean {
|
|
|
|
return false
|
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
@Suppress("ReturnCount")
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onFling(
|
|
|
|
e1: MotionEvent,
|
|
|
|
e2: MotionEvent,
|
|
|
|
velocityX: Float,
|
|
|
|
velocityY: Float
|
|
|
|
): Boolean {
|
|
|
|
val e1X = e1.x
|
|
|
|
val e2X = e2.x
|
|
|
|
val e1Y = e1.y
|
|
|
|
val e2Y = e2.y
|
2021-06-19 20:42:03 +02:00
|
|
|
val absX = abs(velocityX)
|
|
|
|
val absY = abs(velocityY)
|
2021-02-05 21:45:50 +01:00
|
|
|
|
|
|
|
// Right to Left swipe
|
2021-06-19 20:05:38 +02:00
|
|
|
if (e1X - e2X > swipeDistance && absX > swipeVelocity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
mediaPlayerController.next()
|
|
|
|
onCurrentChanged()
|
|
|
|
onSliderProgressChanged()
|
|
|
|
return true
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Left to Right swipe
|
2021-06-19 20:05:38 +02:00
|
|
|
if (e2X - e1X > swipeDistance && absX > swipeVelocity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
mediaPlayerController.previous()
|
|
|
|
onCurrentChanged()
|
|
|
|
onSliderProgressChanged()
|
|
|
|
return true
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Top to Bottom swipe
|
2021-06-19 20:05:38 +02:00
|
|
|
if (e2Y - e1Y > swipeDistance && absY > swipeVelocity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
mediaPlayerController.seekTo(mediaPlayerController.playerPosition + 30000)
|
|
|
|
onSliderProgressChanged()
|
|
|
|
return true
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bottom to Top swipe
|
2021-06-19 20:05:38 +02:00
|
|
|
if (e1Y - e2Y > swipeDistance && absY > swipeVelocity) {
|
2021-06-19 20:42:03 +02:00
|
|
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
2021-06-19 20:05:38 +02:00
|
|
|
mediaPlayerController.seekTo(mediaPlayerController.playerPosition - 8000)
|
|
|
|
onSliderProgressChanged()
|
|
|
|
return true
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
return false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onLongPress(e: MotionEvent) {}
|
|
|
|
override fun onScroll(
|
|
|
|
e1: MotionEvent,
|
|
|
|
e2: MotionEvent,
|
|
|
|
distanceX: Float,
|
|
|
|
distanceY: Float
|
|
|
|
): Boolean {
|
|
|
|
return false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
override fun onShowPress(e: MotionEvent) {}
|
|
|
|
override fun onSingleTapUp(e: MotionEvent): Boolean {
|
|
|
|
return false
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun displaySongRating() {
|
2021-06-19 23:09:38 +02:00
|
|
|
var rating = 0
|
|
|
|
|
|
|
|
if (currentSong?.userRating != null) {
|
|
|
|
rating = currentSong!!.userRating!!
|
|
|
|
}
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
fiveStar1ImageView.setImageDrawable(if (rating > 0) fullStar else hollowStar)
|
|
|
|
fiveStar2ImageView.setImageDrawable(if (rating > 1) fullStar else hollowStar)
|
|
|
|
fiveStar3ImageView.setImageDrawable(if (rating > 2) fullStar else hollowStar)
|
|
|
|
fiveStar4ImageView.setImageDrawable(if (rating > 3) fullStar else hollowStar)
|
|
|
|
fiveStar5ImageView.setImageDrawable(if (rating > 4) fullStar else hollowStar)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun setSongRating(rating: Int) {
|
|
|
|
if (currentSong == null) return
|
|
|
|
displaySongRating()
|
2021-06-19 20:42:03 +02:00
|
|
|
mediaPlayerController.setSongRating(rating)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
private fun showSavePlaylistDialog() {
|
2021-06-19 23:09:38 +02:00
|
|
|
val layout = LayoutInflater.from(this.context).inflate(R.layout.save_playlist, null)
|
|
|
|
|
|
|
|
playlistNameView = layout.findViewById(R.id.save_playlist_name)
|
|
|
|
|
2021-06-19 20:42:03 +02:00
|
|
|
val builder: AlertDialog.Builder = AlertDialog.Builder(context)
|
2021-06-19 20:05:38 +02:00
|
|
|
builder.setTitle(R.string.download_playlist_title)
|
|
|
|
builder.setMessage(R.string.download_playlist_name)
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
builder.setPositiveButton(R.string.common_save) { _, _ ->
|
2021-06-19 20:05:38 +02:00
|
|
|
savePlaylistInBackground(
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistNameView.text.toString()
|
2021-06-19 20:05:38 +02:00
|
|
|
)
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
|
|
|
|
builder.setNegativeButton(R.string.common_cancel) { dialog, _ -> dialog.cancel() }
|
2021-06-19 20:05:38 +02:00
|
|
|
builder.setView(layout)
|
|
|
|
builder.setCancelable(true)
|
|
|
|
val dialog = builder.create()
|
2021-06-19 20:42:03 +02:00
|
|
|
val playlistName = mediaPlayerController.suggestedPlaylistName
|
2021-06-19 20:05:38 +02:00
|
|
|
if (playlistName != null) {
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistNameView.setText(playlistName)
|
2021-06-19 20:05:38 +02:00
|
|
|
} else {
|
|
|
|
val dateFormat: DateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
2021-06-19 20:42:03 +02:00
|
|
|
playlistNameView.setText(dateFormat.format(Date()))
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:05:38 +02:00
|
|
|
dialog.show()
|
|
|
|
}
|
2021-02-05 21:45:50 +01:00
|
|
|
|
2021-06-19 20:05:38 +02:00
|
|
|
companion object {
|
|
|
|
private const val PERCENTAGE_OF_SCREEN_FOR_SWIPE = 5
|
2021-02-05 21:45:50 +01:00
|
|
|
}
|
2021-06-19 20:42:03 +02:00
|
|
|
}
|