From 2a1b506d98273785605527eedbb06cddae9f24eb Mon Sep 17 00:00:00 2001 From: TobiGr Date: Mon, 18 Sep 2023 03:11:28 +0200 Subject: [PATCH] Improved accessibility of player interfaces --- .../newpipe/player/PlayQueueActivity.java | 14 ++++--- .../newpipe/player/ui/VideoPlayerUi.java | 35 +++++++++++++++-- .../activity_player_queue_control.xml | 14 +++---- .../main/res/layout/fragment_video_detail.xml | 5 ++- app/src/main/res/layout/play_queue_item.xml | 1 + app/src/main/res/layout/player.xml | 39 ++++++++++++------- .../res/layout/player_popup_close_overlay.xml | 1 + app/src/main/res/values/strings.xml | 11 ++++++ 8 files changed, 86 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java index 4baadf69f52..defc8ba21f0 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java @@ -16,6 +16,7 @@ import android.view.SubMenu; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageButton; import android.widget.SeekBar; import androidx.annotation.Nullable; @@ -531,18 +532,19 @@ public void onServiceStopped() { //////////////////////////////////////////////////////////////////////////// private void onStateChanged(final int state) { + final ImageButton playPauseButton = queueControlBinding.controlPlayPause; switch (state) { case Player.STATE_PAUSED: - queueControlBinding.controlPlayPause - .setImageResource(R.drawable.ic_play_arrow); + playPauseButton.setImageResource(R.drawable.ic_play_arrow); + playPauseButton.setContentDescription(getString(R.string.play)); break; case Player.STATE_PLAYING: - queueControlBinding.controlPlayPause - .setImageResource(R.drawable.ic_pause); + playPauseButton.setImageResource(R.drawable.ic_pause); + playPauseButton.setContentDescription(getString(R.string.pause)); break; case Player.STATE_COMPLETED: - queueControlBinding.controlPlayPause - .setImageResource(R.drawable.ic_replay); + playPauseButton.setImageResource(R.drawable.ic_replay); + playPauseButton.setContentDescription(getString(R.string.replay)); break; default: break; diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java index 2638ff041a8..119c43b9522 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java @@ -41,6 +41,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.view.ContextThemeWrapper; +import androidx.appcompat.widget.AppCompatImageButton; import androidx.appcompat.widget.PopupMenu; import androidx.core.graphics.BitmapCompat; import androidx.core.graphics.Insets; @@ -103,6 +104,9 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa // other constants (TODO remove playback speeds and use normal menu for popup, too) private static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f}; + private enum PlayButtonAction { + PLAY, PAUSE, REPLAY + } /*////////////////////////////////////////////////////////////////////////// // Views @@ -755,6 +759,29 @@ public boolean isFullscreen() { // only MainPlayerUi can be in fullscreen, so overridden there return false; } + + /** + * Update the play/pause button ({@link R.id.playPauseButton}) to reflect the action + * that will be performed when the button is clicked.. + * @param action the action that is performed when the play/pause button is clicked + */ + private void updatePlayPauseButton(final PlayButtonAction action) { + final AppCompatImageButton button = binding.playPauseButton; + switch (action) { + case PLAY: + button.setContentDescription(context.getString(R.string.play)); + button.setImageResource(R.drawable.ic_play_arrow); + break; + case PAUSE: + button.setContentDescription(context.getString(R.string.pause)); + button.setImageResource(R.drawable.ic_pause); + break; + case REPLAY: + button.setContentDescription(context.getString(R.string.replay)); + button.setImageResource(R.drawable.ic_replay); + break; + } + } //endregion @@ -785,7 +812,7 @@ public void onBlocked() { animate(binding.loadingPanel, true, 0); animate(binding.surfaceForeground, true, 100); - binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow); + updatePlayPauseButton(PlayButtonAction.PLAY); animatePlayButtons(false, 100); binding.getRoot().setKeepScreenOn(false); } @@ -806,7 +833,7 @@ public void onPlaying() { animate(binding.playPauseButton, false, 80, AnimationType.SCALE_AND_ALPHA, 0, () -> { - binding.playPauseButton.setImageResource(R.drawable.ic_pause); + updatePlayPauseButton(PlayButtonAction.PAUSE); animatePlayButtons(true, 200); if (!isAnyListViewOpen()) { binding.playPauseButton.requestFocus(); @@ -836,7 +863,7 @@ public void onPaused() { animate(binding.playPauseButton, false, 80, AnimationType.SCALE_AND_ALPHA, 0, () -> { - binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow); + updatePlayPauseButton(PlayButtonAction.PLAY); animatePlayButtons(true, 200); if (!isAnyListViewOpen()) { binding.playPauseButton.requestFocus(); @@ -860,7 +887,7 @@ public void onCompleted() { animate(binding.playPauseButton, false, 0, AnimationType.SCALE_AND_ALPHA, 0, () -> { - binding.playPauseButton.setImageResource(R.drawable.ic_replay); + updatePlayPauseButton(PlayButtonAction.REPLAY); animatePlayButtons(true, DEFAULT_CONTROLS_DURATION); }); diff --git a/app/src/main/res/layout-land/activity_player_queue_control.xml b/app/src/main/res/layout-land/activity_player_queue_control.xml index 7d3b43ecc34..a5df5e56629 100644 --- a/app/src/main/res/layout-land/activity_player_queue_control.xml +++ b/app/src/main/res/layout-land/activity_player_queue_control.xml @@ -123,7 +123,7 @@ android:scaleType="fitCenter" android:src="@drawable/exo_controls_rewind" android:tint="?attr/colorAccent" - tools:ignore="ContentDescription" /> + android:contentDescription="@string/rewind" /> + android:contentDescription="@string/pause" /> + android:contentDescription="@string/forward" /> + android:contentDescription="@string/previous_stream" /> + android:contentDescription="@string/notification_action_repeat" /> + android:contentDescription="@string/notification_action_shuffle" /> + android:contentDescription="@string/next_stream" /> diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index 9aaf6d8d6c6..1a4711581e2 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -614,7 +614,8 @@ android:gravity="center_vertical" android:paddingLeft="@dimen/video_item_search_padding" android:paddingRight="@dimen/video_item_search_padding" - android:scaleType="fitCenter" /> + android:scaleType="fitCenter" + tools:ignore="ContentDescription" /> + tools:ignore="RtlHardcoded" /> diff --git a/app/src/main/res/layout/player.xml b/app/src/main/res/layout/player.xml index 89f1ed88e72..99b514bb090 100644 --- a/app/src/main/res/layout/player.xml +++ b/app/src/main/res/layout/player.xml @@ -115,7 +115,8 @@ android:src="@drawable/ic_close" android:visibility="gone" app:tint="@color/white" - tools:ignore="ContentDescription,RtlHardcoded" /> + android:contentDescription="@string/close" + tools:ignore="RtlHardcoded" /> + android:contentDescription="@string/open_play_queue" + tools:ignore="RtlHardcoded" /> + android:contentDescription="@string/chapters" + tools:ignore="RtlHardcoded" /> + android:contentDescription="@string/more_options" + tools:ignore="RtlHardcoded" /> @@ -368,9 +372,10 @@ android:padding="@dimen/player_main_buttons_padding" android:scaleType="fitCenter" android:src="@drawable/ic_fullscreen" + android:contentDescription="@string/toggle_fullscreen" android:visibility="gone" app:tint="@color/white" - tools:ignore="ContentDescription,RtlHardcoded" + tools:ignore="RtlHardcoded" tools:visibility="visible" /> @@ -493,8 +498,9 @@ android:scaleType="fitCenter" android:src="@drawable/ic_fullscreen" android:visibility="gone" + android:contentDescription="@string/toggle_screen_orientation" app:tint="@color/white" - tools:ignore="ContentDescription,RtlHardcoded" + tools:ignore="RtlHardcoded" tools:visibility="visible" /> @@ -517,8 +523,8 @@ android:focusable="true" android:scaleType="fitCenter" android:src="@drawable/ic_previous" - app:tint="@color/white" - tools:ignore="ContentDescription" /> + android:contentDescription="@string/previous_stream" + app:tint="@color/white" /> + android:contentDescription="@string/pause" + app:tint="@color/white" /> + android:contentDescription="@string/next_stream" + app:tint="@color/white" /> @@ -595,7 +601,8 @@ android:scaleType="fitXY" android:src="@drawable/exo_controls_repeat_off" android:tint="?attr/colorAccent" - tools:ignore="ContentDescription,RtlHardcoded" /> + android:contentDescription="@string/notification_action_repeat" + tools:ignore="RtlHardcoded" /> + android:contentDescription="@string/notification_action_shuffle" + tools:ignore="RtlHardcoded" /> + android:contentDescription="@string/add_to_playlist" + tools:ignore="RtlHardcoded" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e6fb35a1634..e5bbffaff09 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -811,4 +811,15 @@ About Channel tabs What tabs are shown on the channel pages + Open play queue + Toggle fullscreen + Toggle screen orientation + Previous stream + Next stream + Play + Replay + More options + Duration + Rewind + Forward \ No newline at end of file