diff --git a/app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt b/app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt index 8e064b2e90..e76cb77099 100644 --- a/app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt +++ b/app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt @@ -180,6 +180,16 @@ class UserPreferences(context: Context) : SharedPreferenceStore( * Enable series thumbnails in home screen rows */ var seriesThumbnailsEnabled = Preference.boolean("pref_enable_series_thumbnails", true) + + /** + * Enable subtitles background + */ + var subtitlesBackgroundEnabled = Preference.boolean("subtitles_background_enabled", true) + + /** + * Set default subtitles font size + */ + var defaultSubtitlesSize = Preference.int("subtitles_size", 28) } init { diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java b/app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java index 9efc4a67bd..6a89eb6471 100644 --- a/app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java +++ b/app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java @@ -47,6 +47,7 @@ import org.jellyfin.androidtv.R; import org.jellyfin.androidtv.TvApp; import org.jellyfin.androidtv.constant.CustomMessage; +import org.jellyfin.androidtv.preference.UserPreferences; import org.jellyfin.androidtv.data.model.DataRefreshService; import org.jellyfin.androidtv.databinding.OverlayTvGuideBinding; import org.jellyfin.androidtv.databinding.VlcPlayerInterfaceBinding; @@ -68,6 +69,7 @@ import org.jellyfin.androidtv.ui.presentation.CardPresenter; import org.jellyfin.androidtv.ui.presentation.ChannelCardPresenter; import org.jellyfin.androidtv.ui.presentation.PositionableListRowPresenter; +import org.jellyfin.androidtv.ui.shared.OutlineSpan; import org.jellyfin.androidtv.ui.shared.PaddedLineBackgroundSpan; import org.jellyfin.androidtv.util.DeviceUtils; import org.jellyfin.androidtv.util.ImageUtils; @@ -148,7 +150,9 @@ public class CustomPlaybackOverlayFragment extends Fragment implements IPlayback private static final long SUBTITLE_RENDER_INTERVAL_MS = 50; private SubtitleTrackInfo subtitleTrackInfo; private int currentSubtitleIndex = 0; + private int subtitlesSize = KoinJavaComponent.get(UserPreferences.class).get(UserPreferences.Companion.getDefaultSubtitlesSize()); private long lastSubtitlePositionMs = 0; + private boolean subtitlesBackgroundEnabled = KoinJavaComponent.get(UserPreferences.class).get(UserPreferences.Companion.getSubtitlesBackgroundEnabled()); private final Lazy apiClient = inject(ApiClient.class); private final Lazy mediaManager = inject(MediaManager.class); @@ -258,6 +262,9 @@ public void onActivityCreated(Bundle savedInstanceState) { binding.subtitlesText.setShadowLayer(SUBTITLE_PADDING, 0, 0, Color.TRANSPARENT); binding.subtitlesText.setPadding(SUBTITLE_PADDING, 0, SUBTITLE_PADDING, 0); + // Subtitles font size configuration + binding.subtitlesText.setTextSize(subtitlesSize); + //pre-load animations fadeOut = AnimationUtils.loadAnimation(requireContext(), R.anim.abc_fade_out); fadeOut.setAnimationListener(hideAnimationListener); @@ -1469,7 +1476,10 @@ private void renderSubtitles(@Nullable final String text) { final SpannableString span = new SpannableString(TextUtilsKt.toHtmlSpanned(htmlText)); span.setSpan(new ForegroundColorSpan(Color.WHITE), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - span.setSpan(new PaddedLineBackgroundSpan(ContextCompat.getColor(requireContext(), R.color.black_opaque), SUBTITLE_PADDING), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + if (subtitlesBackgroundEnabled) { + span.setSpan(new PaddedLineBackgroundSpan(ContextCompat.getColor(requireContext(), R.color.black_opaque), SUBTITLE_PADDING), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + span.setSpan(new OutlineSpan(), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); binding.subtitlesText.setText(span); binding.subtitlesText.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/preference/category/playback.kt b/app/src/main/java/org/jellyfin/androidtv/ui/preference/category/playback.kt index e19ffa797d..537102b5d1 100644 --- a/app/src/main/java/org/jellyfin/androidtv/ui/preference/category/playback.kt +++ b/app/src/main/java/org/jellyfin/androidtv/ui/preference/category/playback.kt @@ -148,4 +148,17 @@ fun OptionsScreen.playbackCategory( } depends { userPreferences[UserPreferences.videoPlayer] == PreferredVideoPlayer.EXTERNAL } } + + checkbox { + setTitle(R.string.pref_subtitles_background_title) + setContent(R.string.pref_subtitles_background_summary) + bind(userPreferences, UserPreferences.subtitlesBackgroundEnabled) + } + + seekbar { + setTitle(R.string.pref_subtitles_size) + min = 18 + max = 38 + bind(userPreferences, UserPreferences.defaultSubtitlesSize) + } } diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/shared/OutlineSpan.kt b/app/src/main/java/org/jellyfin/androidtv/ui/shared/OutlineSpan.kt new file mode 100644 index 0000000000..cf3eb4caf6 --- /dev/null +++ b/app/src/main/java/org/jellyfin/androidtv/ui/shared/OutlineSpan.kt @@ -0,0 +1,55 @@ +package org.jellyfin.androidtv.ui.shared + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.text.style.ReplacementSpan + +/** + * A class that draws the outlines of a text + */ +class OutlineSpan : ReplacementSpan() { + override fun getSize( + paint: Paint, + text: CharSequence, + start: Int, + end: Int, + fm: Paint.FontMetricsInt? + ): Int { + if (fm != null) { + fm.ascent = paint.fontMetricsInt.ascent + fm.bottom = paint.fontMetricsInt.bottom + fm.descent = paint.fontMetricsInt.descent + fm.leading = paint.fontMetricsInt.leading + fm.top = paint.fontMetricsInt.top + } + + return paint.measureText(text, start, end).toInt() + } + + override fun draw( + canvas: Canvas, + text: CharSequence, + start: Int, + end: Int, + x: Float, + top: Int, + y: Int, + bottom: Int, + paint: Paint + ) { + + val strokePaint = paint.apply { + color = Color.BLACK + style = Paint.Style.STROKE + strokeWidth = 4f + } + canvas.drawText(text, start, end, x, y.toFloat(), strokePaint) + + val fillPaint = paint.apply { + color = Color.WHITE + style = Paint.Style.FILL + } + canvas.drawText(text, start, end, x, y.toFloat(), fillPaint) + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76db8c3445..4cbcb840c1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -464,4 +464,7 @@ Home section %1$d Search Jellyfin Media + Enable subtitle background + Show a black background behind the subtitles + Subtitle size