mirror of
https://codeberg.org/tom79/Fedilab.git
synced 2024-12-22 16:50:04 +02:00
track selector
This commit is contained in:
parent
f082611b02
commit
0a9c5162ca
6 changed files with 426 additions and 7 deletions
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -266,4 +266,6 @@
|
|||
<item name="android:insetTop">0dp</item>
|
||||
<item name="android:insetBottom">0dp</item>
|
||||
</style>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue