diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java deleted file mode 100644 index 24fec3b8a..000000000 --- a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.schabi.newpipe.player.ui; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.function.Consumer; - -public final class PlayerUiList { - final List playerUis = new ArrayList<>(); - - /** - * Creates a {@link PlayerUiList} starting with the provided player uis. The provided player uis - * will not be prepared like those passed to {@link #addAndPrepare(PlayerUi)}, because when - * the {@link PlayerUiList} constructor is called, the player is still not running and it - * wouldn't make sense to initialize uis then. Instead the player will initialize them by doing - * proper calls to {@link #call(Consumer)}. - * - * @param initialPlayerUis the player uis this list should start with; the order will be kept - */ - public PlayerUiList(final PlayerUi... initialPlayerUis) { - playerUis.addAll(List.of(initialPlayerUis)); - } - - /** - * Adds the provided player ui to the list and calls on it the initialization functions that - * apply based on the current player state. The preparation step needs to be done since when UIs - * are removed and re-added, the player will not call e.g. initPlayer again since the exoplayer - * is already initialized, but we need to notify the newly built UI that the player is ready - * nonetheless. - * @param playerUi the player ui to prepare and add to the list; its {@link - * PlayerUi#getPlayer()} will be used to query information about the player - * state - */ - public void addAndPrepare(final PlayerUi playerUi) { - if (playerUi.getPlayer().getFragmentListener().isPresent()) { - // make sure UIs know whether a service is connected or not - playerUi.onFragmentListenerSet(); - } - - if (!playerUi.getPlayer().exoPlayerIsNull()) { - playerUi.initPlayer(); - if (playerUi.getPlayer().getPlayQueue() != null) { - playerUi.initPlayback(); - } - } - - playerUis.add(playerUi); - } - - /** - * Destroys all matching player UIs and removes them from the list. - * @param playerUiType the class of the player UI to destroy; the {@link - * Class#isInstance(Object)} method will be used, so even subclasses will be - * destroyed and removed - * @param the class type parameter - */ - public void destroyAll(final Class playerUiType) { - playerUis.stream() - .filter(playerUiType::isInstance) - .forEach(playerUi -> { - playerUi.destroyPlayer(); - playerUi.destroy(); - }); - playerUis.removeIf(playerUiType::isInstance); - } - - /** - * @param playerUiType the class of the player UI to return; the {@link - * Class#isInstance(Object)} method will be used, so even subclasses could - * be returned - * @param the class type parameter - * @return the first player UI of the required type found in the list, or an empty {@link - * Optional} otherwise - */ - public Optional get(final Class playerUiType) { - return playerUis.stream() - .filter(playerUiType::isInstance) - .map(playerUiType::cast) - .findFirst(); - } - - /** - * Calls the provided consumer on all player UIs in the list, in order of addition. - * @param consumer the consumer to call with player UIs - */ - public void call(final Consumer consumer) { - //noinspection SimplifyStreamApiCallChains - playerUis.stream().forEachOrdered(consumer); - } -} diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.kt b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.kt new file mode 100644 index 000000000..46090285f --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.kt @@ -0,0 +1,92 @@ +package org.schabi.newpipe.player.ui + +import androidx.core.util.Consumer +import java.util.Optional + +class PlayerUiList(vararg initialPlayerUis: PlayerUi) { + val playerUis = mutableListOf() + + /** + * Creates a [PlayerUiList] starting with the provided player uis. The provided player uis + * will not be prepared like those passed to [.addAndPrepare], because when + * the [PlayerUiList] constructor is called, the player is still not running and it + * wouldn't make sense to initialize uis then. Instead the player will initialize them by doing + * proper calls to [.call]. + * + * @param initialPlayerUis the player uis this list should start with; the order will be kept + */ + init { + playerUis.addAll(listOf(*initialPlayerUis)) + } + + /** + * Adds the provided player ui to the list and calls on it the initialization functions that + * apply based on the current player state. The preparation step needs to be done since when UIs + * are removed and re-added, the player will not call e.g. initPlayer again since the exoplayer + * is already initialized, but we need to notify the newly built UI that the player is ready + * nonetheless. + * @param playerUi the player ui to prepare and add to the list; its [PlayerUi.getPlayer] + * will be used to query information about the player state + */ + fun addAndPrepare(playerUi: PlayerUi) { + if (playerUi.getPlayer().fragmentListener.isPresent) { + // make sure UIs know whether a service is connected or not + playerUi.onFragmentListenerSet() + } + + if (!playerUi.getPlayer().exoPlayerIsNull()) { + playerUi.initPlayer() + if (playerUi.getPlayer().playQueue != null) { + playerUi.initPlayback() + } + } + + playerUis.add(playerUi) + } + + /** + * Destroys all matching player UIs and removes them from the list. + * @param playerUiType the class of the player UI to destroy; + * the [Class.isInstance] method will be used, so even subclasses will be + * destroyed and removed + * @param T the class type parameter + * */ + fun destroyAll(playerUiType: Class) { + for (ui in playerUis) { + if (playerUiType.isInstance(ui)) { + ui.destroyPlayer() + ui.destroy() + playerUis.remove(ui) + } + } + } + + /** + * @param playerUiType the class of the player UI to return; + * the [Class.isInstance] method will be used, so even subclasses could be returned + * @param T the class type parameter + * @return the first player UI of the required type found in the list, or an empty + * [ ] otherwise + */ + fun get(playerUiType: Class): Optional { + for (ui in playerUis) { + if (playerUiType.isInstance(ui)) { + when (val r = playerUiType.cast(ui)) { + null -> continue + else -> return Optional.of(r) + } + } + } + return Optional.empty() + } + + /** + * Calls the provided consumer on all player UIs in the list, in order of addition. + * @param consumer the consumer to call with player UIs + */ + fun call(consumer: java.util.function.Consumer) { + for (ui in playerUis) { + consumer.accept(ui) + } + } +}