Skip to content

Commit 72373bf

Browse files
committed
Add support for empty and logo screensaver modes to reduce (OLED) screen burn-in
- Introduces `ScreenSaverType` enum with `NORMAL` (slideshow) and `EMPTY_SCREEN` (black screen) options. - Adds `screensaverType` user preference to control the screensaver type. - Adds `screensaverShowLogo` user preference to show or not the logo on the screensaver. - Implements the empty screen logic in `DreamView`. - Update DreamHost logic for the new settings. - Add the new settings on the Customization screen.
1 parent 160965f commit 72373bf

File tree

6 files changed

+89
-22
lines changed

6 files changed

+89
-22
lines changed

app/src/main/java/org/jellyfin/androidtv/integration/dream/composable/DreamHost.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.compose.runtime.getValue
66
import org.jellyfin.androidtv.integration.dream.DreamViewModel
77
import org.jellyfin.androidtv.preference.UserPreferences
88
import org.jellyfin.androidtv.preference.constant.ClockBehavior
9+
import org.jellyfin.androidtv.preference.constant.ScreenSaverType
910
import org.koin.androidx.compose.koinViewModel
1011
import org.koin.compose.koinInject
1112

@@ -20,6 +21,11 @@ fun DreamHost() {
2021
showClock = when (userPreferences[UserPreferences.clockBehavior]) {
2122
ClockBehavior.ALWAYS, ClockBehavior.IN_MENUS -> true
2223
else -> false
23-
}
24+
},
25+
showLogoSetting = userPreferences[UserPreferences.screensaverShowLogo],
26+
showBlank = when (userPreferences[UserPreferences.screensaverType]) {
27+
ScreenSaverType.EMPTY_SCREEN -> true
28+
else -> false
29+
},
2430
)
2531
}

app/src/main/java/org/jellyfin/androidtv/integration/dream/composable/DreamView.kt

