Remove SilentBackgroundTask.kt
This commit is contained in:
parent
45e9728e0f
commit
ed152fa52a
|
@ -59,7 +59,6 @@
|
||||||
<ID>NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID>
|
<ID>NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID>
|
||||||
<ID>NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
|
<ID>NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
|
||||||
<ID>NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID>
|
<ID>NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID>
|
||||||
<ID>ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String</ID>
|
|
||||||
<ID>ReturnCount:ServerRowAdapter.kt$ServerRowAdapter$ private fun popupMenuItemClick(menuItem: MenuItem, position: Int): Boolean</ID>
|
<ID>ReturnCount:ServerRowAdapter.kt$ServerRowAdapter$ private fun popupMenuItemClick(menuItem: MenuItem, position: Int): Boolean</ID>
|
||||||
<ID>ReturnCount:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
|
<ID>ReturnCount:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
|
||||||
<ID>TooGenericExceptionCaught:DownloadFile.kt$DownloadFile$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:DownloadFile.kt$DownloadFile$e: Exception</ID>
|
||||||
|
@ -74,7 +73,6 @@
|
||||||
<ID>TooManyFunctions:MediaPlayerService.kt$MediaPlayerService : Service</ID>
|
<ID>TooManyFunctions:MediaPlayerService.kt$MediaPlayerService : Service</ID>
|
||||||
<ID>TooManyFunctions:RESTMusicService.kt$RESTMusicService : MusicService</ID>
|
<ID>TooManyFunctions:RESTMusicService.kt$RESTMusicService : MusicService</ID>
|
||||||
<ID>TooManyFunctions:TrackCollectionFragment.kt$TrackCollectionFragment : Fragment</ID>
|
<ID>TooManyFunctions:TrackCollectionFragment.kt$TrackCollectionFragment : Fragment</ID>
|
||||||
<ID>UtilityClassWithPublicConstructor:CommunicationErrorHandler.kt$CommunicationErrorHandler</ID>
|
|
||||||
<ID>UtilityClassWithPublicConstructor:FragmentTitle.kt$FragmentTitle</ID>
|
<ID>UtilityClassWithPublicConstructor:FragmentTitle.kt$FragmentTitle</ID>
|
||||||
</CurrentIssues>
|
</CurrentIssues>
|
||||||
</SmellBaseline>
|
</SmellBaseline>
|
||||||
|
|
|
@ -20,7 +20,7 @@ package org.moire.ultrasonic.util;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import org.moire.ultrasonic.service.CommunicationErrorHandler;
|
import org.moire.ultrasonic.service.CommunicationErrorUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Sindre Mehus
|
* @author Sindre Mehus
|
||||||
|
@ -54,12 +54,12 @@ public abstract class BackgroundTask<T> implements ProgressListener
|
||||||
|
|
||||||
protected void error(Throwable error)
|
protected void error(Throwable error)
|
||||||
{
|
{
|
||||||
CommunicationErrorHandler.Companion.handleError(error, activity);
|
CommunicationErrorUtil.Companion.handleError(error, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getErrorMessage(Throwable error)
|
protected String getErrorMessage(Throwable error)
|
||||||
{
|
{
|
||||||
return CommunicationErrorHandler.Companion.getErrorMessage(error, activity);
|
return CommunicationErrorUtil.Companion.getErrorMessage(error, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,7 +18,7 @@ import org.koin.core.component.inject
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider
|
import org.moire.ultrasonic.data.ActiveServerProvider
|
||||||
import org.moire.ultrasonic.data.ServerSetting
|
import org.moire.ultrasonic.data.ServerSetting
|
||||||
import org.moire.ultrasonic.domain.MusicFolder
|
import org.moire.ultrasonic.domain.MusicFolder
|
||||||
import org.moire.ultrasonic.service.CommunicationErrorHandler
|
import org.moire.ultrasonic.service.CommunicationErrorUtil
|
||||||
import org.moire.ultrasonic.service.MusicService
|
import org.moire.ultrasonic.service.MusicService
|
||||||
import org.moire.ultrasonic.service.MusicServiceFactory
|
import org.moire.ultrasonic.service.MusicServiceFactory
|
||||||
import org.moire.ultrasonic.util.Settings
|
import org.moire.ultrasonic.util.Settings
|
||||||
|
@ -94,7 +94,7 @@ open class GenericListModel(application: Application) :
|
||||||
|
|
||||||
private fun handleException(exception: Exception, context: Context) {
|
private fun handleException(exception: Exception, context: Context) {
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
CommunicationErrorHandler.handleError(exception, context)
|
CommunicationErrorUtil.handleError(exception, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,8 @@ import java.util.concurrent.ScheduledExecutorService
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
|
@ -65,6 +67,7 @@ import org.moire.ultrasonic.domain.RepeatMode
|
||||||
import org.moire.ultrasonic.featureflags.Feature
|
import org.moire.ultrasonic.featureflags.Feature
|
||||||
import org.moire.ultrasonic.featureflags.FeatureStorage
|
import org.moire.ultrasonic.featureflags.FeatureStorage
|
||||||
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
||||||
|
import org.moire.ultrasonic.service.CommunicationErrorUtil
|
||||||
import org.moire.ultrasonic.service.DownloadFile
|
import org.moire.ultrasonic.service.DownloadFile
|
||||||
import org.moire.ultrasonic.service.LocalMediaPlayer
|
import org.moire.ultrasonic.service.LocalMediaPlayer
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController
|
import org.moire.ultrasonic.service.MediaPlayerController
|
||||||
|
@ -76,19 +79,18 @@ import org.moire.ultrasonic.subsonic.ShareHandler
|
||||||
import org.moire.ultrasonic.util.CancellationToken
|
import org.moire.ultrasonic.util.CancellationToken
|
||||||
import org.moire.ultrasonic.util.Constants
|
import org.moire.ultrasonic.util.Constants
|
||||||
import org.moire.ultrasonic.util.Settings
|
import org.moire.ultrasonic.util.Settings
|
||||||
import org.moire.ultrasonic.util.SilentBackgroundTask
|
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
import org.moire.ultrasonic.view.AutoRepeatButton
|
import org.moire.ultrasonic.view.AutoRepeatButton
|
||||||
import org.moire.ultrasonic.view.SongListAdapter
|
import org.moire.ultrasonic.view.SongListAdapter
|
||||||
import org.moire.ultrasonic.view.VisualizerView
|
import org.moire.ultrasonic.view.VisualizerView
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.concurrent.CancellationException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the Music Player screen of Ultrasonic with playback controls and the playlist
|
* Contains the Music Player screen of Ultrasonic with playback controls and the playlist
|
||||||
*
|
*
|
||||||
* TODO: This class was more or less straight converted from Java legacy code.
|
* TODO: This class was more or less straight converted from Java legacy code.
|
||||||
* There are many places where further cleanup would be nice.
|
* There are many places where further cleanup would be nice.
|
||||||
* The usage of threads and SilentBackgroundTask can be replaced with Coroutines.
|
|
||||||
*/
|
*/
|
||||||
@Suppress("LargeClass", "TooManyFunctions", "MagicNumber")
|
@Suppress("LargeClass", "TooManyFunctions", "MagicNumber")
|
||||||
class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinComponent {
|
class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinComponent {
|
||||||
|
@ -112,8 +114,9 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
private lateinit var executorService: ScheduledExecutorService
|
private lateinit var executorService: ScheduledExecutorService
|
||||||
private var currentPlaying: DownloadFile? = null
|
private var currentPlaying: DownloadFile? = null
|
||||||
private var currentSong: MusicDirectory.Entry? = null
|
private var currentSong: MusicDirectory.Entry? = null
|
||||||
private var onProgressChangedTask: SilentBackgroundTask<Void?>? = null
|
private var onProgressChangedTask: Job? = null
|
||||||
private var rxBusSubscription: Disposable? = null
|
private var rxBusSubscription: Disposable? = null
|
||||||
|
private val scope: CoroutineScope = viewLifecycleOwner.lifecycleScope
|
||||||
|
|
||||||
// Views and UI Elements
|
// Views and UI Elements
|
||||||
private lateinit var visualizerViewLayout: LinearLayout
|
private lateinit var visualizerViewLayout: LinearLayout
|
||||||
|
@ -233,17 +236,11 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
|
|
||||||
previousButton.setOnClickListener {
|
previousButton.setOnClickListener {
|
||||||
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
||||||
object : SilentBackgroundTask<Void?>(activity) {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
override fun doInBackground(): Void? {
|
mediaPlayerController.previous()
|
||||||
mediaPlayerController.previous()
|
onCurrentChanged()
|
||||||
return null
|
onSliderProgressChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun done(result: Void?) {
|
|
||||||
onCurrentChanged()
|
|
||||||
onSliderProgressChanged()
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
previousButton.setOnRepeatListener {
|
previousButton.setOnRepeatListener {
|
||||||
|
@ -253,19 +250,11 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
|
|
||||||
nextButton.setOnClickListener {
|
nextButton.setOnClickListener {
|
||||||
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
||||||
object : SilentBackgroundTask<Boolean?>(activity) {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
override fun doInBackground(): Boolean {
|
mediaPlayerController.next()
|
||||||
mediaPlayerController.next()
|
onCurrentChanged()
|
||||||
return true
|
onSliderProgressChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun done(result: Boolean?) {
|
|
||||||
if (result == true) {
|
|
||||||
onCurrentChanged()
|
|
||||||
onSliderProgressChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nextButton.setOnRepeatListener {
|
nextButton.setOnRepeatListener {
|
||||||
|
@ -273,44 +262,26 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
changeProgress(incrementTime)
|
changeProgress(incrementTime)
|
||||||
}
|
}
|
||||||
pauseButton.setOnClickListener {
|
pauseButton.setOnClickListener {
|
||||||
object : SilentBackgroundTask<Void?>(activity) {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
override fun doInBackground(): Void? {
|
mediaPlayerController.pause()
|
||||||
mediaPlayerController.pause()
|
onCurrentChanged()
|
||||||
return null
|
onSliderProgressChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun done(result: Void?) {
|
|
||||||
onCurrentChanged()
|
|
||||||
onSliderProgressChanged()
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
stopButton.setOnClickListener {
|
stopButton.setOnClickListener {
|
||||||
object : SilentBackgroundTask<Void?>(activity) {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
override fun doInBackground(): Void? {
|
mediaPlayerController.reset()
|
||||||
mediaPlayerController.reset()
|
onCurrentChanged()
|
||||||
return null
|
onSliderProgressChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun done(result: Void?) {
|
|
||||||
onCurrentChanged()
|
|
||||||
onSliderProgressChanged()
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
startButton.setOnClickListener {
|
startButton.setOnClickListener {
|
||||||
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
||||||
object : SilentBackgroundTask<Void?>(activity) {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
override fun doInBackground(): Void? {
|
start()
|
||||||
start()
|
onCurrentChanged()
|
||||||
return null
|
onSliderProgressChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun done(result: Void?) {
|
|
||||||
onCurrentChanged()
|
|
||||||
onSliderProgressChanged()
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
shuffleButton.setOnClickListener {
|
shuffleButton.setOnClickListener {
|
||||||
mediaPlayerController.shuffle()
|
mediaPlayerController.shuffle()
|
||||||
|
@ -338,16 +309,10 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
|
|
||||||
progressBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
|
progressBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
|
||||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||||
object : SilentBackgroundTask<Void?>(activity) {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
override fun doInBackground(): Void? {
|
mediaPlayerController.seekTo(progressBar.progress)
|
||||||
mediaPlayerController.seekTo(progressBar.progress)
|
onSliderProgressChanged()
|
||||||
return null
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun done(result: Void?) {
|
|
||||||
onSliderProgressChanged()
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
||||||
|
@ -356,17 +321,11 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
|
|
||||||
playlistView.setOnItemClickListener { _, _, position, _ ->
|
playlistView.setOnItemClickListener { _, _, position, _ ->
|
||||||
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
|
||||||
object : SilentBackgroundTask<Void?>(activity) {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
override fun doInBackground(): Void? {
|
mediaPlayerController.play(position)
|
||||||
mediaPlayerController.play(position)
|
onCurrentChanged()
|
||||||
return null
|
onSliderProgressChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun done(result: Void?) {
|
|
||||||
onCurrentChanged()
|
|
||||||
onSliderProgressChanged()
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
registerForContextMenu(playlistView)
|
registerForContextMenu(playlistView)
|
||||||
|
|
||||||
|
@ -429,7 +388,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query the Jukebox state off-thread
|
// Query the Jukebox state off-thread
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
try {
|
try {
|
||||||
jukeboxAvailable = mediaPlayerController.isJukeboxAvailable
|
jukeboxAvailable = mediaPlayerController.isJukeboxAvailable
|
||||||
} catch (all: Exception) {
|
} catch (all: Exception) {
|
||||||
|
@ -819,33 +778,28 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
private fun savePlaylistInBackground(playlistName: String) {
|
private fun savePlaylistInBackground(playlistName: String) {
|
||||||
Util.toast(context, resources.getString(R.string.download_playlist_saving, playlistName))
|
Util.toast(context, resources.getString(R.string.download_playlist_saving, playlistName))
|
||||||
mediaPlayerController.suggestedPlaylistName = playlistName
|
mediaPlayerController.suggestedPlaylistName = playlistName
|
||||||
object : SilentBackgroundTask<Void?>(activity) {
|
|
||||||
@Throws(Throwable::class)
|
|
||||||
override fun doInBackground(): Void? {
|
|
||||||
val entries: MutableList<MusicDirectory.Entry> = LinkedList()
|
|
||||||
for (downloadFile in mediaPlayerController.playList) {
|
|
||||||
entries.add(downloadFile.song)
|
|
||||||
}
|
|
||||||
val musicService = getMusicService()
|
|
||||||
musicService.createPlaylist(null, playlistName, entries)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun done(result: Void?) {
|
scope.launch {
|
||||||
|
val entries: MutableList<MusicDirectory.Entry> = LinkedList()
|
||||||
|
for (downloadFile in mediaPlayerController.playList) {
|
||||||
|
entries.add(downloadFile.song)
|
||||||
|
}
|
||||||
|
val musicService = getMusicService()
|
||||||
|
musicService.createPlaylist(null, playlistName, entries)
|
||||||
|
}.invokeOnCompletion {
|
||||||
|
if (it == null || it is CancellationException) {
|
||||||
Util.toast(context, R.string.download_playlist_done)
|
Util.toast(context, R.string.download_playlist_done)
|
||||||
}
|
} else {
|
||||||
|
Timber.e(it, "Exception has occurred in savePlaylistInBackground")
|
||||||
override fun error(error: Throwable) {
|
|
||||||
Timber.e(error, "Exception has occurred in savePlaylistInBackground")
|
|
||||||
val msg = String.format(
|
val msg = String.format(
|
||||||
Locale.ROOT,
|
Locale.ROOT,
|
||||||
"%s %s",
|
"%s %s",
|
||||||
resources.getString(R.string.download_playlist_error),
|
resources.getString(R.string.download_playlist_error),
|
||||||
getErrorMessage(error)
|
CommunicationErrorUtil.getErrorMessage(it, context)
|
||||||
)
|
)
|
||||||
Util.toast(context, msg)
|
Util.toast(context, msg)
|
||||||
}
|
}
|
||||||
}.execute()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleFullScreenAlbumArt() {
|
private fun toggleFullScreenAlbumArt() {
|
||||||
|
@ -979,116 +933,96 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
|
||||||
if (onProgressChangedTask != null) {
|
if (onProgressChangedTask != null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
onProgressChangedTask = object : SilentBackgroundTask<Void?>(activity) {
|
|
||||||
var isJukeboxEnabled = false
|
onProgressChangedTask = scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
var millisPlayed = 0
|
|
||||||
var duration: Int? = null
|
val isJukeboxEnabled: Boolean = mediaPlayerController.isJukeboxEnabled
|
||||||
var playerState: PlayerState? = null
|
val millisPlayed = max(0, mediaPlayerController.playerPosition)
|
||||||
override fun doInBackground(): Void? {
|
val duration = mediaPlayerController.playerDuration
|
||||||
isJukeboxEnabled = mediaPlayerController.isJukeboxEnabled
|
val playerState = mediaPlayerController.playerState
|
||||||
millisPlayed = max(0, mediaPlayerController.playerPosition)
|
|
||||||
duration = mediaPlayerController.playerDuration
|
if (cancellationToken.isCancellationRequested) return@launch
|
||||||
playerState = mediaPlayerController.playerState
|
if (currentPlaying != null) {
|
||||||
return null
|
positionTextView.text = Util.formatTotalDuration(millisPlayed.toLong(), true)
|
||||||
|
durationTextView.text = Util.formatTotalDuration(duration.toLong(), true)
|
||||||
|
progressBar.max =
|
||||||
|
if (duration == 0) 100 else duration // Work-around for apparent bug.
|
||||||
|
progressBar.progress = millisPlayed
|
||||||
|
progressBar.isEnabled = currentPlaying!!.isWorkDone || isJukeboxEnabled
|
||||||
|
} else {
|
||||||
|
positionTextView.setText(R.string.util_zero_time)
|
||||||
|
durationTextView.setText(R.string.util_no_time)
|
||||||
|
progressBar.progress = 0
|
||||||
|
progressBar.max = 0
|
||||||
|
progressBar.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
when (playerState) {
|
||||||
override fun done(result: Void?) {
|
PlayerState.DOWNLOADING -> {
|
||||||
if (cancellationToken.isCancellationRequested) return
|
val progress =
|
||||||
if (currentPlaying != null) {
|
if (currentPlaying != null) currentPlaying!!.progress.value!! else 0
|
||||||
val millisTotal = if (duration == null) 0 else duration!!
|
val downloadStatus = resources.getString(
|
||||||
positionTextView.text = Util.formatTotalDuration(millisPlayed.toLong(), true)
|
R.string.download_playerstate_downloading,
|
||||||
durationTextView.text = Util.formatTotalDuration(millisTotal.toLong(), true)
|
Util.formatPercentage(progress)
|
||||||
progressBar.max =
|
|
||||||
if (millisTotal == 0) 100 else millisTotal // Work-around for apparent bug.
|
|
||||||
progressBar.progress = millisPlayed
|
|
||||||
progressBar.isEnabled = currentPlaying!!.isWorkDone || isJukeboxEnabled
|
|
||||||
} else {
|
|
||||||
positionTextView.setText(R.string.util_zero_time)
|
|
||||||
durationTextView.setText(R.string.util_no_time)
|
|
||||||
progressBar.progress = 0
|
|
||||||
progressBar.max = 0
|
|
||||||
progressBar.isEnabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
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 -> {
|
setTitle(this@PlayerFragment, downloadStatus)
|
||||||
if (mediaPlayerController.isShufflePlayEnabled) {
|
|
||||||
setTitle(
|
|
||||||
this@PlayerFragment,
|
|
||||||
R.string.download_playerstate_playing_shuffle
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
setTitle(this@PlayerFragment, R.string.common_appname)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PlayerState.IDLE,
|
|
||||||
PlayerState.PREPARED,
|
|
||||||
PlayerState.STOPPED,
|
|
||||||
PlayerState.PAUSED,
|
|
||||||
PlayerState.COMPLETED -> {
|
|
||||||
}
|
|
||||||
else -> setTitle(this@PlayerFragment, R.string.common_appname)
|
|
||||||
}
|
}
|
||||||
|
PlayerState.PREPARING -> setTitle(
|
||||||
when (playerState) {
|
this@PlayerFragment,
|
||||||
PlayerState.STARTED -> {
|
R.string.download_playerstate_buffering
|
||||||
pauseButton.isVisible = true
|
)
|
||||||
stopButton.isVisible = false
|
PlayerState.STARTED -> {
|
||||||
startButton.isVisible = false
|
if (mediaPlayerController.isShufflePlayEnabled) {
|
||||||
}
|
setTitle(
|
||||||
PlayerState.DOWNLOADING, PlayerState.PREPARING -> {
|
this@PlayerFragment,
|
||||||
pauseButton.isVisible = false
|
R.string.download_playerstate_playing_shuffle
|
||||||
stopButton.isVisible = true
|
)
|
||||||
startButton.isVisible = false
|
} else {
|
||||||
}
|
setTitle(this@PlayerFragment, R.string.common_appname)
|
||||||
else -> {
|
|
||||||
pauseButton.isVisible = false
|
|
||||||
stopButton.isVisible = false
|
|
||||||
startButton.isVisible = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PlayerState.IDLE,
|
||||||
// TODO: It would be a lot nicer if MediaPlayerController would send an event
|
PlayerState.PREPARED,
|
||||||
// when this is necessary instead of updating every time
|
PlayerState.STOPPED,
|
||||||
displaySongRating()
|
PlayerState.PAUSED,
|
||||||
onProgressChangedTask = null
|
PlayerState.COMPLETED -> {
|
||||||
|
}
|
||||||
|
else -> setTitle(this@PlayerFragment, R.string.common_appname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when (playerState) {
|
||||||
|
PlayerState.STARTED -> {
|
||||||
|
pauseButton.isVisible = true
|
||||||
|
stopButton.isVisible = false
|
||||||
|
startButton.isVisible = false
|
||||||
|
}
|
||||||
|
PlayerState.DOWNLOADING, PlayerState.PREPARING -> {
|
||||||
|
pauseButton.isVisible = false
|
||||||
|
stopButton.isVisible = true
|
||||||
|
startButton.isVisible = false
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
pauseButton.isVisible = false
|
||||||
|
stopButton.isVisible = false
|
||||||
|
startButton.isVisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: It would be a lot nicer if MediaPlayerController would send an event
|
||||||
|
// when this is necessary instead of updating every time
|
||||||
|
displaySongRating()
|
||||||
|
onProgressChangedTask = null
|
||||||
}
|
}
|
||||||
onProgressChangedTask!!.execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeProgress(ms: Int) {
|
private fun changeProgress(ms: Int) {
|
||||||
object : SilentBackgroundTask<Void?>(activity) {
|
scope.launch(CommunicationErrorUtil.handler(context)) {
|
||||||
var msPlayed = 0
|
val msPlayed: Int = max(0, mediaPlayerController.playerPosition)
|
||||||
var duration: Int? = null
|
val duration = mediaPlayerController.playerDuration
|
||||||
var seekTo = 0
|
val seekTo = (msPlayed + ms).coerceAtMost(duration)
|
||||||
override fun doInBackground(): Void? {
|
mediaPlayerController.seekTo(seekTo)
|
||||||
msPlayed = max(0, mediaPlayerController.playerPosition)
|
progressBar.progress = seekTo
|
||||||
duration = mediaPlayerController.playerDuration
|
}
|
||||||
val msTotal = duration!!
|
|
||||||
seekTo = (msPlayed + ms).coerceAtMost(msTotal)
|
|
||||||
mediaPlayerController.seekTo(seekTo)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun done(result: Void?) {
|
|
||||||
progressBar.progress = seekTo
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDown(me: MotionEvent): Boolean {
|
override fun onDown(me: MotionEvent): Boolean {
|
||||||
|
|
|
@ -38,7 +38,7 @@ import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory
|
import org.moire.ultrasonic.domain.MusicDirectory
|
||||||
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.getTitle
|
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.getTitle
|
||||||
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
||||||
import org.moire.ultrasonic.service.CommunicationErrorHandler
|
import org.moire.ultrasonic.service.CommunicationErrorUtil
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController
|
import org.moire.ultrasonic.service.MediaPlayerController
|
||||||
import org.moire.ultrasonic.subsonic.DownloadHandler
|
import org.moire.ultrasonic.subsonic.DownloadHandler
|
||||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||||
|
@ -211,7 +211,7 @@ class TrackCollectionFragment : Fragment() {
|
||||||
|
|
||||||
val handler = CoroutineExceptionHandler { _, exception ->
|
val handler = CoroutineExceptionHandler { _, exception ->
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
CommunicationErrorHandler.handleError(exception, context)
|
CommunicationErrorUtil.handleError(exception, context)
|
||||||
}
|
}
|
||||||
refreshAlbumListView!!.isRefreshing = false
|
refreshAlbumListView!!.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,16 @@ package org.moire.ultrasonic.service
|
||||||
|
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import com.fasterxml.jackson.core.JsonParseException
|
import com.fasterxml.jackson.core.JsonParseException
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.security.cert.CertPathValidatorException
|
import java.security.cert.CertPathValidatorException
|
||||||
import java.security.cert.CertificateException
|
import java.security.cert.CertificateException
|
||||||
import javax.net.ssl.SSLException
|
import javax.net.ssl.SSLException
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException
|
import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException
|
||||||
import org.moire.ultrasonic.api.subsonic.SubsonicRESTException
|
import org.moire.ultrasonic.api.subsonic.SubsonicRESTException
|
||||||
|
@ -37,8 +41,19 @@ import timber.log.Timber
|
||||||
* Contains helper functions to handle the exceptions
|
* Contains helper functions to handle the exceptions
|
||||||
* thrown during the communication with a Subsonic server
|
* thrown during the communication with a Subsonic server
|
||||||
*/
|
*/
|
||||||
class CommunicationErrorHandler {
|
@Suppress("ReturnCount", "UtilityClassWithPublicConstructor")
|
||||||
|
class CommunicationErrorUtil {
|
||||||
companion object {
|
companion object {
|
||||||
|
fun handler(context: Context?, handler: ((CoroutineContext, Throwable) -> Unit)? = null):
|
||||||
|
CoroutineExceptionHandler {
|
||||||
|
return CoroutineExceptionHandler { coroutineContext, exception ->
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
handleError(exception, context)
|
||||||
|
handler?.invoke(coroutineContext, exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun handleError(error: Throwable?, context: Context?) {
|
fun handleError(error: Throwable?, context: Context?) {
|
||||||
Timber.w(error)
|
Timber.w(error)
|
||||||
|
|
||||||
|
@ -53,7 +68,8 @@ class CommunicationErrorHandler {
|
||||||
.create().show()
|
.create().show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getErrorMessage(error: Throwable, context: Context): String {
|
fun getErrorMessage(error: Throwable, context: Context?): String {
|
||||||
|
if (context == null) return "Couldn't get Error message, Context is null"
|
||||||
if (error is IOException && !Util.isNetworkConnected()) {
|
if (error is IOException && !Util.isNetworkConnected()) {
|
||||||
return context.resources.getString(R.string.background_task_no_network)
|
return context.resources.getString(R.string.background_task_no_network)
|
||||||
} else if (error is FileNotFoundException) {
|
} else if (error is FileNotFoundException) {
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* SilentBackgroundTask.kt
|
|
||||||
* Copyright (C) 2009-2021 Ultrasonic developers
|
|
||||||
*
|
|
||||||
* Distributed under terms of the GNU GPLv3 license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.moire.ultrasonic.util
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sindre Mehus
|
|
||||||
*/
|
|
||||||
abstract class SilentBackgroundTask<T>(activity: Activity?) : BackgroundTask<T>(activity) {
|
|
||||||
override fun execute() {
|
|
||||||
val thread: Thread = object : Thread() {
|
|
||||||
override fun run() {
|
|
||||||
try {
|
|
||||||
val result = doInBackground()
|
|
||||||
handler.post { done(result) }
|
|
||||||
} catch (all: Throwable) {
|
|
||||||
handler.post { error(all) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thread.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateProgress(messageId: Int) {}
|
|
||||||
override fun updateProgress(message: String) {}
|
|
||||||
}
|
|
Loading…
Reference in New Issue