summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas <tschneider.ac@gmail.com>2023-03-19 12:05:33 +0100
committerThomas <tschneider.ac@gmail.com>2023-03-19 12:05:33 +0100
commit0a9c5162ca7bc1d6cdfab13561b4caf61c10db0d (patch)
tree467c09d8830d23409f9f9a0aa2cfeaa6f305a6d8
parentf082611b0279848ce75452e0d2c7938841a148b9 (diff)
track selector
-rw-r--r--app/src/main/java/app/fedilab/android/peertube/activities/PeertubeActivity.java15
-rw-r--r--app/src/main/java/app/fedilab/android/peertube/client/data/VideoData.java5
-rw-r--r--app/src/main/java/app/fedilab/android/peertube/helper/TrackSelectionDialog.java352
-rw-r--r--app/src/main/res/layouts/peertube/layout/track_selection_dialog.xml55
-rw-r--r--app/src/main/res/values/strings.xml4
-rw-r--r--app/src/main/res/values/themes.xml2
6 files changed, 426 insertions, 7 deletions
diff --git a/app/src/main/java/app/fedilab/android/peertube/activities/PeertubeActivity.java b/app/src/main/java/app/fedilab/android/peertube/activities/PeertubeActivity.java
index 2c41ebb18..80397d82a 100644
--- a/app/src/main/java/app/fedilab/android/peertube/activities/PeertubeActivity.java
+++ b/app/src/main/java/app/fedilab/android/peertube/activities/PeertubeActivity.java
@@ -149,7 +149,6 @@ import app.fedilab.android.peertube.client.data.PlaylistData;
import app.fedilab.android.peertube.client.data.PluginData;
import app.fedilab.android.peertube.client.data.VideoData;
import app.fedilab.android.peertube.client.entities.Error;
-import app.fedilab.android.peertube.client.entities.File;
import app.fedilab.android.peertube.client.entities.MenuItemView;
import app.fedilab.android.peertube.client.entities.PlaylistExist;
import app.fedilab.android.peertube.client.entities.Report;
@@ -159,6 +158,7 @@ import app.fedilab.android.peertube.drawer.MenuAdapter;
import app.fedilab.android.peertube.drawer.MenuItemAdapter;
import app.fedilab.android.peertube.helper.Helper;
import app.fedilab.android.peertube.helper.HelperInstance;
+import app.fedilab.android.peertube.helper.TrackSelectionDialog;
import app.fedilab.android.peertube.viewmodel.CaptionsVM;
import app.fedilab.android.peertube.viewmodel.CommentVM;
import app.fedilab.android.peertube.viewmodel.PlaylistsVM;
@@ -203,7 +203,7 @@ public class PeertubeActivity extends BasePeertubeActivity implements CommentLis
private String currentCaption;
private boolean isRemote;
private boolean willPlayFromIntent;
-
+ private boolean isShowingTrackSelectionDialog;
private Status status;
public static void hideKeyboard(Activity activity) {
@@ -1765,7 +1765,7 @@ public class PeertubeActivity extends BasePeertubeActivity implements CommentLis
List<MenuItemView> items = new ArrayList<>();
switch (action) {
case RESOLUTION:
- binding.subMenuTitle.setText(R.string.pickup_resolution);
+ /*binding.subMenuTitle.setText(R.string.pickup_resolution);
int position = 0;
for (File file : peertube.getAllFile(PeertubeActivity.this)) {
@@ -1790,6 +1790,15 @@ public class PeertubeActivity extends BasePeertubeActivity implements CommentLis
position++;
}
}
+ }*/
+ if (!isShowingTrackSelectionDialog
+ && TrackSelectionDialog.willHaveContent(player)) {
+ isShowingTrackSelectionDialog = true;
+ TrackSelectionDialog trackSelectionDialog =
+ TrackSelectionDialog.createForPlayer(
+ player,
+ /* onDismissListener= */ dismissedDialog -> isShowingTrackSelectionDialog = false);
+ trackSelectionDialog.show(getSupportFragmentManager(), /* tag= */ null);
}
break;
case SPEED:
diff --git a/app/src/main/java/app/fedilab/android/peertube/client/data/VideoData.java b/app/src/main/java/app/fedilab/android/peertube/client/data/VideoData.java
index 55d9bb250..1b53731cc 100644
--- a/app/src/main/java/app/fedilab/android/peertube/client/data/VideoData.java
+++ b/app/src/main/java/app/fedilab/android/peertube/client/data/VideoData.java
@@ -146,7 +146,7 @@ public class VideoData implements Serializable {
}
public List<File> getAllFile(Context context) {
- if (files != null && files.size() > 0) {
+ if (files != null && files.size() > 0) { //Old support
return files;
} else if (streamingPlaylists != null) {
List<File> files = new ArrayList<>();
@@ -156,9 +156,6 @@ public class VideoData implements Serializable {
file.setFileUrl(streamingPlaylists.getPlaylistUrl());
file.setFileDownloadUrl(streamingPlaylists.getPlaylistUrl());
files.add(file);
- if (streamingPlaylists.getFiles().size() > 0) {
- files.addAll(streamingPlaylists.getFiles());
- }
}
return files;
}
diff --git a/app/src/main/java/app/fedilab/android/peertube/helper/TrackSelectionDialog.java b/app/src/main/java/app/fedilab/android/peertube/helper/TrackSelectionDialog.java
new file mode 100644
index 000000000..897950679
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/peertube/helper/TrackSelectionDialog.java
@@ -0,0 +1,352 @@
+package app.fedilab.android.peertube.helper;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatDialog;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.Tracks;
+import com.google.android.exoplayer2.source.TrackGroup;
+import com.google.android.exoplayer2.trackselection.TrackSelectionOverride;
+import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
+import com.google.android.exoplayer2.ui.TrackSelectionView;
+import com.google.android.material.tabs.TabLayout;
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import app.fedilab.android.R;
+
+/**
+ * Dialog to select tracks.
+ */
+public final class TrackSelectionDialog extends DialogFragment {
+
+ public static final ImmutableList<Integer> SUPPORTED_TRACK_TYPES =
+ ImmutableList.of(C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_TEXT);
+ private final SparseArray<TrackSelectionViewFragment> tabFragments;
+ private final ArrayList<Integer> tabTrackTypes;
+ private int titleId;
+ private DialogInterface.OnClickListener onClickListener;
+ private DialogInterface.OnDismissListener onDismissListener;
+
+ public TrackSelectionDialog() {
+ tabFragments = new SparseArray<>();
+ tabTrackTypes = new ArrayList<>();
+ // Retain instance across activity re-creation to prevent losing access to init data.
+ setRetainInstance(true);
+ }
+
+ /**
+ * Returns whether a track selection dialog will have content to display if initialized with the
+ * specified {@link Player}.
+ */
+ public static boolean willHaveContent(Player player) {
+ return willHaveContent(player.getCurrentTracks());
+ }
+
+ /**
+ * Returns whether a track selection dialog will have content to display if initialized with the
+ * specified {@link Tracks}.
+ */
+ public static boolean willHaveContent(Tracks tracks) {
+ for (Tracks.Group trackGroup : tracks.getGroups()) {
+ if (SUPPORTED_TRACK_TYPES.contains(trackGroup.getType())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates a dialog for a given {@link Player}, whose parameters will be automatically updated
+ * when tracks are selected.
+ *
+ * @param player The {@link Player}.
+ * @param onDismissListener A {@link DialogInterface.OnDismissListener} to call when the dialog is
+ * dismissed.
+ */
+ public static TrackSelectionDialog createForPlayer(
+ Player player, DialogInterface.OnDismissListener onDismissListener) {
+ return createForTracksAndParameters(
+ R.string.track_selection_title,
+ player.getCurrentTracks(),
+ player.getTrackSelectionParameters(),
+ /* allowAdaptiveSelections= */ true,
+ /* allowMultipleOverrides= */ false,
+ player::setTrackSelectionParameters,
+ onDismissListener);
+ }
+
+ /**
+ * Creates a dialog for given {@link Tracks} and {@link TrackSelectionParameters}.
+ *
+ * @param titleId The resource id of the dialog title.
+ * @param tracks The {@link Tracks} describing the tracks to display.
+ * @param trackSelectionParameters The initial {@link TrackSelectionParameters}.
+ * @param allowAdaptiveSelections Whether adaptive selections (consisting of more than one track)
+ * can be made.
+ * @param allowMultipleOverrides Whether tracks from multiple track groups can be selected.
+ * @param trackSelectionListener Called when tracks are selected.
+ * @param onDismissListener {@link DialogInterface.OnDismissListener} called when the dialog is
+ * dismissed.
+ */
+ public static TrackSelectionDialog createForTracksAndParameters(
+ int titleId,
+ Tracks tracks,
+ TrackSelectionParameters trackSelectionParameters,
+ boolean allowAdaptiveSelections,
+ boolean allowMultipleOverrides,
+ TrackSelectionListener trackSelectionListener,
+ DialogInterface.OnDismissListener onDismissListener) {
+ TrackSelectionDialog trackSelectionDialog = new TrackSelectionDialog();
+ trackSelectionDialog.init(
+ tracks,
+ trackSelectionParameters,
+ titleId,
+ allowAdaptiveSelections,
+ allowMultipleOverrides,
+ /* onClickListener= */ (dialog, which) -> {
+ TrackSelectionParameters.Builder builder = trackSelectionParameters.buildUpon();
+ for (int i = 0; i < SUPPORTED_TRACK_TYPES.size(); i++) {
+ int trackType = SUPPORTED_TRACK_TYPES.get(i);
+ builder.setTrackTypeDisabled(trackType, trackSelectionDialog.getIsDisabled(trackType));
+ builder.clearOverridesOfType(trackType);
+ Map<TrackGroup, TrackSelectionOverride> overrides =
+ trackSelectionDialog.getOverrides(trackType);
+ for (TrackSelectionOverride override : overrides.values()) {
+ builder.addOverride(override);
+ }
+ }
+ trackSelectionListener.onTracksSelected(builder.build());
+ },
+ onDismissListener);
+ return trackSelectionDialog;
+ }
+
+ private static String getTrackTypeString(Resources resources, @C.TrackType int trackType) {
+ switch (trackType) {
+ case C.TRACK_TYPE_VIDEO:
+ return resources.getString(R.string.exo_track_selection_title_video);
+ case C.TRACK_TYPE_AUDIO:
+ return resources.getString(R.string.exo_track_selection_title_audio);
+ case C.TRACK_TYPE_TEXT:
+ return resources.getString(R.string.exo_track_selection_title_text);
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private void init(
+ Tracks tracks,
+ TrackSelectionParameters trackSelectionParameters,
+ int titleId,
+ boolean allowAdaptiveSelections,
+ boolean allowMultipleOverrides,
+ DialogInterface.OnClickListener onClickListener,
+ DialogInterface.OnDismissListener onDismissListener) {
+ this.titleId = titleId;
+ this.onClickListener = onClickListener;
+ this.onDismissListener = onDismissListener;
+
+ for (int i = 0; i < SUPPORTED_TRACK_TYPES.size(); i++) {
+ @C.TrackType int trackType = SUPPORTED_TRACK_TYPES.get(i);
+ ArrayList<Tracks.Group> trackGroups = new ArrayList<>();
+ for (Tracks.Group trackGroup : tracks.getGroups()) {
+ if (trackGroup.getType() == trackType) {
+ trackGroups.add(trackGroup);
+ }
+ }
+ if (!trackGroups.isEmpty()) {
+ TrackSelectionViewFragment tabFragment = new TrackSelectionViewFragment();
+ tabFragment.init(
+ trackGroups,
+ trackSelectionParameters.disabledTrackTypes.contains(trackType),
+ trackSelectionParameters.overrides,
+ allowAdaptiveSelections,
+ allowMultipleOverrides);
+ tabFragments.put(trackType, tabFragment);
+ tabTrackTypes.add(trackType);
+ }
+ }
+ }
+
+ /**
+ * Returns whether the disabled option is selected for the specified track type.
+ *
+ * @param trackType The track type.
+ * @return Whether the disabled option is selected for the track type.
+ */
+ public boolean getIsDisabled(int trackType) {
+ TrackSelectionViewFragment trackView = tabFragments.get(trackType);
+ return trackView != null && trackView.isDisabled;
+ }
+
+ /**
+ * Returns the selected track overrides for the specified track type.
+ *
+ * @param trackType The track type.
+ * @return The track overrides for the track type.
+ */
+ public Map<TrackGroup, TrackSelectionOverride> getOverrides(int trackType) {
+ TrackSelectionViewFragment trackView = tabFragments.get(trackType);
+ return trackView == null ? Collections.emptyMap() : trackView.overrides;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // We need to own the view to let tab layout work correctly on all API levels. We can't use
+ // AlertDialog because it owns the view itself, so we use AppCompatDialog instead, themed using
+ // the AlertDialog theme overlay with force-enabled title.
+ AppCompatDialog dialog =
+ new AppCompatDialog(getActivity());
+ dialog.setTitle(titleId);
+ return dialog;
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ onDismissListener.onDismiss(dialog);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View dialogView = inflater.inflate(R.layout.track_selection_dialog, container, false);
+ TabLayout tabLayout = dialogView.findViewById(R.id.track_selection_dialog_tab_layout);
+ ViewPager viewPager = dialogView.findViewById(R.id.track_selection_dialog_view_pager);
+ Button cancelButton = dialogView.findViewById(R.id.track_selection_dialog_cancel_button);
+ Button okButton = dialogView.findViewById(R.id.track_selection_dialog_ok_button);
+ viewPager.setAdapter(new FragmentAdapter(getChildFragmentManager()));
+ tabLayout.setupWithViewPager(viewPager);
+ tabLayout.setVisibility(tabFragments.size() > 1 ? View.VISIBLE : View.GONE);
+ cancelButton.setOnClickListener(view -> dismiss());
+ okButton.setOnClickListener(
+ view -> {
+ onClickListener.onClick(getDialog(), DialogInterface.BUTTON_POSITIVE);
+ dismiss();
+ });
+ return dialogView;
+ }
+
+ /**
+ * Called when tracks are selected.
+ */
+ public interface TrackSelectionListener {
+
+ /**
+ * Called when tracks are selected.
+ *
+ * @param trackSelectionParameters A {@link TrackSelectionParameters} representing the selected
+ * tracks. Any manual selections are defined by {@link
+ * TrackSelectionParameters#disabledTrackTypes} and {@link
+ * TrackSelectionParameters#overrides}.
+ */
+ void onTracksSelected(TrackSelectionParameters trackSelectionParameters);
+ }
+
+ /**
+ * Fragment to show a track selection in tab of the track selection dialog.
+ */
+ public static final class TrackSelectionViewFragment extends Fragment
+ implements TrackSelectionView.TrackSelectionListener {
+
+ /* package */ boolean isDisabled;
+ /* package */ Map<TrackGroup, TrackSelectionOverride> overrides;
+ private List<Tracks.Group> trackGroups;
+ private boolean allowAdaptiveSelections;
+ private boolean allowMultipleOverrides;
+
+ public TrackSelectionViewFragment() {
+ // Retain instance across activity re-creation to prevent losing access to init data.
+ setRetainInstance(true);
+ }
+
+ public void init(
+ List<Tracks.Group> trackGroups,
+ boolean isDisabled,
+ Map<TrackGroup, TrackSelectionOverride> overrides,
+ boolean allowAdaptiveSelections,
+ boolean allowMultipleOverrides) {
+ this.trackGroups = trackGroups;
+ this.isDisabled = isDisabled;
+ this.allowAdaptiveSelections = allowAdaptiveSelections;
+ this.allowMultipleOverrides = allowMultipleOverrides;
+ // TrackSelectionView does this filtering internally, but we need to do it here as well to
+ // handle the case where the TrackSelectionView is never created.
+ this.overrides =
+ new HashMap<>(
+ TrackSelectionView.filterOverrides(overrides, trackGroups, allowMultipleOverrides));
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View rootView =
+ inflater.inflate(
+ R.layout.exo_track_selection_dialog, container, /* attachToRoot= */ false);
+ TrackSelectionView trackSelectionView = rootView.findViewById(R.id.exo_track_selection_view);
+ trackSelectionView.setShowDisableOption(true);
+ trackSelectionView.setAllowMultipleOverrides(allowMultipleOverrides);
+ trackSelectionView.setAllowAdaptiveSelections(allowAdaptiveSelections);
+ trackSelectionView.init(
+ trackGroups,
+ isDisabled,
+ overrides,
+ /* trackFormatComparator= */ null,
+ /* listener= */ this);
+ return rootView;
+ }
+
+ @Override
+ public void onTrackSelectionChanged(
+ boolean isDisabled, Map<TrackGroup, TrackSelectionOverride> overrides) {
+ this.isDisabled = isDisabled;
+ this.overrides = overrides;
+ }
+ }
+
+ private final class FragmentAdapter extends FragmentPagerAdapter {
+
+ public FragmentAdapter(FragmentManager fragmentManager) {
+ super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return tabFragments.get(tabTrackTypes.get(position));
+ }
+
+ @Override
+ public int getCount() {
+ return tabTrackTypes.size();
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return getTrackTypeString(getResources(), tabTrackTypes.get(position));
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/res/layouts/peertube/layout/track_selection_dialog.xml b/app/src/main/res/layouts/peertube/layout/track_selection_dialog.xml
new file mode 100644
index 000000000..ba8e5acf1
--- /dev/null
+++ b/app/src/main/res/layouts/peertube/layout/track_selection_dialog.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2018 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <androidx.viewpager.widget.ViewPager
+ android:id="@+id/track_selection_dialog_view_pager"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/track_selection_dialog_tab_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:tabGravity="fill"
+ app:tabMode="fixed" />
+
+ </androidx.viewpager.widget.ViewPager>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/track_selection_dialog_cancel_button"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@android:string/cancel" />
+
+ <Button
+ android:id="@+id/track_selection_dialog_ok_button"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@android:string/ok" />
+
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 02e0923b8..0f130646f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1962,4 +1962,8 @@
<string name="add_description">Add a description</string>
<string name="retrieve_remote_account">Retrieve remote account!</string>
<string name="exit">Exit</string>
+
+
+ <string name="track_selection_title">Select tracks</string>
+
</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 25c4b30ac..409d14f9d 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -266,4 +266,6 @@
<item name="android:insetTop">0dp</item>
<item name="android:insetBottom">0dp</item>
</style>
+
+
</resources>