+27-21
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,33 @@ import org.jellyfin.androidtv.integration.dream.model.DreamContent
1616
fun DreamView(
1717
content: DreamContent,
1818
showClock: Boolean,
19-
) = Box(
20-
modifier = Modifier
21-
.fillMaxSize()
22-
) {
23-
AnimatedContent(
24-
targetState = content,
25-
transitionSpec = {
26-
fadeIn(tween(durationMillis = 1_000)) togetherWith fadeOut(snap(delayMillis = 1_000))
27-
},
28-
label = "DreamContentTransition"
29-
) { content ->
30-
when (content) {
31-
DreamContent.Logo -> DreamContentLogo()
32-
is DreamContent.LibraryShowcase -> DreamContentLibraryShowcase(content)
33-
is DreamContent.NowPlaying -> DreamContentNowPlaying(content)
19+
showLogoSetting: Boolean,
20+
showBlank: Boolean,
21+
) = if (showBlank) {
22+
Box(modifier = Modifier.fillMaxSize()) {}
23+
} else {
24+
Box(
25+
modifier = Modifier
26+
.fillMaxSize()
27+
) {
28+
AnimatedContent(
29+
targetState = content,
30+
transitionSpec = {
31+
fadeIn(tween(durationMillis = 1_000)) togetherWith fadeOut(snap(delayMillis = 1_000))
32+
},
33+
label = "DreamContentTransition"
34+
) { content ->
35+
when (content) {
36+
DreamContent.Logo -> DreamContentLogo()
37+
is DreamContent.LibraryShowcase -> DreamContentLibraryShowcase(content)
38+
is DreamContent.NowPlaying -> DreamContentNowPlaying(content)
39+
}
3440
}
35-
}
3641

37-
// Header overlay
38-
DreamHeader(
39-
showLogo = content != DreamContent.Logo,
40-
showClock = showClock,
41-
)
42+
// Header overlay
43+
DreamHeader(
44+
showLogo = content != DreamContent.Logo && showLogoSetting,
45+
showClock = showClock,
46+
)
47+
}
4248
}

app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt

+12
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.jellyfin.androidtv.preference.constant.ClockBehavior
99
import org.jellyfin.androidtv.preference.constant.NextUpBehavior
1010
import org.jellyfin.androidtv.preference.constant.RatingType
1111
import org.jellyfin.androidtv.preference.constant.RefreshRateSwitchingBehavior
12+
import org.jellyfin.androidtv.preference.constant.ScreenSaverType
1213
import org.jellyfin.androidtv.preference.constant.WatchedIndicatorBehavior
1314
import org.jellyfin.androidtv.preference.constant.ZoomMode
1415
import org.jellyfin.androidtv.ui.playback.segment.MediaSegmentAction
@@ -190,6 +191,17 @@ class UserPreferences(context: Context) : SharedPreferenceStore(
190191
*/
191192
var screensaverInAppEnabled = booleanPreference("screensaver_inapp_enabled", true)
192193

194+
/**
195+
* Screensaver Type in app
196+
*/
197+
var screensaverType = enumPreference("screensaver_inapp_type", ScreenSaverType.NORMAL)
198+
199+
/**
200+
* Show Logo in screensaver
201+
*/
202+
var screensaverShowLogo = booleanPreference("screensaver_inapp_showlogo", true)
203+
204+
193205
/**
194206
* Timeout before showing the screensaver in app, depends on [screensaverInAppEnabled].
195207
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.jellyfin.androidtv.preference.constant
2+
3+
import org.jellyfin.androidtv.R
4+
import org.jellyfin.preference.PreferenceEnum
5+
6+
enum class ScreenSaverType(
7+
override val nameRes: Int,
8+
) : PreferenceEnum {
9+
/**
10+
* Sets the screensaver to normal slideshow behavior
11+
*/
12+
NORMAL(R.string.lbl_fit),
13+
14+
/**
15+
* Sets the screensaver to black screen
16+
*/
17+
EMPTY_SCREEN(R.string.lbl_empty_screen),
18+
}
19+

app/src/main/java/org/jellyfin/androidtv/ui/preference/screen/CustomizationPreferencesScreen.kt

+19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.jellyfin.androidtv.preference.UserPreferences
55
import org.jellyfin.androidtv.preference.constant.AppTheme
66
import org.jellyfin.androidtv.preference.constant.ClockBehavior
77
import org.jellyfin.androidtv.preference.constant.RatingType
8+
import org.jellyfin.androidtv.preference.constant.ScreenSaverType
89
import org.jellyfin.androidtv.preference.constant.WatchedIndicatorBehavior
910
import org.jellyfin.androidtv.ui.preference.dsl.OptionsFragment
1011
import org.jellyfin.androidtv.ui.preference.dsl.checkbox
@@ -122,6 +123,24 @@ class CustomizationPreferencesScreen : OptionsFragment() {
122123
depends { userPreferences[UserPreferences.screensaverInAppEnabled] }
123124
}
124125

126+
enum<ScreenSaverType> {
127+
setTitle(R.string.pref_screensaver_inapp_type)
128+
bind(userPreferences, UserPreferences.screensaverType)
129+
depends { userPreferences[UserPreferences.screensaverInAppEnabled] }
130+
}
131+
checkbox {
132+
setTitle(R.string.pref_screensaver_showlogo)
133+
setContent(
134+
R.string.pref_screensaver_showlogo_enabled,
135+
R.string.pref_screensaver_showlogo_disabled,
136+
)
137+
depends {
138+
userPreferences[UserPreferences.screensaverType] == ScreenSaverType.NORMAL
139+
}
140+
141+
bind(userPreferences, UserPreferences.screensaverShowLogo)
142+
}
143+
125144
checkbox {
126145
setTitle(R.string.pref_screensaver_ageratingrequired_title)
127146
setContent(

app/src/main/res/values/strings.xml

+5
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
<string name="msg_cannot_play">This item cannot be played</string>
9595
<string name="lbl_no_items">No items</string>
9696
<string name="lbl_empty">Empty</string>
97+
<string name="lbl_empty_screen">Empty Screen</string>
9798
<string name="lbl_tv_queuing">Play next episode automatically</string>
9899
<string name="lbl_search_hint">Search text (select for keyboard)</string>
99100
<string name="lbl_play_first_unwatched">Play first unwatched</string>
@@ -476,6 +477,7 @@
476477
<string name="pref_screensaver_inapp_enabled">Use in-app screensaver</string>
477478
<string name="pref_screensaver_inapp_enabled_description">Show the Jellyfin screensaver while the app is open</string>
478479
<string name="pref_screensaver_inapp_timeout">Start screensaver after</string>
480+
<string name="pref_screensaver_inapp_type">Screensaver type</string>
479481
<string name="enable_reactive_homepage">Enable reactive homepage</string>
480482
<string name="not_set">Not set</string>
481483
<string name="lbl_album_artists">Album artists</string>
@@ -497,6 +499,9 @@
497499
<string name="random">Random</string>
498500
<string name="unreleased">Not yet released</string>
499501
<string name="pref_playback_advanced">Advanced playback preferences</string>
502+
<string name="pref_screensaver_showlogo">Show Logo in Screensaver</string>
503+
<string name="pref_screensaver_showlogo_enabled">Show Logo in Screensaver</string>
504+
<string name="pref_screensaver_showlogo_disabled">Do not show Logo in Screensaver</string>
500505
<string name="pref_screensaver_ageratingmax">Maximum age rating</string>
501506
<string name="pref_screensaver_ageratingmax_zero">All ages</string>
502507
<string name="pref_screensaver_ageratingmax_entry">Up to age %1$d</string>

0 commit comments

Comments
 (0)