diff --git a/app/src/main/java/com/brouken/player/PlayerActivity.java b/app/src/main/java/com/brouken/player/PlayerActivity.java index f66856e4..ac03c3fd 100644 --- a/app/src/main/java/com/brouken/player/PlayerActivity.java +++ b/app/src/main/java/com/brouken/player/PlayerActivity.java @@ -18,6 +18,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.UriPermission; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -97,6 +98,7 @@ import com.brouken.player.dtpv.DoubleTapPlayerView; import com.brouken.player.dtpv.youtube.YouTubeOverlay; +import com.brouken.player.osd.OsdSettingsController; import com.getkeepsafe.taptargetview.TapTarget; import com.getkeepsafe.taptargetview.TapTargetView; import com.google.android.material.snackbar.Snackbar; @@ -123,6 +125,7 @@ public class PlayerActivity extends Activity { public CustomPlayerView playerView; public static ExoPlayer player; private YouTubeOverlay youTubeOverlay; + private OsdSettingsController osdSettingsController; private Object mPictureInPictureParamsBuilder; @@ -145,7 +148,7 @@ public class PlayerActivity extends Activity { private static final int REQUEST_CHOOSER_VIDEO_MEDIASTORE = 20; private static final int REQUEST_CHOOSER_SUBTITLE_MEDIASTORE = 21; private static final int REQUEST_SETTINGS = 100; - private static final int REQUEST_SYSTEM_CAPTIONS = 200; + public static final int REQUEST_SYSTEM_CAPTIONS = 200; public static final int CONTROLLER_TIMEOUT = 3500; private static final String ACTION_MEDIA_CONTROL = "media_control"; private static final String EXTRA_CONTROL_TYPE = "control_type"; @@ -170,7 +173,7 @@ public class PlayerActivity extends Activity { private boolean restorePlayState; private boolean restorePlayStateAllowed; private boolean play; - private float subtitlesScale; + // private float subtitlesScale; private boolean isScrubbing; private boolean scrubbingNoticeable; private long scrubbingStart; @@ -247,6 +250,8 @@ protected void onCreate(Bundle savedInstanceState) { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); } + mPrefs.mSharedPreferences.registerOnSharedPreferenceChangeListener(preferenceListener); + final Intent launchIntent = getIntent(); final String action = launchIntent.getAction(); final String type = launchIntent.getType(); @@ -551,6 +556,9 @@ public void onScrubStop(TimeBar timeBar, long position, boolean canceled) { } return windowInsets; }); + + osdSettingsController = new OsdSettingsController(this); + timeBar.setAdMarkerColor(Color.argb(0x00, 0xFF, 0xFF, 0xFF)); timeBar.setPlayedAdMarkerColor(Color.argb(0x98, 0xFF, 0xFF, 0xFF)); @@ -606,8 +614,7 @@ public void onScrubStop(TimeBar timeBar, long position, boolean canceled) { }); exoSubtitle.setOnLongClickListener(v -> { - enableRotation(); - safelyStartActivityForResult(new Intent(Settings.ACTION_CAPTIONING_SETTINGS), REQUEST_SYSTEM_CAPTIONS); + osdSettingsController.showSubtitleSettings(); return true; }); @@ -758,6 +765,12 @@ public void onStop() { releasePlayer(false); } + @Override + protected void onDestroy() { + super.onDestroy(); + mPrefs.mSharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceListener); + } + @Override public void onBackPressed() { restorePlayStateAllowed = false; @@ -1596,7 +1609,7 @@ public void onPlayerError(PlaybackException error) { } } - private void enableRotation() { + public void enableRotation() { try { if (Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 0) { Settings.System.putInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 1); @@ -1697,7 +1710,7 @@ private Intent createBaseFileIntent(final String action, final Uri initialUri) { return intent; } - void safelyStartActivityForResult(final Intent intent, final int code) { + public void safelyStartActivityForResult(final Intent intent, final int code) { if (intent.resolveActivity(getPackageManager()) == null) showSnack(getText(R.string.error_files_missing).toString(), intent.toString()); else @@ -1790,10 +1803,16 @@ public String getSelectedTrack(final int trackType) { } void setSubtitleTextSize() { - setSubtitleTextSize(getResources().getConfiguration().orientation); + // setSubtitleTextSize(getResources().getConfiguration().orientation); + + final SubtitleView subtitleView = playerView.getSubtitleView(); + if (subtitleView != null) { + final CaptioningManager captioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE); + SubtitleUtils.updateFractionalTextSize(subtitleView, captioningManager, mPrefs); + } } - void setSubtitleTextSize(final int orientation) { + /*void setSubtitleTextSize(final int orientation) { // Tweak text size as fraction size doesn't work well in portrait final SubtitleView subtitleView = playerView.getSubtitleView(); if (subtitleView != null) { @@ -1810,7 +1829,7 @@ void setSubtitleTextSize(final int orientation) { subtitleView.setFractionalTextSize(size); } - } + }*/ void updateSubtitleViewMargin() { if (player == null) { @@ -1839,6 +1858,13 @@ void updateSubtitleViewMargin(Format format) { int videoWidth = metrics.heightPixels / aspectVideo.getDenominator() * aspectVideo.getNumerator(); marginHorizontal = (metrics.widthPixels - videoWidth) / 2; } + } else { + // SubtitleView’s height must be the same in both landscape + // and portrait modes to maintain the same subtitle size. + DisplayMetrics realMetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getRealMetrics(realMetrics); + int minMarginVertical = (realMetrics.heightPixels - realMetrics.widthPixels) / 2; + if (marginVertical < minMarginVertical) marginVertical = minMarginVertical; } Utils.setViewParams(playerView.getSubtitleView(), 0, 0, 0, 0, @@ -1884,7 +1910,7 @@ public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); if (!isInPip()) { - setSubtitleTextSize(newConfig.orientation); + setSubtitleTextSize(/*newConfig.orientation*/); } updateSubtitleViewMargin(); @@ -1949,8 +1975,8 @@ void reportScrubbing(long position) { void updateSubtitleStyle(final Context context) { final CaptioningManager captioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE); final SubtitleView subtitleView = playerView.getSubtitleView(); - final boolean isTablet = Utils.isTablet(context); - subtitlesScale = SubtitleUtils.normalizeFontScale(captioningManager.getFontScale(), isTvBox || isTablet); + // final boolean isTablet = Utils.isTablet(context); + // subtitlesScale = SubtitleUtils.normalizeFontScale(captioningManager.getFontScale(), isTvBox || isTablet); if (subtitleView != null) { final CaptioningManager.CaptionStyle userStyle = captioningManager.getUserStyle(); final CaptionStyleCompat userStyleCompat = CaptionStyleCompat.createFromCaptionStyle(userStyle); @@ -1958,15 +1984,21 @@ void updateSubtitleStyle(final Context context) { userStyle.hasForegroundColor() ? userStyleCompat.foregroundColor : Color.WHITE, userStyle.hasBackgroundColor() ? userStyleCompat.backgroundColor : Color.TRANSPARENT, userStyle.hasWindowColor() ? userStyleCompat.windowColor : Color.TRANSPARENT, - userStyle.hasEdgeType() ? userStyleCompat.edgeType : CaptionStyleCompat.EDGE_TYPE_OUTLINE, + SubtitleUtils.getSubtitleEdgeType(mPrefs.subtitleEdgeType, userStyle), userStyle.hasEdgeColor() ? userStyleCompat.edgeColor : Color.BLACK, Typeface.create(userStyleCompat.typeface != null ? userStyleCompat.typeface : Typeface.DEFAULT, mPrefs.subtitleStyleBold ? Typeface.BOLD : Typeface.NORMAL)); subtitleView.setStyle(captionStyle); subtitleView.setApplyEmbeddedStyles(mPrefs.subtitleStyleEmbedded); - subtitleView.setBottomPaddingFraction(SubtitleView.DEFAULT_BOTTOM_PADDING_FRACTION * 2f / 3f); + updateSubtitleBottomPaddingFraction(mPrefs.subtitleVerticalPosition); + SubtitleUtils.updateFractionalTextSize(subtitleView, captioningManager, mPrefs); } - setSubtitleTextSize(); + // setSubtitleTextSize(); + } + + private void updateSubtitleBottomPaddingFraction(int subtitleVerticalPosition) { + float bottomPaddingFraction = SubtitleView.DEFAULT_BOTTOM_PADDING_FRACTION + (subtitleVerticalPosition * 0.01f); + playerView.getSubtitleView().setBottomPaddingFraction(bottomPaddingFraction); } void searchSubtitles() { @@ -2317,4 +2349,15 @@ private void updateButtonRotation() { } } } + + private final SharedPreferences.OnSharedPreferenceChangeListener preferenceListener = (sharedPreferences, key) -> { + switch (key) { + case Prefs.PREF_KEY_SUBTITLE_VERTICAL_POSITION: + case Prefs.PREF_KEY_SUBTITLE_SIZE: + case Prefs.PREF_KEY_SUBTITLE_EDGE_TYPE: + case Prefs.PREF_KEY_SUBTITLE_STYLE_BOLD: + case Prefs.PREF_KEY_SUBTITLE_STYLE_EMBEDDED: + updateSubtitleStyle(PlayerActivity.this); + } + }; } \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/Prefs.java b/app/src/main/java/com/brouken/player/Prefs.java index 54a3f344..4b29801c 100644 --- a/app/src/main/java/com/brouken/player/Prefs.java +++ b/app/src/main/java/com/brouken/player/Prefs.java @@ -6,9 +6,13 @@ import android.net.Uri; import android.preference.PreferenceManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.media3.exoplayer.DefaultRenderersFactory; import androidx.media3.ui.AspectRatioFrameLayout; +import com.brouken.player.osd.subtitle.SubtitleEdgeType; + import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; @@ -16,7 +20,7 @@ import java.util.LinkedHashMap; import java.util.Set; -class Prefs { +public class Prefs { // Previously used // private static final String PREF_KEY_AUDIO_TRACK = "audioTrack"; // private static final String PREF_KEY_AUDIO_TRACK_FFMPEG = "audioTrackFfmpeg"; @@ -45,8 +49,11 @@ class Prefs { private static final String PREF_KEY_DECODER_PRIORITY = "decoderPriority"; private static final String PREF_KEY_MAP_DV7 = "mapDV7ToHevc"; private static final String PREF_KEY_LANGUAGE_AUDIO = "languageAudio"; - private static final String PREF_KEY_SUBTITLE_STYLE_EMBEDDED = "subtitleStyleEmbedded"; - private static final String PREF_KEY_SUBTITLE_STYLE_BOLD = "subtitleStyleBold"; + static final String PREF_KEY_SUBTITLE_STYLE_EMBEDDED = "subtitleStyleEmbedded"; + static final String PREF_KEY_SUBTITLE_STYLE_BOLD = "subtitleStyleBold"; + static final String PREF_KEY_SUBTITLE_VERTICAL_POSITION = "subtitleVerticalPosition"; + static final String PREF_KEY_SUBTITLE_SIZE = "subtitleSize"; + static final String PREF_KEY_SUBTITLE_EDGE_TYPE = "subtitleEdgeType"; public static final String TRACK_DEFAULT = "default"; public static final String TRACK_DEVICE = "device"; @@ -81,6 +88,9 @@ class Prefs { public String languageAudio = TRACK_DEVICE; public boolean subtitleStyleEmbedded = true; public boolean subtitleStyleBold = false; + public int subtitleVerticalPosition = 0; + public int subtitleSize = 0; + public SubtitleEdgeType subtitleEdgeType = SubtitleEdgeType.Default; private LinkedHashMap positions; @@ -94,6 +104,15 @@ public Prefs(Context context) { loadPositions(); } + private static > T valueOfEnum(@NonNull Class clazz, @Nullable String name, @NonNull T defaultValue) { + if (name == null) return defaultValue; + try { + return Enum.valueOf(clazz, name); + } catch (IllegalArgumentException e) { + return defaultValue; + } + } + private void loadSavedPreferences() { if (mSharedPreferences.contains(PREF_KEY_MEDIA_URI)) mediaUri = Uri.parse(mSharedPreferences.getString(PREF_KEY_MEDIA_URI, null)); @@ -130,6 +149,9 @@ public void loadUserPreferences() { languageAudio = mSharedPreferences.getString(PREF_KEY_LANGUAGE_AUDIO, languageAudio); subtitleStyleEmbedded = mSharedPreferences.getBoolean(PREF_KEY_SUBTITLE_STYLE_EMBEDDED, subtitleStyleEmbedded); subtitleStyleBold = mSharedPreferences.getBoolean(PREF_KEY_SUBTITLE_STYLE_BOLD, subtitleStyleBold); + subtitleVerticalPosition = mSharedPreferences.getInt(PREF_KEY_SUBTITLE_VERTICAL_POSITION, subtitleVerticalPosition); + subtitleSize = mSharedPreferences.getInt(PREF_KEY_SUBTITLE_SIZE, subtitleSize); + subtitleEdgeType = valueOfEnum(SubtitleEdgeType.class, mSharedPreferences.getString(PREF_KEY_SUBTITLE_EDGE_TYPE, null), subtitleEdgeType); } public void updateMedia(final Context context, final Uri uri, final String type) { @@ -309,6 +331,41 @@ public void updateScope(final Uri uri) { sharedPreferencesEditor.apply(); } + public void updateSubtitleVerticalPosition(final int subtitleVerticalPosition) { + this.subtitleVerticalPosition = subtitleVerticalPosition; + final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); + sharedPreferencesEditor.putInt(PREF_KEY_SUBTITLE_VERTICAL_POSITION, subtitleVerticalPosition); + sharedPreferencesEditor.apply(); + } + + public void updateSubtitleSize(final int subtitleSize) { + this.subtitleSize = subtitleSize; + final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); + sharedPreferencesEditor.putInt(PREF_KEY_SUBTITLE_SIZE, subtitleSize); + sharedPreferencesEditor.apply(); + } + + public void updateSubtitleEdgeType(final SubtitleEdgeType subtitleEdgeType) { + this.subtitleEdgeType = subtitleEdgeType; + final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); + sharedPreferencesEditor.putString(PREF_KEY_SUBTITLE_EDGE_TYPE, subtitleEdgeType.name()); + sharedPreferencesEditor.apply(); + } + + public void updateSubtitleStyleBold(final boolean subtitleStyleBold) { + this.subtitleStyleBold = subtitleStyleBold; + final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); + sharedPreferencesEditor.putBoolean(PREF_KEY_SUBTITLE_STYLE_BOLD, subtitleStyleBold); + sharedPreferencesEditor.apply(); + } + + public void updateSubtitleStyleEmbedded(final boolean subtitleStyleEmbedded) { + this.subtitleStyleEmbedded = subtitleStyleEmbedded; + final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); + sharedPreferencesEditor.putBoolean(PREF_KEY_SUBTITLE_STYLE_EMBEDDED, subtitleStyleEmbedded); + sharedPreferencesEditor.apply(); + } + public void setPersistent(boolean persistentMode) { this.persistentMode = persistentMode; } diff --git a/app/src/main/java/com/brouken/player/SubtitleUtils.java b/app/src/main/java/com/brouken/player/SubtitleUtils.java index c28af301..c1d5be73 100644 --- a/app/src/main/java/com/brouken/player/SubtitleUtils.java +++ b/app/src/main/java/com/brouken/player/SubtitleUtils.java @@ -3,11 +3,16 @@ import android.content.ContentResolver; import android.content.Context; import android.net.Uri; +import android.view.accessibility.CaptioningManager; import androidx.documentfile.provider.DocumentFile; import androidx.media3.common.C; import androidx.media3.common.MediaItem; import androidx.media3.common.MimeTypes; +import androidx.media3.ui.CaptionStyleCompat; +import androidx.media3.ui.SubtitleView; + +import com.brouken.player.osd.subtitle.SubtitleEdgeType; import java.io.File; import java.util.ArrayList; @@ -282,7 +287,7 @@ public static MediaItem.SubtitleConfiguration buildSubtitle(Context context, Uri return subtitleConfigurationBuilder.build(); } - public static float normalizeFontScale(float fontScale, boolean small) { + /*public static float normalizeFontScale(float fontScale, boolean small) { // https://bbc.github.io/subtitle-guidelines/#Presentation-font-size float newScale; // ¯\_(ツ)_/¯ @@ -306,5 +311,31 @@ public static float normalizeFontScale(float fontScale, boolean small) { newScale = (small ? 0.85f : 1.0f); } return newScale; + }*/ + + public static void updateFractionalTextSize(SubtitleView subtitleView, CaptioningManager captioningManager, Prefs prefs) { + float fontScale = captioningManager.getFontScale(); + int subtitleSize = prefs.subtitleSize; + float fractionalTextSize = (SubtitleView.DEFAULT_TEXT_SIZE_FRACTION * fontScale) + (subtitleSize * 0.001f); + subtitleView.setFractionalTextSize(fractionalTextSize); + } + + public static @CaptionStyleCompat.EdgeType int getSubtitleEdgeType(SubtitleEdgeType subtitleEdgeType, CaptioningManager.CaptionStyle captionStyle) { + switch (subtitleEdgeType) { + case Default: + return captionStyle.hasEdgeType() ? captionStyle.edgeType : CaptionStyleCompat.EDGE_TYPE_OUTLINE; + case None: + return CaptionStyleCompat.EDGE_TYPE_NONE; + case Outline: + return CaptionStyleCompat.EDGE_TYPE_OUTLINE; + case DropShadow: + return CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW; + case Raised: + return CaptionStyleCompat.EDGE_TYPE_RAISED; + case Depressed: + return CaptionStyleCompat.EDGE_TYPE_DEPRESSED; + default: + throw new IllegalArgumentException("Unknown subtitleEdgeType: " + subtitleEdgeType); + } } } diff --git a/app/src/main/java/com/brouken/player/osd/OsdSettingsAdapter.java b/app/src/main/java/com/brouken/player/osd/OsdSettingsAdapter.java new file mode 100644 index 00000000..8a1326f2 --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/OsdSettingsAdapter.java @@ -0,0 +1,192 @@ +package com.brouken.player.osd; + +import android.content.Context; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.media3.common.util.Util; +import androidx.recyclerview.widget.RecyclerView; + +import com.brouken.player.R; +import com.brouken.player.osd.item.LeftOrRightOsdSettingsItem; +import com.brouken.player.osd.item.OsdSettingsItem; +import com.brouken.player.osd.item.SimpleOsdSettingsItem; + +public class OsdSettingsAdapter extends RecyclerView.Adapter { + + protected final Context context; + private final LayoutInflater layoutInflater; + protected OsdSettingsItem[] items; + + public OsdSettingsAdapter(@NonNull Context context) { + this.context = context; + this.layoutInflater = LayoutInflater.from(context); + } + + @NonNull + @Override + public OsdSettingsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case LeftOrRightOsdSettingsItem.VIEW_TYPE: + view = layoutInflater.inflate(R.layout.osd_settings_item_left_or_right, parent, false); + return new ValueOsdSettingsViewHolder(view); + case SimpleOsdSettingsItem.VIEW_TYPE: + view = layoutInflater.inflate(R.layout.osd_settings_item_simple, parent, false); + return new SimpleOsdSettingsViewHolder(view); + default: + throw new IllegalArgumentException("Unknown viewType: " + viewType); + } + } + + @Override + public void onBindViewHolder(@NonNull OsdSettingsViewHolder holder, int position) { + OsdSettingsItem item = items[position]; + holder.bind(item); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemCount() { + return items.length; + } + + @Override + public int getItemViewType(int position) { + return items[position].getViewType(); + } + + public static abstract class OsdSettingsViewHolder extends RecyclerView.ViewHolder { + + public OsdSettingsViewHolder(@NonNull View itemView) { + super(itemView); + } + + abstract void bind(OsdSettingsItem item); + + } + + private class ValueOsdSettingsViewHolder extends OsdSettingsViewHolder { + + private final TextView titleTextView; + private final TextView summaryTextView; + + private ValueOsdSettingsViewHolder(View itemView) { + super(itemView); + + if (Util.SDK_INT < 26) { + // Workaround for https://github.com/google/ExoPlayer/issues/9061. + itemView.setFocusable(true); + } + + titleTextView = itemView.findViewById(android.R.id.title); + summaryTextView = itemView.findViewById(android.R.id.summary); + + View button1 = itemView.findViewById(android.R.id.button1); + View button2 = itemView.findViewById(android.R.id.button2); + + button1.setOnClickListener(v -> notifySettingLeftPressed()); + button2.setOnClickListener(v -> notifySettingRightPressed()); + + itemView.setOnKeyListener((v, keyCode, event) -> { + if (event.getAction() == KeyEvent.ACTION_DOWN) { + boolean isLtr = v.getLayoutDirection() != View.LAYOUT_DIRECTION_RTL; + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (isLtr) { + button1.setPressed(true); + button1.setPressed(false); + notifySettingLeftPressed(); + } else { + button2.setPressed(true); + button2.setPressed(false); + notifySettingRightPressed(); + } + return true; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (isLtr) { + button2.setPressed(true); + button2.setPressed(false); + notifySettingRightPressed(); + } else { + button1.setPressed(true); + button1.setPressed(false); + notifySettingLeftPressed(); + } + return true; + } + } + return false; + }); + } + + @Override + void bind(OsdSettingsItem item) { + LeftOrRightOsdSettingsItem valueItem = (LeftOrRightOsdSettingsItem) item; + titleTextView.setText(valueItem.title); + if (valueItem.summary == null) { + summaryTextView.setVisibility(View.GONE); + } else { + summaryTextView.setText(valueItem.summary); + } + } + + private void notifySettingLeftPressed() { + int position = getBindingAdapterPosition(); + LeftOrRightOsdSettingsItem item = (LeftOrRightOsdSettingsItem) items[position]; + item.listener.onSettingLeftClick(position); + } + + private void notifySettingRightPressed() { + int position = getBindingAdapterPosition(); + LeftOrRightOsdSettingsItem item = (LeftOrRightOsdSettingsItem) items[position]; + item.listener.onSettingRightClick(position); + } + + } + + private class SimpleOsdSettingsViewHolder extends OsdSettingsViewHolder { + + private final TextView titleTextView; + private final ImageView iconView; + + private SimpleOsdSettingsViewHolder(View itemView) { + super(itemView); + + if (Util.SDK_INT < 26) { + // Workaround for https://github.com/google/ExoPlayer/issues/9061. + itemView.setFocusable(true); + } + + titleTextView = itemView.findViewById(android.R.id.title); + iconView = itemView.findViewById(android.R.id.icon); + + itemView.setOnClickListener(v -> { + int position = getBindingAdapterPosition(); + SimpleOsdSettingsItem item = (SimpleOsdSettingsItem) items[position]; + item.listener.onSettingClicked(position); + }); + } + + @Override + void bind(OsdSettingsItem item) { + SimpleOsdSettingsItem simpleItem = (SimpleOsdSettingsItem) item; + titleTextView.setText(simpleItem.title); + if (simpleItem.icon == null) { + iconView.setVisibility(View.GONE); + } else { + iconView.setImageDrawable(simpleItem.icon); + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/OsdSettingsController.java b/app/src/main/java/com/brouken/player/osd/OsdSettingsController.java new file mode 100644 index 00000000..3330cdd3 --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/OsdSettingsController.java @@ -0,0 +1,113 @@ +package com.brouken.player.osd; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.provider.Settings; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.PopupWindow; +import android.widget.TextView; + +import androidx.media3.common.util.Util; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.brouken.player.PlayerActivity; +import com.brouken.player.Prefs; +import com.brouken.player.R; +import com.brouken.player.osd.subtitle.SubtitleEdgeType; +import com.brouken.player.osd.subtitle.SubtitleOsdSettingsAdapter; +import com.brouken.player.osd.subtitle.SubtitleTypeface; + +public class OsdSettingsController { + + private final PlayerActivity playerActivity; + private final Prefs prefs; + + private final PopupWindow osdSettingsWindow; + + @SuppressLint("InflateParams") + public OsdSettingsController(PlayerActivity playerActivity) { + this.playerActivity = playerActivity; + this.prefs = playerActivity.mPrefs; + + Context context = playerActivity.playerView.getContext(); + + SubtitleOsdSettingsAdapter subtitleAdapter = + new SubtitleOsdSettingsAdapter(context, createSubtitleSettingsListener()); + + subtitleAdapter.setInitialValues( + prefs.subtitleVerticalPosition, + prefs.subtitleSize, + prefs.subtitleEdgeType, + prefs.subtitleStyleBold ? SubtitleTypeface.Bold : SubtitleTypeface.Regular, + prefs.subtitleStyleEmbedded + ); + + View settingsView = LayoutInflater.from(context).inflate(R.layout.osd_settings, null); + RecyclerView recyclerView = settingsView.findViewById(android.R.id.list); + recyclerView.setAdapter(subtitleAdapter); + recyclerView.setLayoutManager(new LinearLayoutManager(context)); + osdSettingsWindow = + new PopupWindow(settingsView, FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, true); + if (Util.SDK_INT < 23) { + // Work around issue where tapping outside of the menu area or pressing the back button + // doesn't dismiss the menu as expected. See: https://github.com/google/ExoPlayer/issues/8272. + osdSettingsWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + } + } + + public void showSubtitleSettings() { + int margin = playerActivity.getResources().getDimensionPixelSize(R.dimen.osd_settings_margin); + TextView titleTextView = osdSettingsWindow.getContentView().findViewById(android.R.id.text1); + titleTextView.setText(R.string.osd_subtitle_title); + osdSettingsWindow.showAtLocation(playerActivity.playerView, Gravity.END | Gravity.TOP, margin, margin); + + // Without delaying hide, controller's UI reappears when + // using physical button on a remote to open settings + playerActivity.playerView.postDelayed(playerActivity.playerView::hideController, 100); + } + + private SubtitleOsdSettingsAdapter.Listener createSubtitleSettingsListener() { + return new SubtitleOsdSettingsAdapter.Listener() { + @Override + public void onSubtitlePositionChange(int position) { + prefs.updateSubtitleVerticalPosition(position); + } + + @Override + public void onSubtitleSizeChange(int size) { + prefs.updateSubtitleSize(size); + } + + @Override + public void onSubtitleEdgeTypeChange(SubtitleEdgeType edgeType) { + prefs.updateSubtitleEdgeType(edgeType); + } + + @Override + public void onSubtitleTypefaceChange(SubtitleTypeface typeface) { + prefs.updateSubtitleStyleBold(typeface == SubtitleTypeface.Bold); + } + + @Override + public void onSubtitleEmbeddedStylesChange(boolean embeddedStyles) { + prefs.updateSubtitleStyleEmbedded(embeddedStyles); + } + + @Override + public void onOpenCaptionPreferences() { + osdSettingsWindow.dismiss(); + playerActivity.enableRotation(); + Intent intent = new Intent(Settings.ACTION_CAPTIONING_SETTINGS); + playerActivity.safelyStartActivityForResult(intent, PlayerActivity.REQUEST_SYSTEM_CAPTIONS); + } + }; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/item/BooleanOsdSettingsItem.java b/app/src/main/java/com/brouken/player/osd/item/BooleanOsdSettingsItem.java new file mode 100644 index 00000000..2f9496cf --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/item/BooleanOsdSettingsItem.java @@ -0,0 +1,31 @@ +package com.brouken.player.osd.item; + +import com.brouken.player.osd.OsdSettingsAdapter; + +public class BooleanOsdSettingsItem extends ChoiceOsdSettingsItem { + + private final Listener listener; + + public BooleanOsdSettingsItem(String title, String labelTrue, String labelFalse, boolean value, Listener listener, OsdSettingsAdapter adapter) { + super(title, createElements(labelTrue, labelFalse), value ? 1 : 0, null, adapter); + + super.listener = createChoiceListener(); + this.listener = listener; + } + + private ChoiceOsdSettingsItem.Listener createChoiceListener() { + return (position, newElementIndex) -> listener.onSettingChanged(position, newElementIndex == 1); + } + + private static Element[] createElements(String labelTrue, String labelFalse) { + return new Element[]{ + new Element(labelFalse), + new Element(labelTrue) + }; + } + + public interface Listener { + void onSettingChanged(int position, boolean newValue); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/item/ChoiceOsdSettingsItem.java b/app/src/main/java/com/brouken/player/osd/item/ChoiceOsdSettingsItem.java new file mode 100644 index 00000000..0e975ea9 --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/item/ChoiceOsdSettingsItem.java @@ -0,0 +1,62 @@ +package com.brouken.player.osd.item; + +import com.brouken.player.osd.OsdSettingsAdapter; + +public class ChoiceOsdSettingsItem extends LeftOrRightOsdSettingsItem { + + private final Element[] elements; + Listener listener; + private final OsdSettingsAdapter adapter; + + private int currentElementIndex; + + public ChoiceOsdSettingsItem(String title, Element[] elements, int elementIndex, Listener listener, OsdSettingsAdapter adapter) { + super(title, null); + + super.listener = createLeftOrRightListener(); + this.elements = elements; + this.listener = listener; + this.adapter = adapter; + + this.currentElementIndex = elementIndex; + summary = elements[elementIndex].name; + } + + private void updateCurrentElementIndex(int position, int newElementIndex) { + currentElementIndex = newElementIndex; + summary = elements[newElementIndex].name; + adapter.notifyItemChanged(position); + listener.onSettingChanged(position, newElementIndex); + } + + private LeftOrRightOsdSettingsItem.Listener createLeftOrRightListener() { + return new LeftOrRightOsdSettingsItem.Listener() { + @Override + public void onSettingLeftClick(int position) { + int newElementIndex = currentElementIndex == 0 ? elements.length - 1 : currentElementIndex - 1; + updateCurrentElementIndex(position, newElementIndex); + } + + @Override + public void onSettingRightClick(int position) { + int newElementIndex = currentElementIndex == elements.length - 1 ? 0 : currentElementIndex + 1; + updateCurrentElementIndex(position, newElementIndex); + } + }; + } + + public interface Listener { + void onSettingChanged(int position, int newElementIndex); + } + + public static class Element { + + private final String name; + + public Element(String name) { + this.name = name; + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/item/IntegerOsdSettingsItem.java b/app/src/main/java/com/brouken/player/osd/item/IntegerOsdSettingsItem.java new file mode 100644 index 00000000..2a84a489 --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/item/IntegerOsdSettingsItem.java @@ -0,0 +1,62 @@ +package com.brouken.player.osd.item; + +import com.brouken.player.osd.OsdSettingsAdapter; + +public class IntegerOsdSettingsItem extends LeftOrRightOsdSettingsItem { + + private final Listener listener; + private final OsdSettingsAdapter adapter; + private final String labelDefault; + private final boolean addPlusToValue; + + private int currentValue; + + public IntegerOsdSettingsItem(String title, String labelDefault, boolean addPlusToValue, int value, Listener listener, OsdSettingsAdapter adapter) { + super(title, null); + + super.listener = createLeftOrRightListener(); + this.listener = listener; + this.adapter = adapter; + this.labelDefault = labelDefault; + this.addPlusToValue = addPlusToValue; + + this.currentValue = value; + summary = withPlusOrDefault(value); + } + + private String withPlusOrDefault(int value) { + if (value == 0 && labelDefault != null) { + return labelDefault; + } else if (value > 0 && addPlusToValue) { + return "+" + value; + } else { + return String.valueOf(value); + } + } + + private void updateCurrentValue(int position, int newValue) { + currentValue = newValue; + summary = withPlusOrDefault(newValue); + adapter.notifyItemChanged(position); + listener.onSettingChanged(position, newValue); + } + + private LeftOrRightOsdSettingsItem.Listener createLeftOrRightListener() { + return new LeftOrRightOsdSettingsItem.Listener() { + @Override + public void onSettingLeftClick(int position) { + updateCurrentValue(position, currentValue - 1); + } + + @Override + public void onSettingRightClick(int position) { + updateCurrentValue(position, currentValue + 1); + } + }; + } + + public interface Listener { + void onSettingChanged(int position, int newValue); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/item/LeftOrRightOsdSettingsItem.java b/app/src/main/java/com/brouken/player/osd/item/LeftOrRightOsdSettingsItem.java new file mode 100644 index 00000000..9edeeba7 --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/item/LeftOrRightOsdSettingsItem.java @@ -0,0 +1,29 @@ +package com.brouken.player.osd.item; + +public class LeftOrRightOsdSettingsItem implements OsdSettingsItem { + + public static final int VIEW_TYPE = 0; + + public final String title; + public LeftOrRightOsdSettingsItem.Listener listener; + public String summary; + + public LeftOrRightOsdSettingsItem(String title, Listener listener) { + this.title = title; + this.listener = listener; + } + + @Override + public int getViewType() { + return VIEW_TYPE; + } + + public interface Listener { + + void onSettingLeftClick(int position); + + void onSettingRightClick(int position); + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/item/OsdSettingsItem.java b/app/src/main/java/com/brouken/player/osd/item/OsdSettingsItem.java new file mode 100644 index 00000000..e186b49c --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/item/OsdSettingsItem.java @@ -0,0 +1,5 @@ +package com.brouken.player.osd.item; + +public interface OsdSettingsItem { + int getViewType(); +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/item/SimpleOsdSettingsItem.java b/app/src/main/java/com/brouken/player/osd/item/SimpleOsdSettingsItem.java new file mode 100644 index 00000000..453c546d --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/item/SimpleOsdSettingsItem.java @@ -0,0 +1,28 @@ +package com.brouken.player.osd.item; + +import android.graphics.drawable.Drawable; + +public class SimpleOsdSettingsItem implements OsdSettingsItem { + + public static final int VIEW_TYPE = 1; + + public final String title; + public final Drawable icon; + public final Listener listener; + + public SimpleOsdSettingsItem(String title, Drawable icon, Listener listener) { + this.title = title; + this.icon = icon; + this.listener = listener; + } + + @Override + public int getViewType() { + return VIEW_TYPE; + } + + public interface Listener { + void onSettingClicked(int position); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleEdgeType.java b/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleEdgeType.java new file mode 100644 index 00000000..4e4a93d2 --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleEdgeType.java @@ -0,0 +1,3 @@ +package com.brouken.player.osd.subtitle; + +public enum SubtitleEdgeType {Default, None, Outline, DropShadow, Raised, Depressed} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleOsdSettingsAdapter.java b/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleOsdSettingsAdapter.java new file mode 100644 index 00000000..0e890736 --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleOsdSettingsAdapter.java @@ -0,0 +1,150 @@ +package com.brouken.player.osd.subtitle; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.drawable.Drawable; + +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.core.content.res.ResourcesCompat; + +import com.brouken.player.R; +import com.brouken.player.osd.OsdSettingsAdapter; +import com.brouken.player.osd.item.BooleanOsdSettingsItem; +import com.brouken.player.osd.item.ChoiceOsdSettingsItem; +import com.brouken.player.osd.item.IntegerOsdSettingsItem; +import com.brouken.player.osd.item.OsdSettingsItem; +import com.brouken.player.osd.item.SimpleOsdSettingsItem; + +public class SubtitleOsdSettingsAdapter extends OsdSettingsAdapter { + + private final Listener listener; + + public SubtitleOsdSettingsAdapter(@NonNull Context context, @NonNull Listener listener) { + super(context); + this.listener = listener; + } + + public void setInitialValues(int subtitlePosition, int size, SubtitleEdgeType edgeType, SubtitleTypeface typeface, boolean embeddedStyles) { + this.items = createSubtitleSettingsArray(subtitlePosition, size, edgeType, typeface, embeddedStyles); + } + + private OsdSettingsItem[] createSubtitleSettingsArray(int subtitlePosition, int size, SubtitleEdgeType edgeType, SubtitleTypeface typeface, boolean embeddedStyles) { + return new OsdSettingsItem[]{ + createPositionItem(subtitlePosition), + createSizeItem(size), + createEdgeTypeItem(edgeType), + createTypefaceItem(typeface), + createEmbeddedStylesItem(embeddedStyles), + createCaptioningPreferenceItem() + }; + } + + private static Drawable getDrawable(Context context, @DrawableRes int id) { + return ResourcesCompat.getDrawable(context.getResources(), id, context.getTheme()); + } + + private OsdSettingsItem createPositionItem(int subtitlePosition) { + String title = context.getString(R.string.osd_subtitle_position_title); + String labelDefault = context.getString(R.string.osd_item_integer_default); + + IntegerOsdSettingsItem.Listener itemListener = (position, newValue) -> listener.onSubtitlePositionChange(newValue); + return new IntegerOsdSettingsItem(title, labelDefault, true, subtitlePosition, itemListener, this); + } + + private OsdSettingsItem createSizeItem(int size) { + String title = context.getString(R.string.osd_subtitle_size_title); + String labelDefault = context.getString(R.string.osd_item_integer_default); + + IntegerOsdSettingsItem.Listener itemListener = (position, newValue) -> listener.onSubtitleSizeChange(newValue); + return new IntegerOsdSettingsItem(title, labelDefault, true, size, itemListener, this); + } + + private OsdSettingsItem createEdgeTypeItem(SubtitleEdgeType edgeType) { + String title = context.getString(R.string.osd_subtitle_edge_type_title); + + ChoiceOsdSettingsItem.Element[] elements = new ChoiceOsdSettingsItem.Element[SubtitleEdgeType.values().length]; + for (int i = 0; i < elements.length; i++) { + switch (SubtitleEdgeType.values()[i]) { + case Default: + elements[i] = new ChoiceOsdSettingsItem.Element(context.getString(R.string.osd_subtitle_edge_type_default)); + break; + case None: + elements[i] = new ChoiceOsdSettingsItem.Element(context.getString(R.string.osd_subtitle_edge_type_none)); + break; + case Outline: + elements[i] = new ChoiceOsdSettingsItem.Element(context.getString(R.string.osd_subtitle_edge_type_outline)); + break; + case DropShadow: + elements[i] = new ChoiceOsdSettingsItem.Element(context.getString(R.string.osd_subtitle_edge_type_drop_shadow)); + break; + case Raised: + elements[i] = new ChoiceOsdSettingsItem.Element(context.getString(R.string.osd_subtitle_edge_type_raised)); + break; + case Depressed: + elements[i] = new ChoiceOsdSettingsItem.Element(context.getString(R.string.osd_subtitle_edge_type_depressed)); + break; + default: + throw new IllegalArgumentException("Unknown SubtitleEdgeType: " + SubtitleEdgeType.values()[i]); + } + } + + ChoiceOsdSettingsItem.Listener itemListener = (position, newValueIndex) -> listener.onSubtitleEdgeTypeChange(SubtitleEdgeType.values()[newValueIndex]); + return new ChoiceOsdSettingsItem(title, elements, edgeType.ordinal(), itemListener, this); + } + + private OsdSettingsItem createTypefaceItem(SubtitleTypeface typeface) { + String title = context.getString(R.string.osd_subtitle_typeface_title); + + ChoiceOsdSettingsItem.Element[] elements = new ChoiceOsdSettingsItem.Element[SubtitleTypeface.values().length]; + for (int i = 0; i < elements.length; i++) { + switch (SubtitleTypeface.values()[i]) { + case Regular: + elements[i] = new ChoiceOsdSettingsItem.Element(context.getString(R.string.osd_subtitle_typeface_regular)); + break; + case Bold: + elements[i] = new ChoiceOsdSettingsItem.Element(context.getString(R.string.osd_subtitle_typeface_bold)); + break; + default: + throw new IllegalArgumentException("Unknown SubtitleTypeface: " + SubtitleEdgeType.values()[i]); + } + } + + ChoiceOsdSettingsItem.Listener itemListener = (position, newValueIndex) -> listener.onSubtitleTypefaceChange(SubtitleTypeface.values()[newValueIndex]); + return new ChoiceOsdSettingsItem(title, elements, typeface.ordinal(), itemListener, this); + } + + private OsdSettingsItem createEmbeddedStylesItem(boolean embeddedStyles) { + String title = context.getString(R.string.osd_subtitle_embedded_styles_title); + String labelTrue = context.getString(R.string.osd_item_boolean_true); + String labelFalse = context.getString(R.string.osd_item_boolean_false); + + BooleanOsdSettingsItem.Listener itemListener = (position, newValue) -> SubtitleOsdSettingsAdapter.this.listener.onSubtitleEmbeddedStylesChange(newValue); + return new BooleanOsdSettingsItem(title, labelTrue, labelFalse, embeddedStyles, itemListener, this); + } + + private OsdSettingsItem createCaptioningPreferenceItem() { + String title = context.getString(R.string.osd_subtitle_caption_preferences_title); + @SuppressLint("PrivateResource") + Drawable icon = getDrawable(context, androidx.media3.ui.R.drawable.exo_styled_controls_settings); + SimpleOsdSettingsItem.Listener itemListener = position -> listener.onOpenCaptionPreferences(); + return new SimpleOsdSettingsItem(title, icon, itemListener); + } + + public interface Listener { + + void onSubtitlePositionChange(int position); + + void onSubtitleSizeChange(int size); + + void onSubtitleEdgeTypeChange(SubtitleEdgeType edgeType); + + void onSubtitleTypefaceChange(SubtitleTypeface typeface); + + void onSubtitleEmbeddedStylesChange(boolean embeddedStyles); + + void onOpenCaptionPreferences(); + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleTypeface.java b/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleTypeface.java new file mode 100644 index 00000000..f879ecb5 --- /dev/null +++ b/app/src/main/java/com/brouken/player/osd/subtitle/SubtitleTypeface.java @@ -0,0 +1,3 @@ +package com.brouken.player.osd.subtitle; + +public enum SubtitleTypeface {Regular, Bold} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_left_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_left_24dp.xml new file mode 100644 index 00000000..8ec68a1b --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_left_24dp.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_right_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_right_24dp.xml new file mode 100644 index 00000000..3e502a81 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_right_24dp.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/osd_settings.xml b/app/src/main/res/layout/osd_settings.xml new file mode 100644 index 00000000..93bcb710 --- /dev/null +++ b/app/src/main/res/layout/osd_settings.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/osd_settings_item_left_or_right.xml b/app/src/main/res/layout/osd_settings_item_left_or_right.xml new file mode 100644 index 00000000..64171e7c --- /dev/null +++ b/app/src/main/res/layout/osd_settings_item_left_or_right.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/osd_settings_item_simple.xml b/app/src/main/res/layout/osd_settings_item_simple.xml new file mode 100644 index 00000000..c7f31ed0 --- /dev/null +++ b/app/src/main/res/layout/osd_settings_item_simple.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 1cdbc1f9..21fc2341 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -50,11 +50,6 @@ قم بتشغيل محتوى UHD Blu-ray الذي يحتوي على Dolby Vision كما هو خطير ⚠️ لم يتم العثور على ملفات فيديو - الأساليب المدمجة - تطبيق أساليب الترجمة المدمجة - لا تُطبّقُ اساليبَ الترجمَةِ الفرعيةِ المُضمّنةِ - استخدم الخط العادي الافتراضي الترجمات - اسلوب التضخيم - استخدم محرفًا غامقًا كالمعتاد + الأساليب المدمجة \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 1add7f57..1e77dc65 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -51,10 +51,5 @@ Jazyky zařízení Výchozí nastavení Titulky - Styly v titulcích - Aplikovat styly definované v titulcích - Neaplikovat styly definované v titulcích - Tučné písmo - Použít tučný styl písma - Použít výchozí styl písma + Styly v titulcích \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7e9de5f5..3fbd1e3d 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -46,15 +46,10 @@ Standard-Audiospur Standard Gerätesprachen - Eingebettete Untertitelstile anwenden Dolby Vision Profile 7 Fallback Wiedergabe von Dolby Vision Profil 7-Inhalten auf HDR-Bildschirmen Wiedergabe von UHD-Blu-ray-Inhalten mit Dolby Vision in unveränderter Form Das Umschalten von Optionen in dieser Kategorie kann die Wiedergabe von normalerweise kompatiblen Inhalten unterbrechen Untertitel - Eingebettete Stile - Eingebettete Untertitelstile nicht anwenden - Fettschrift - Fettschrift als Normalschrift verwenden - Normale Standardschriftart verwenden + Eingebettete Stile \ No newline at end of file diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index de560b82..ff8adeb5 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -50,11 +50,6 @@ Προεπιλεγμένο κομμάτι ήχου Γλώσσες συσκευής Προεπιλογή - Ενσωματωμένο στυλ - Εφαρμογή στυλ ενσωματωμένων υποτίτλων - Μη εφαρμογή στυλ ενσωματωμένων υποτίτλων - Χρήση προεπιλεγμένης κανονικής γραμματοσειράς Υπότιτλοι - Έντονοι - Χρήση έντονης γραμματοσειράς ως κανονική - + Ενσωματωμένο στυλ + \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 747babe2..623540d4 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -50,11 +50,6 @@ Reproducir contenido UHD Blu-ray con Dolby Vision tal cual Pista de audio por defecto Por defecto - Estilos integrados - Aplicar los estilos de los subtítulos incrustados - No aplicar los estilos de los subtítulos incrustados - Utilizar el tipo de letra normal por defecto Subtítulo - Estilo negrita - Usar negrita como letra habitual + Estilos integrados \ No newline at end of file diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 7acd7e45..7abcc15f 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -49,12 +49,7 @@ Nutiseadme keele alusel Nii nagu failis on vaikimisi määratud Subtiitrid - Failis leiduvad subtiitrid - Ära kasuta lõimitud subtiitrites määratletud kujundust - Paks kiri - Kasuta vaikimisi kirjatüüpi tavalisena Eelistuste muutmine sellest kategoorias võib korralikult toimiva taasesituse katki teha Eelista nutiseadme dekoodereid (vaikimisi valik) - Kasuta lõimitud subtiitrites määratletud kujundust - Kasuta paksu kirjatüübi tavalisena + Failis leiduvad subtiitrid \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9c01887b..b43da07a 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -50,11 +50,6 @@ Langues de l\'appareil Lire du contenu Blu-ray UHD contenant Dolby Vision tel quel Par défaut - Styles embarqués - Appliquer des styles de sous-titres intégrés - Ne pas appliquer les styles de sous-titres intégrés - Utiliser la police normale par défaut Sous-titrage - Style gras - Utiliser le gras comme forme régulière + Styles embarqués \ No newline at end of file diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 4d229bbc..b63a9b6f 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -50,11 +50,6 @@ कोई इंडेक्स हुई वीडियो फ़ाइल नहीं मिली। दिए गए स्टोरेज में वीडियो फ़ाइलों तक पहुंचने के लिए, सिस्टम सेटिंग्स में स्वचालित मीडिया स्कैनिंग सक्षम करें। कैप्शनिंग प्राथमिकताएँ डिफ़ॉल्ट - एंबेडेड शैलियाँ - एम्बेडेड उपशीर्षक शैलियाँ लागू करें - एम्बेडेड उपशीर्षक शैलियाँ लागू न करें - डिफ़ॉल्ट नियमित टाइपफ़ेस का उपयोग करें उपशीर्षक - बोल्ड शैली - नियमित रूप से बोल्ड टाइपफेस का प्रयोग करें + एंबेडेड शैलियाँ \ No newline at end of file diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 1703d303..4ecdaccd 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -50,11 +50,6 @@ Opasno ⚠️ Reproduciraj UHD Blu-ray sadržaj koji sadrži Dolby Vision kakav je Mijenjanje opcija u ovoj kategoriji može prekinuti reprodukciju uobičajeno kompatibilnog sadržaja - Ugrađeni stilovi - Primijeni ugrađene stilove titlova - Nemoj primijeniti ugrađene stilove titlova - Koristi osnovni stil fonta Titl - Podebljani stil - Koristi podebljani stil fonta kao osnovni + Ugrađeni stilovi \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 7c9a9245..8b958801 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -47,14 +47,9 @@ Traccia audio predefinita Lingue del dispositivo Impostazione predefinita del file multimediale - Stili incorporati - Applica stili di sottotitoli incorporati - Non applicare stili di sottotitoli incorporati - Usa il carattere regolare predefinito Riproduci contenuti del profilo 7 Dolby Vision su display HDR Retrocompatibilità del profilo 7 Dolby Vision Sottotitoli Riproduci contenuti Blu-ray UHD contenenti Dolby Vision così come sono - Stile grassetto - Utilizza il carattere grassetto come regolare + Stili incorporati \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 472f3bd2..2f25998b 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -3,5 +3,4 @@ 맞춤 삭제 설정 - 일반 기본 글꼴 사용 \ No newline at end of file diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml index 486f8884..9ae246d4 100644 --- a/app/src/main/res/values-ml/strings.xml +++ b/app/src/main/res/values-ml/strings.xml @@ -14,7 +14,6 @@ ഉപകരണ ഭാഷകൾ സ്ഥിരസ്ഥിതി ഉപശീർഷകം - വിശദമായ ശൈലി അടിക്കുറിപ്പ് മുൻഗണനകൾ കുറുക്കുവഴികൾ അനുയോജ്യം @@ -24,8 +23,6 @@ സ്വയം തിരിയുക ഉള്ളടക്കം അതേപടി കളിക്കുക വീഡിയോകൾ - ഉൾച്ചേർത്ത ശൈലികൾ - ഉൾച്ചേർത്ത ഉപശീർഷക ശൈലികൾ പ്രയോഗിക്കുക - ഉൾച്ചേർത്ത ഉപശീർഷക ശൈലികൾ പ്രയോഗിക്കരുത് ഡിസ്പ്ലേ പുതുക്കൽ നിരക്ക് മാറ്റരുത് + ഉൾച്ചേർത്ത ശൈലികൾ \ No newline at end of file diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index a55ca1d1..73c5e01b 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -50,11 +50,6 @@ ਆਪਣੇ ਆਪ ਹੀ PiP \'ਤੇ ਨਾ ਬਦਲੋ ਆਟੋ ਪਿਕਚਰ ਇਨ ਪਿਕਚਰ ਐਪ ਛੱਡਣ ਵੇਲੇ PiP \'ਤੇ ਸਵਿਚ ਕਰੋ - ਏਮਬੈਡਡ ਸਟਾਈਲ - ਏਮਬੈਡਡ ਸਬਟਾਈਟਲ ਸ਼ੈਲੀਆਂ ਲਾਗੂ ਕਰੋ - ਏਮਬੈਡਡ ਸਬਟਾਈਟਲ ਸ਼ੈਲੀਆਂ ਨੂੰ ਲਾਗੂ ਨਾ ਕਰੋ - ਡਿਫ਼ਾਲਟ ਨਿਯਮਤ ਟਾਈਪਫੇਸ ਦੀ ਵਰਤੋਂ ਕਰੋ ਸਬਟਾਈਟਲ - ਬੋਲਡ ਸ਼ੈਲੀ - ਨਿਯਮਤ ਤੌਰ \'ਤੇ ਬੋਲਡ ਟਾਈਪਫੇਸ ਦੀ ਵਰਤੋਂ ਕਰੋ + ਏਮਬੈਡਡ ਸਟਾਈਲ \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 30f89a7c..b31522eb 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -50,11 +50,23 @@ Domyślne Preferuj dekodery urządzeń (domyślnie) Zmień rozmiar - Wbudowane style - Zastosuj wbudowane style napisów - Nie stosuj wbudowanych styli napisów - Użyj domyślnej normalnej czcionki Napisy - Pogrubiony styl - Użyj pogrubionej czcionki jako normalnej + Dodatkowe ustawienia napisów są dostępne podczas odtwarzania po przytrzymaniu ikony napisów + Tak + Nie + @string/pref_subtitle_header + Położenie + Rozmiar + Typ krawędzi + @string/pref_language_track_default + Brak + Obrys + Z cieniem + Uniesione + Obniżone + Styl + Zwykły + Pogrubiony + Wbudowane style + @string/pref_captioning_preferences \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index ec138980..b7c96163 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -51,10 +51,5 @@ Reproduzir conteúdo \"Blu-ray UHD\" contendo \"Dolby Vision\" como está Alternar opções nesta categoria pode interromper a reprodução de conteúdo normalmente compatível Legenda - Estilos embutidos - Aplicar estilos de legenda embutidos - Não aplicar estilos de legenda embutidos - Estilo negrito - Usar fonte em negrito como regular - Usar fonte regular padrão + Estilos embutidos diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 786eacc0..acc61c67 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -50,11 +50,6 @@ Alternando as opções nesta categoria pode quebrar a reprodução de conteúdo normalmente compatível Idiomas do aparelho Predefinição - Aplicar estilos de legendas incorporados Legenda - Estilos embutidos - Não aplicar estilos de legendas embutidos - Usar o tipo negrito como regular - Estilo negrito - Usar o tipo regular padrão + Estilos embutidos \ No newline at end of file diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index e1f5c5ce..a2c0dc78 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -50,11 +50,6 @@ Limbile dispozitivului Implicit Pistă audio implicită - Stiluri încorporate - Aplicați stiluri de subtitrare încorporate - Nu aplicați stiluri de subtitrare încorporate - Utilizați fontul obișnuit implicit Subtitrare - Stilul bold - Folosiți caractere bold ca și caractere obișnuite + Stiluri încorporate diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 19043ca6..db8dc1f1 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -51,10 +51,5 @@ По умолчанию Воспроизведение контента Dolby Vision profile 7 на дисплеях HDR Субтитры - Встроенные стили - Применить встроенные стили субтитров - Не применять встроенные стили субтитров - Полужирный стиль - Использовать полужирный шрифт как обычный - Использовать стандартный шрифт по умолчанию + Встроенные стили \ No newline at end of file diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index 05d6e172..7245284b 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -41,11 +41,6 @@ சாதன மொழிகள் இயல்புநிலை வசன வரிகள் - உட்பொதிக்கப்பட்ட வசன பாணிகளைப் பயன்படுத்துங்கள் - தைரியமான நடை - தைரியமான தட்டச்சுப்பொறியை வழக்கமானதாகப் பயன்படுத்தவும் - உட்பொதிக்கப்பட்ட வசன பாணிகளைப் பயன்படுத்த வேண்டாம் - இயல்புநிலை வழக்கமான தட்டச்சு பயன்படுத்தவும் டால்பி பார்வை சுயவிவரம் 7 குறைவானது வீடியோ கோப்புகள் எதுவும் கிடைக்கவில்லை சாதன நோக்குநிலை @@ -55,6 +50,6 @@ தானி பயன்பாட்டு டிகோடர்களை விரும்புங்கள் சாதன டிகோடர்கள் மட்டுமே - உட்பொதிக்கப்பட்ட பாணிகள் வீடியோ நோக்குநிலை + உட்பொதிக்கப்பட்ட பாணிகள் \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index faef09b4..358dee68 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -51,10 +51,5 @@ Мова пристрою За замовчуванням Субтитри - Вбудовані стилі - Застосувати вбудовані стилі субтитрів - Не застосувати вбудовані стилі субтитрів - Жирний стиль - Використовувати жирний шрифт замість звичайного - Використовувати звичайний шрифт за замовчуванням + Вбудовані стилі diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index feaac886..5b507e42 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -50,11 +50,6 @@ Ngôn ngữ âm thanh được ưu tiên Ngôn ngữ của thiết bị Mặc định - Kiểu nhúng Phụ đề - Không áp dụng kiểu phụ đề nhúng - Áp dụng kiểu phụ đề nhúng - Im đậm - Sử dụng kiểu chữ in đậm - Sử dụng kiểu chữ mặc định + Kiểu nhúng diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index aef8a19d..42f9da30 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -50,11 +50,6 @@ 默认 杜比视界配置文件 7 后备 在 HDR 显示器上播放杜比视界配置 7 内容 - 字幕嵌入样式 - 应用嵌入字幕样式 - 不应用嵌入字幕样式 - 使用默认的常规字体 字幕 - 粗体式样 - 使用粗体字体 + 字幕嵌入样式 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index b8274514..0b234ea5 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -50,11 +50,6 @@ 預設音訊軌道 裝置語言 媒體檔案預設 - 默認使用粗體字型 - 使用預設一般字型 - 嵌入樣式 - 套用內嵌字幕樣式 + 嵌入樣式 字幕 - 不要套用內嵌字幕樣式 - 粗體樣式 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 1a096f1a..19849769 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -9,4 +9,8 @@ @color/ui_controls_background @color/ui_controls_background @color/ui_controls_background + + @color/exo_white + @color/exo_white + @color/exo_white_opacity_70 \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 3867ed3e..d5d5f997 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -11,4 +11,11 @@ 51dp 3dp + + 24dp + 20sp + 152dp + 52dp + 14sp + 12sp \ 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 511466aa..ae070b57 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -52,10 +52,23 @@ Device languages Default Subtitle - Embedded styles - Apply embedded subtitle styles - Do not apply embedded subtitle styles - Bold style - Use bold typeface as regular - Use default regular typeface + Additional subtitle settings are available during playback by long-pressing the subtitles icon + @string/pref_language_track_default + On + Off + @string/pref_subtitle_header + Position + Size + Edge type + @string/pref_language_track_default + None + Outline + Drop shadow + Raised + Depressed + Typeface + Regular + Bold + Embedded styles + @string/pref_captioning_preferences \ No newline at end of file diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 73cd1b33..e88762ad 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -48,19 +48,9 @@ - - - +