mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-08-22 10:09:39 +00:00
Improve Kotlin converted from java in various places
This commit is contained in:
parent
7330541499
commit
3f62ec7e53
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,6 @@ import org.schabi.newpipe.player.notification.NotificationPlayerUi
|
|||||||
import org.schabi.newpipe.util.Localization
|
import org.schabi.newpipe.util.Localization
|
||||||
import org.schabi.newpipe.util.ThemeHelper
|
import org.schabi.newpipe.util.ThemeHelper
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.function.BiConsumer
|
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,13 +46,13 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
// These objects are used to cleanly separate the Service implementation (in this file) and the
|
// These objects are used to cleanly separate the Service implementation (in this file) and the
|
||||||
// media browser and playback preparer implementations. At the moment the playback preparer is
|
// media browser and playback preparer implementations. At the moment the playback preparer is
|
||||||
// only used in conjunction with the media browser.
|
// only used in conjunction with the media browser.
|
||||||
private var mediaBrowserImpl: MediaBrowserImpl? = null
|
private lateinit var mediaBrowserImpl: MediaBrowserImpl
|
||||||
private var mediaBrowserPlaybackPreparer: MediaBrowserPlaybackPreparer? = null
|
private lateinit var mediaBrowserPlaybackPreparer: MediaBrowserPlaybackPreparer
|
||||||
|
|
||||||
// these are instantiated in onCreate() as per
|
// these are instantiated in onCreate() as per
|
||||||
// https://developer.android.com/training/cars/media#browser_workflow
|
// https://developer.android.com/training/cars/media#browser_workflow
|
||||||
private var mediaSession: MediaSessionCompat? = null
|
private lateinit var mediaSession: MediaSessionCompat
|
||||||
private var sessionConnector: MediaSessionConnector? = null
|
private lateinit var sessionConnector: MediaSessionConnector
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the current active player instance. May be null, since the player service can outlive
|
* @return the current active player instance. May be null, since the player service can outlive
|
||||||
@ -68,7 +67,7 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
* The parameter taken by this [Consumer] can be null to indicate the player is being
|
* The parameter taken by this [Consumer] can be null to indicate the player is being
|
||||||
* stopped.
|
* stopped.
|
||||||
*/
|
*/
|
||||||
private var onPlayerStartedOrStopped: Consumer<Player?>? = null
|
private var onPlayerStartedOrStopped: ((player: Player?) -> Unit)? = null
|
||||||
|
|
||||||
//region Service lifecycle
|
//region Service lifecycle
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
@ -80,14 +79,7 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
Localization.assureCorrectAppLanguage(this)
|
Localization.assureCorrectAppLanguage(this)
|
||||||
ThemeHelper.setTheme(this)
|
ThemeHelper.setTheme(this)
|
||||||
|
|
||||||
mediaBrowserImpl = MediaBrowserImpl(
|
mediaBrowserImpl = MediaBrowserImpl(this, this::notifyChildrenChanged)
|
||||||
this,
|
|
||||||
Consumer { parentId: String ->
|
|
||||||
this.notifyChildrenChanged(
|
|
||||||
parentId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// see https://developer.android.com/training/cars/media#browser_workflow
|
// see https://developer.android.com/training/cars/media#browser_workflow
|
||||||
val session = MediaSessionCompat(this, "MediaSessionPlayerServ")
|
val session = MediaSessionCompat(this, "MediaSessionPlayerServ")
|
||||||
@ -98,17 +90,10 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
connector.setMetadataDeduplicationEnabled(true)
|
connector.setMetadataDeduplicationEnabled(true)
|
||||||
|
|
||||||
mediaBrowserPlaybackPreparer = MediaBrowserPlaybackPreparer(
|
mediaBrowserPlaybackPreparer = MediaBrowserPlaybackPreparer(
|
||||||
this,
|
context = this,
|
||||||
BiConsumer { message: String, code: Int ->
|
setMediaSessionError = connector::setCustomErrorMessage,
|
||||||
connector.setCustomErrorMessage(
|
clearMediaSessionError = { connector.setCustomErrorMessage(null) },
|
||||||
message,
|
onPrepare = { player?.onPrepare() }
|
||||||
code
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Runnable { connector.setCustomErrorMessage(null) },
|
|
||||||
Consumer { playWhenReady: Boolean? ->
|
|
||||||
player?.onPrepare()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
connector.setPlaybackPreparer(mediaBrowserPlaybackPreparer)
|
connector.setPlaybackPreparer(mediaBrowserPlaybackPreparer)
|
||||||
|
|
||||||
@ -125,11 +110,8 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
(
|
"onStartCommand() called with: intent = [$intent], extras = [${
|
||||||
"onStartCommand() called with: intent = [" + intent +
|
intent.extras.toDebugString()}], flags = [$flags], startId = [$startId]"
|
||||||
"], extras = [" + intent.extras.toDebugString() +
|
|
||||||
"], flags = [" + flags + "], startId = [" + startId + "]"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +122,7 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
val playerWasNull = (player == null)
|
val playerWasNull = (player == null)
|
||||||
if (playerWasNull) {
|
if (playerWasNull) {
|
||||||
// make sure the player exists, in case the service was resumed
|
// make sure the player exists, in case the service was resumed
|
||||||
player = Player(this, mediaSession!!, sessionConnector!!)
|
player = Player(this, mediaSession, sessionConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Be sure that the player notification is set and the service is started in foreground,
|
// Be sure that the player notification is set and the service is started in foreground,
|
||||||
@ -150,35 +132,29 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
// no one already and starting the service in foreground should not create any issues.
|
// no one already and starting the service in foreground should not create any issues.
|
||||||
// If the service is already started in foreground, requesting it to be started
|
// If the service is already started in foreground, requesting it to be started
|
||||||
// shouldn't do anything.
|
// shouldn't do anything.
|
||||||
player!!.UIs().get(NotificationPlayerUi::class.java)
|
player?.UIs()?.get(NotificationPlayerUi::class)?.createNotificationAndStartForeground()
|
||||||
?.createNotificationAndStartForeground()
|
|
||||||
|
|
||||||
val startedOrStopped = onPlayerStartedOrStopped
|
if (playerWasNull) {
|
||||||
if (playerWasNull && startedOrStopped != null) {
|
|
||||||
// notify that a new player was created (but do it after creating the foreground
|
// notify that a new player was created (but do it after creating the foreground
|
||||||
// notification just to make sure we don't incur, due to slowness, in
|
// notification just to make sure we don't incur, due to slowness, in
|
||||||
// "Context.startForegroundService() did not then call Service.startForeground()")
|
// "Context.startForegroundService() did not then call Service.startForeground()")
|
||||||
startedOrStopped.accept(player)
|
onPlayerStartedOrStopped?.invoke(player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val p = player
|
val p = player
|
||||||
if (Intent.ACTION_MEDIA_BUTTON == intent.action &&
|
if (Intent.ACTION_MEDIA_BUTTON == intent.action && p?.playQueue == null) {
|
||||||
(p == null || p.playQueue == null)
|
// No need to process media button's actions if the player is not working, otherwise
|
||||||
) {
|
// the player service would strangely start with nothing to play
|
||||||
/*
|
// Stop the service in this case, which will be removed from the foreground and its
|
||||||
No need to process media button's actions if the player is not working, otherwise
|
// notification cancelled in its destruction
|
||||||
the player service would strangely start with nothing to play
|
|
||||||
Stop the service in this case, which will be removed from the foreground and its
|
|
||||||
notification cancelled in its destruction
|
|
||||||
*/
|
|
||||||
destroyPlayerAndStopService()
|
destroyPlayerAndStopService()
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
p.handleIntent(intent)
|
p.handleIntent(intent)
|
||||||
p.UIs().get(MediaSessionPlayerUi::class.java)
|
p.UIs().get(MediaSessionPlayerUi::class)
|
||||||
?.handleMediaButtonIntent(intent)
|
?.handleMediaButtonIntent(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,22 +194,22 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
|
|
||||||
cleanup()
|
cleanup()
|
||||||
|
|
||||||
mediaBrowserPlaybackPreparer?.dispose()
|
mediaBrowserPlaybackPreparer.dispose()
|
||||||
mediaSession?.release()
|
mediaSession.release()
|
||||||
mediaBrowserImpl?.dispose()
|
mediaBrowserImpl.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cleanup() {
|
private fun cleanup() {
|
||||||
val p = player
|
val p = player
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
// notify that the player is being destroyed
|
// notify that the player is being destroyed
|
||||||
onPlayerStartedOrStopped?.accept(null)
|
onPlayerStartedOrStopped?.invoke(null)
|
||||||
p.saveAndShutdown()
|
p.saveAndShutdown()
|
||||||
player = null
|
player = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should already be handled by MediaSessionPlayerUi, but just to be sure.
|
// Should already be handled by MediaSessionPlayerUi, but just to be sure.
|
||||||
mediaSession?.setActive(false)
|
mediaSession.setActive(false)
|
||||||
|
|
||||||
// Should already be handled by NotificationUtil.cancelNotificationAndStopForeground() in
|
// Should already be handled by NotificationUtil.cancelNotificationAndStopForeground() in
|
||||||
// NotificationPlayerUi, but let's make sure that the foreground service is stopped.
|
// NotificationPlayerUi, but let's make sure that the foreground service is stopped.
|
||||||
@ -273,24 +249,22 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
(
|
"onBind() called with: intent = [$intent], extras = [${
|
||||||
"onBind() called with: intent = [" + intent +
|
intent.extras.toDebugString()}]"
|
||||||
"], extras = [" + intent.extras.toDebugString() + "]"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BIND_PLAYER_HOLDER_ACTION == intent.action) {
|
return if (BIND_PLAYER_HOLDER_ACTION == intent.action) {
|
||||||
// Note that this binder might be reused multiple times while the service is alive, even
|
// Note that this binder might be reused multiple times while the service is alive, even
|
||||||
// after unbind() has been called: https://stackoverflow.com/a/8794930 .
|
// after unbind() has been called: https://stackoverflow.com/a/8794930 .
|
||||||
return mBinder
|
mBinder
|
||||||
} else if (SERVICE_INTERFACE == intent.action) {
|
} else if (SERVICE_INTERFACE == intent.action) {
|
||||||
// MediaBrowserService also uses its own binder, so for actions related to the media
|
// MediaBrowserService also uses its own binder, so for actions related to the media
|
||||||
// browser service, pass the onBind to the superclass.
|
// browser service, pass the onBind to the superclass.
|
||||||
return super.onBind(intent)
|
super.onBind(intent)
|
||||||
} else {
|
} else {
|
||||||
// This is an unknown request, avoid returning any binder to not leak objects.
|
// This is an unknown request, avoid returning any binder to not leak objects.
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,9 +281,9 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
* by the [Consumer] can be null to indicate that the player is stopping.
|
* by the [Consumer] can be null to indicate that the player is stopping.
|
||||||
* @param listener the listener to set or unset
|
* @param listener the listener to set or unset
|
||||||
*/
|
*/
|
||||||
fun setPlayerListener(listener: Consumer<Player?>?) {
|
fun setPlayerListener(listener: ((player: Player?) -> Unit)?) {
|
||||||
this.onPlayerStartedOrStopped = listener
|
this.onPlayerStartedOrStopped = listener
|
||||||
listener?.accept(player)
|
listener?.invoke(player)
|
||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
@ -320,14 +294,14 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
rootHints: Bundle?
|
rootHints: Bundle?
|
||||||
): BrowserRoot? {
|
): BrowserRoot? {
|
||||||
// TODO check if the accessing package has permission to view data
|
// TODO check if the accessing package has permission to view data
|
||||||
return mediaBrowserImpl?.onGetRoot(clientPackageName, clientUid, rootHints)
|
return mediaBrowserImpl.onGetRoot(clientPackageName, clientUid, rootHints)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoadChildren(
|
override fun onLoadChildren(
|
||||||
parentId: String,
|
parentId: String,
|
||||||
result: Result<List<MediaBrowserCompat.MediaItem>>
|
result: Result<List<MediaBrowserCompat.MediaItem>>
|
||||||
) {
|
) {
|
||||||
mediaBrowserImpl?.onLoadChildren(parentId, result)
|
mediaBrowserImpl.onLoadChildren(parentId, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSearch(
|
override fun onSearch(
|
||||||
@ -335,7 +309,7 @@ class PlayerService : MediaBrowserServiceCompat() {
|
|||||||
extras: Bundle?,
|
extras: Bundle?,
|
||||||
result: Result<List<MediaBrowserCompat.MediaItem>>
|
result: Result<List<MediaBrowserCompat.MediaItem>>
|
||||||
) {
|
) {
|
||||||
mediaBrowserImpl?.onSearch(query, result)
|
mediaBrowserImpl.onSearch(query, result)
|
||||||
} //endregion
|
} //endregion
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -20,7 +20,6 @@ import org.schabi.newpipe.player.event.PlayerServiceEventListener
|
|||||||
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener
|
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue
|
import org.schabi.newpipe.player.playqueue.PlayQueue
|
||||||
import org.schabi.newpipe.util.NavigationHelper
|
import org.schabi.newpipe.util.NavigationHelper
|
||||||
import java.util.function.Consumer
|
|
||||||
|
|
||||||
private val DEBUG = MainActivity.DEBUG
|
private val DEBUG = MainActivity.DEBUG
|
||||||
private val TAG: String = PlayerHolder::class.java.getSimpleName()
|
private val TAG: String = PlayerHolder::class.java.getSimpleName()
|
||||||
@ -40,9 +39,9 @@ object PlayerHolder {
|
|||||||
private val player: Player?
|
private val player: Player?
|
||||||
get() = playerService?.player
|
get() = playerService?.player
|
||||||
|
|
||||||
|
// player play queue might be null e.g. while player is starting
|
||||||
private val playQueue: PlayQueue?
|
private val playQueue: PlayQueue?
|
||||||
get() = // player play queue might be null e.g. while player is starting
|
get() = this.player?.playQueue
|
||||||
this.player?.playQueue
|
|
||||||
|
|
||||||
val type: PlayerType?
|
val type: PlayerType?
|
||||||
/**
|
/**
|
||||||
@ -78,8 +77,8 @@ object PlayerHolder {
|
|||||||
|
|
||||||
// Force reload data from service
|
// Force reload data from service
|
||||||
newListener?.let { listener ->
|
newListener?.let { listener ->
|
||||||
playerService?.let {
|
playerService?.let { service ->
|
||||||
listener.onServiceConnected(it)
|
listener.onServiceConnected(service)
|
||||||
startPlayerListener()
|
startPlayerListener()
|
||||||
// ^ will call listener.onPlayerConnected() down the line if there is an active player
|
// ^ will call listener.onPlayerConnected() down the line if there is an active player
|
||||||
}
|
}
|
||||||
@ -103,7 +102,7 @@ object PlayerHolder {
|
|||||||
newListener: PlayerServiceExtendedEventListener?
|
newListener: PlayerServiceExtendedEventListener?
|
||||||
) {
|
) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "startService() called with playAfterConnect=" + playAfterConnect)
|
Log.d(TAG, "startService() called with playAfterConnect=$playAfterConnect")
|
||||||
}
|
}
|
||||||
val context = this.commonContext
|
val context = this.commonContext
|
||||||
setListener(newListener)
|
setListener(newListener)
|
||||||
@ -162,21 +161,15 @@ object PlayerHolder {
|
|||||||
|
|
||||||
val s = localBinder.service
|
val s = localBinder.service
|
||||||
requireNotNull(s) {
|
requireNotNull(s) {
|
||||||
(
|
|
||||||
"PlayerService.LocalBinder.getService() must never be" +
|
"PlayerService.LocalBinder.getService() must never be" +
|
||||||
"null after the service connects"
|
"null after the service connects"
|
||||||
)
|
|
||||||
}
|
}
|
||||||
playerService = s
|
playerService = s
|
||||||
val l = listener
|
listener?.let { l ->
|
||||||
if (l != null) {
|
|
||||||
l.onServiceConnected(s)
|
l.onServiceConnected(s)
|
||||||
player?.let {
|
player?.let { l.onPlayerConnected(it, playAfterConnect) }
|
||||||
l.onPlayerConnected(it, playAfterConnect)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
startPlayerListener()
|
startPlayerListener()
|
||||||
|
|
||||||
// ^ will call listener.onPlayerConnected() down the line if there is an active player
|
// ^ will call listener.onPlayerConnected() down the line if there is an active player
|
||||||
|
|
||||||
// notify the main activity that binding the service has completed, so that it can
|
// notify the main activity that binding the service has completed, so that it can
|
||||||
@ -305,9 +298,8 @@ object PlayerHolder {
|
|||||||
* or stopping. This is necessary since the service outlives the player e.g. to answer Android
|
* or stopping. This is necessary since the service outlives the player e.g. to answer Android
|
||||||
* Auto media browser queries.
|
* Auto media browser queries.
|
||||||
*/
|
*/
|
||||||
private val playerStateListener = Consumer { player: Player? ->
|
private val playerStateListener: (Player?) -> Unit = { player: Player? ->
|
||||||
val l = listener
|
listener?.let { l ->
|
||||||
if (l != null) {
|
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
// player.fragmentListener=null is already done by player.stopActivityBinding(),
|
// player.fragmentListener=null is already done by player.stopActivityBinding(),
|
||||||
// which is called by player.destroy(), which is in turn called by PlayerService
|
// which is called by player.destroy(), which is in turn called by PlayerService
|
||||||
|
@ -36,7 +36,6 @@ import org.schabi.newpipe.local.playlist.RemotePlaylistManager
|
|||||||
import org.schabi.newpipe.util.ExtractorHelper
|
import org.schabi.newpipe.util.ExtractorHelper
|
||||||
import org.schabi.newpipe.util.ServiceHelper
|
import org.schabi.newpipe.util.ServiceHelper
|
||||||
import org.schabi.newpipe.util.image.ImageStrategy
|
import org.schabi.newpipe.util.image.ImageStrategy
|
||||||
import java.util.function.Consumer
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to cleanly separate the Service implementation (in
|
* This class is used to cleanly separate the Service implementation (in
|
||||||
@ -46,16 +45,14 @@ import java.util.function.Consumer
|
|||||||
*/
|
*/
|
||||||
class MediaBrowserImpl(
|
class MediaBrowserImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
notifyChildrenChanged: Consumer<String>, // parentId
|
notifyChildrenChanged: (parentId: String) -> Unit,
|
||||||
) {
|
) {
|
||||||
private val database = NewPipeDatabase.getInstance(context)
|
private val database = NewPipeDatabase.getInstance(context)
|
||||||
private var disposables = CompositeDisposable()
|
private var disposables = CompositeDisposable()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// this will listen to changes in the bookmarks until this MediaBrowserImpl is dispose()d
|
// this will listen to changes in the bookmarks until this MediaBrowserImpl is dispose()d
|
||||||
disposables.add(
|
disposables.add(getMergedPlaylists().subscribe { notifyChildrenChanged(ID_BOOKMARKS) })
|
||||||
getMergedPlaylists().subscribe { notifyChildrenChanged.accept(ID_BOOKMARKS) }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//region Cleanup
|
//region Cleanup
|
||||||
@ -204,6 +201,7 @@ class MediaBrowserImpl(
|
|||||||
val builder = MediaDescriptionCompat.Builder()
|
val builder = MediaDescriptionCompat.Builder()
|
||||||
builder.setMediaId(createMediaIdForInfoItem(item))
|
builder.setMediaId(createMediaIdForInfoItem(item))
|
||||||
.setTitle(item.name)
|
.setTitle(item.name)
|
||||||
|
.setIconUri(ImageStrategy.choosePreferredImage(item.thumbnails)?.toUri())
|
||||||
|
|
||||||
when (item.infoType) {
|
when (item.infoType) {
|
||||||
InfoType.STREAM -> builder.setSubtitle((item as StreamInfoItem).uploaderName)
|
InfoType.STREAM -> builder.setSubtitle((item as StreamInfoItem).uploaderName)
|
||||||
@ -212,10 +210,6 @@ class MediaBrowserImpl(
|
|||||||
else -> return null
|
else -> return null
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageStrategy.choosePreferredImage(item.thumbnails)?.let {
|
|
||||||
builder.setIconUri(imageUriOrNullIfDisabled(it))
|
|
||||||
}
|
|
||||||
|
|
||||||
return MediaBrowserCompat.MediaItem(
|
return MediaBrowserCompat.MediaItem(
|
||||||
builder.build(),
|
builder.build(),
|
||||||
MediaBrowserCompat.MediaItem.FLAG_PLAYABLE
|
MediaBrowserCompat.MediaItem.FLAG_PLAYABLE
|
||||||
@ -276,10 +270,7 @@ class MediaBrowserImpl(
|
|||||||
builder.setMediaId(createMediaIdForPlaylistIndex(true, playlistId, index))
|
builder.setMediaId(createMediaIdForPlaylistIndex(true, playlistId, index))
|
||||||
.setTitle(item.name)
|
.setTitle(item.name)
|
||||||
.setSubtitle(item.uploaderName)
|
.setSubtitle(item.uploaderName)
|
||||||
|
.setIconUri(ImageStrategy.choosePreferredImage(item.thumbnails)?.toUri())
|
||||||
ImageStrategy.choosePreferredImage(item.thumbnails)?.let {
|
|
||||||
builder.setIconUri(imageUriOrNullIfDisabled(it))
|
|
||||||
}
|
|
||||||
|
|
||||||
return MediaBrowserCompat.MediaItem(
|
return MediaBrowserCompat.MediaItem(
|
||||||
builder.build(),
|
builder.build(),
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package org.schabi.newpipe.player.ui
|
package org.schabi.newpipe.player.ui
|
||||||
|
|
||||||
import org.schabi.newpipe.util.GuardedByMutex
|
import org.schabi.newpipe.util.GuardedByMutex
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.safeCast
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [PlayerUiList] starting with the provided player uis. The provided player uis
|
* Creates a [PlayerUiList] starting with the provided player uis. The provided player uis
|
||||||
@ -84,20 +86,20 @@ class PlayerUiList(vararg initialPlayerUis: PlayerUi) {
|
|||||||
* @param T the class type parameter
|
* @param T the class type parameter
|
||||||
* @return the first player UI of the required type found in the list, or null
|
* @return the first player UI of the required type found in the list, or null
|
||||||
</T> */
|
</T> */
|
||||||
fun <T : PlayerUi> get(playerUiType: Class<T>): T? =
|
fun <T : PlayerUi> get(playerUiType: KClass<T>): T? =
|
||||||
playerUis.runWithLockSync {
|
playerUis.runWithLockSync {
|
||||||
for (ui in lockData) {
|
for (ui in lockData) {
|
||||||
if (playerUiType.isInstance(ui)) {
|
if (playerUiType.isInstance(ui)) {
|
||||||
when (val r = playerUiType.cast(ui)) {
|
|
||||||
// try all UIs before returning null
|
// try all UIs before returning null
|
||||||
null -> continue
|
playerUiType.safeCast(ui)?.let { return@runWithLockSync it }
|
||||||
else -> return@runWithLockSync r
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@runWithLockSync null
|
return@runWithLockSync null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T : PlayerUi> get(playerUiType: Class<T>): T? =
|
||||||
|
get(playerUiType.kotlin)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls the provided consumer on all player UIs in the list, in order of addition.
|
* Calls the provided consumer on all player UIs in the list, in order of addition.
|
||||||
* @param consumer the consumer to call with player UIs
|
* @param consumer the consumer to call with player UIs
|
||||||
|
Loading…
x
Reference in New Issue
Block a user