@@ -25,6 +25,9 @@ import android.os.Build
2525import android.util.Log
2626import androidx.activity.compose.BackHandler
2727import androidx.annotation.OptIn
28+ import androidx.compose.foundation.isSystemInDarkTheme
29+ import androidx.compose.material3.ColorScheme
30+ import androidx.compose.material3.MaterialTheme
2831import androidx.compose.material3.adaptive.currentWindowSize
2932import androidx.compose.runtime.Composable
3033import androidx.compose.runtime.LaunchedEffect
@@ -35,6 +38,8 @@ import androidx.compose.ui.tooling.preview.Preview
3538import androidx.core.view.WindowCompat
3639import androidx.core.view.WindowInsetsCompat
3740import androidx.core.view.WindowInsetsControllerCompat
41+ import androidx.compose.material3.Typography
42+
3843
3944import androidx.media3.common.util.UnstableApi
4045import net.newpipe.newplayer.data.NewPlayerException
@@ -43,15 +48,16 @@ import net.newpipe.newplayer.uiModel.InternalNewPlayerViewModel
4348import net.newpipe.newplayer.uiModel.NewPlayerViewModel
4449import net.newpipe.newplayer.uiModel.NewPlayerViewModelDummy
4550import net.newpipe.newplayer.ui.audioplayer.AudioPlayerUI
46- import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
51+ import net.newpipe.newplayer.ui.theme.VideoPlayerDarkTheme
4752import net.newpipe.newplayer.ui.videoplayer.VideoPlayerUi
4853import net.newpipe.newplayer.ui.common.LockScreenOrientation
4954import net.newpipe.newplayer.ui.common.activity
50- import net.newpipe.newplayer.ui.common.findActivity
5155import net.newpipe.newplayer.ui.common.getDefaultBrightness
5256import net.newpipe.newplayer.ui.common.isInPowerSaveMode
5357import net.newpipe.newplayer.ui.common.setScreenBrightness
54- import net.newpipe.newplayer.ui.common.window
58+ import net.newpipe.newplayer.ui.theme.NewPlayerTypography
59+ import net.newpipe.newplayer.ui.theme.NewPlayerDarkColorScheme
60+ import net.newpipe.newplayer.ui.theme.NewPlayerLightColorScheme
5561
5662private const val TAG = " VideoPlayerUI"
5763
@@ -65,122 +71,138 @@ private const val TAG = "VideoPlayerUI"
6571 * or views are hidden and only NewPlayerUI is visible. You can read more about this in
6672 * the [NewPlayerViewModel], since the [viewModel] is responsible to tell your UI how to behave
6773 * in such cases.
74+ *
75+ * @param viewModel the NewPlayerViewModel that should control this NewPlayerUi.
76+ * @param lightColorScheme is the color scheme used by non video ui related composables, when the system is in light mode.
77+ * @param darkColorScheme is the color scheme used by the video ui related composables, and the rest of the ui if the system is in dark mode.
78+ * @param the typography used by NewPlayer
6879 */
6980@OptIn(UnstableApi ::class )
7081@Composable
7182fun NewPlayerUI (
7283 viewModel : NewPlayerViewModel ? ,
84+ lightColorScheme : ColorScheme = NewPlayerLightColorScheme ,
85+ darkColorScheme : ColorScheme = NewPlayerDarkColorScheme ,
86+ typography : Typography = NewPlayerTypography
7387) {
74- if (viewModel !is InternalNewPlayerViewModel ? ) {
75- throw NewPlayerException (
76- " The view model given to NewPlayerUI must be of type InternalNewPlayerViewModel. "
77- + " This can not be implemented externally, so do not extend NewPlayerViewModel"
78- )
79- }
80-
81- if (viewModel == null ) {
82- LoadingPlaceholder ()
83- } else if (viewModel.newPlayer == null ) {
84- LoadingPlaceholder (viewModel.uiState.collectAsState().value.embeddedUiRatio)
85- } else {
86- val uiState by viewModel.uiState.collectAsState()
88+ MaterialTheme (colorScheme = darkColorScheme, typography = typography) {
89+ if (viewModel !is InternalNewPlayerViewModel ? ) {
90+ throw NewPlayerException (
91+ " The view model given to NewPlayerUI must be of type InternalNewPlayerViewModel. "
92+ + " This can not be implemented externally, so do not extend NewPlayerViewModel"
93+ )
94+ }
8795
88- // find out whether application is light or dark mode from LocalContext.current
89- val view = LocalView .current
90- val activity = activity()
91- val window = activity.window
96+ if (viewModel == null ) {
97+ LoadingPlaceholder ()
98+ } else if (viewModel.newPlayer == null ) {
99+ LoadingPlaceholder (viewModel.uiState.collectAsState().value.embeddedUiRatio)
100+ } else {
101+ val uiState by viewModel.uiState.collectAsState()
92102
93- // Setup fullscreen
103+ // find out whether application is light or dark mode from LocalContext.current
104+ val view = LocalView .current
105+ val activity = activity()
106+ val window = activity.window
94107
108+ // Setup fullscreen
95109
96- LaunchedEffect (uiState.uiMode.fullscreen) {
97- if (uiState.uiMode.fullscreen) {
98- WindowCompat .getInsetsController(window, view).isAppearanceLightStatusBars =
99- false
100- } else {
101- uiState.embeddedUiConfig?.let {
110+ val isInDarkTheme = isSystemInDarkTheme()
111+ LaunchedEffect (uiState.uiMode.forceSysUiDarkThemeMode, key2 = isInDarkTheme) {
112+ if (uiState.uiMode.forceSysUiDarkThemeMode) {
102113 WindowCompat .getInsetsController(window, view).isAppearanceLightStatusBars =
103- it.systemBarInLightMode
114+ false
115+ } else {
116+ uiState.embeddedUiConfig?.let {
117+ WindowCompat .getInsetsController(window, view).isAppearanceLightStatusBars = isInDarkTheme
118+ }
104119 }
105120 }
106- }
107121
108- if (uiState.uiMode.fullscreen) {
109- BackHandler {
110- viewModel.onBackPressed()
122+ if (uiState.uiMode.fullscreen) {
123+ BackHandler {
124+ viewModel.onBackPressed()
125+ }
111126 }
112- }
113127
114- // setup immersive mode
115- LaunchedEffect (
116- key1 = uiState.uiMode.systemInsetsVisible,
117- ) {
118- val windowInsetsController = WindowCompat .getInsetsController(window, window.decorView)
119- windowInsetsController.systemBarsBehavior =
120- WindowInsetsControllerCompat .BEHAVIOR_DEFAULT
121-
122- if (uiState.uiMode.systemInsetsVisible) {
123- windowInsetsController.show(WindowInsetsCompat .Type .systemBars())
124- } else {
125- windowInsetsController.hide(WindowInsetsCompat .Type .systemBars())
128+ // setup immersive mode
129+ LaunchedEffect (
130+ key1 = uiState.uiMode.systemInsetsVisible,
131+ ) {
132+ val windowInsetsController =
133+ WindowCompat .getInsetsController(window, window.decorView)
134+ windowInsetsController.systemBarsBehavior =
135+ WindowInsetsControllerCompat .BEHAVIOR_DEFAULT
136+
137+ if (uiState.uiMode.systemInsetsVisible) {
138+ windowInsetsController.show(WindowInsetsCompat .Type .systemBars())
139+ } else {
140+ windowInsetsController.hide(WindowInsetsCompat .Type .systemBars())
141+ }
126142 }
127- }
128143
129- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .LOLLIPOP ) {
130- val isInPowerSaveMode = isInPowerSaveMode()
131- LaunchedEffect (key1 = isInPowerSaveMode) {
132- viewModel.deviceInPowerSaveMode = isInPowerSaveMode
144+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .LOLLIPOP ) {
145+ val isInPowerSaveMode = isInPowerSaveMode()
146+ LaunchedEffect (key1 = isInPowerSaveMode) {
147+ viewModel.deviceInPowerSaveMode = isInPowerSaveMode
148+ }
133149 }
134- }
135150
136- if (uiState.uiMode.fitScreenRotation) {
137- if (uiState.contentRatio < 1 ) {
138- LockScreenOrientation (orientation = ActivityInfo .SCREEN_ORIENTATION_PORTRAIT )
151+ if (uiState.uiMode.fitScreenRotation) {
152+ if (uiState.contentRatio < 1 ) {
153+ LockScreenOrientation (orientation = ActivityInfo .SCREEN_ORIENTATION_PORTRAIT )
154+ } else {
155+ LockScreenOrientation (orientation = ActivityInfo .SCREEN_ORIENTATION_LANDSCAPE )
156+ }
139157 } else {
140- LockScreenOrientation (orientation = ActivityInfo .SCREEN_ORIENTATION_LANDSCAPE )
141- }
142- } else {
143- uiState.embeddedUiConfig?.let {
144- LockScreenOrientation (orientation = it.screenOrientation)
158+ uiState.embeddedUiConfig?.let {
159+ LockScreenOrientation (orientation = it.screenOrientation)
160+ }
145161 }
146- }
147-
148- val defaultBrightness = activity.getDefaultBrightness()
149- LaunchedEffect (key1 = uiState.brightness) {
150- Log .d(TAG , " New Brightness: ${uiState.brightness} " )
151162
152- setScreenBrightness(
153- if (uiState.brightness < 0 ) defaultBrightness else uiState.brightness, activity
154- )
155- }
163+ val defaultBrightness = activity.getDefaultBrightness()
164+ LaunchedEffect (key1 = uiState.brightness) {
165+ Log .d(TAG , " New Brightness: ${uiState.brightness} " )
156166
157- when (uiState.uiMode) {
158-
159- UIModeState .FULLSCREEN_VIDEO ,
160- UIModeState .FULLSCREEN_VIDEO_CONTROLLER_UI ,
161- UIModeState .FULLSCREEN_VIDEO_CHAPTER_SELECT ,
162- UIModeState .FULLSCREEN_VIDEO_STREAM_SELECT ,
163- UIModeState .EMBEDDED_VIDEO ,
164- UIModeState .EMBEDDED_VIDEO_CONTROLLER_UI ,
165- UIModeState .EMBEDDED_VIDEO_STREAM_SELECT ,
166- UIModeState .EMBEDDED_VIDEO_CHAPTER_SELECT ,
167- UIModeState .PIP -> {
168- VideoPlayerUi (viewModel = viewModel, uiState = uiState)
169- }
170-
171- UIModeState .FULLSCREEN_AUDIO ,
172- UIModeState .EMBEDDED_AUDIO ,
173- UIModeState .AUDIO_STREAM_SELECT ,
174- UIModeState .AUDIO_CHAPTER_SELECT -> {
175- val windowSize = currentWindowSize()
176- AudioPlayerUI (
177- viewModel = viewModel, uiState = uiState,
178- isLandScape = windowSize.height < windowSize.width
167+ setScreenBrightness(
168+ if (uiState.brightness < 0 ) defaultBrightness else uiState.brightness, activity
179169 )
180170 }
181171
182- else -> {
183- LoadingPlaceholder (uiState.embeddedUiRatio)
172+ when (uiState.uiMode) {
173+
174+ UIModeState .FULLSCREEN_VIDEO ,
175+ UIModeState .FULLSCREEN_VIDEO_CONTROLLER_UI ,
176+ UIModeState .FULLSCREEN_VIDEO_CHAPTER_SELECT ,
177+ UIModeState .FULLSCREEN_VIDEO_STREAM_SELECT ,
178+ UIModeState .EMBEDDED_VIDEO ,
179+ UIModeState .EMBEDDED_VIDEO_CONTROLLER_UI ,
180+ UIModeState .EMBEDDED_VIDEO_STREAM_SELECT ,
181+ UIModeState .EMBEDDED_VIDEO_CHAPTER_SELECT ,
182+ UIModeState .PIP -> {
183+ VideoPlayerUi (viewModel = viewModel, uiState = uiState)
184+ }
185+
186+ UIModeState .FULLSCREEN_AUDIO ,
187+ UIModeState .EMBEDDED_AUDIO ,
188+ UIModeState .AUDIO_STREAM_SELECT ,
189+ UIModeState .AUDIO_CHAPTER_SELECT -> {
190+ val windowSize = currentWindowSize()
191+ MaterialTheme (
192+ colorScheme =
193+ if (isInDarkTheme) darkColorScheme else lightColorScheme,
194+ typography = typography
195+ ) {
196+ AudioPlayerUI (
197+ viewModel = viewModel, uiState = uiState,
198+ isLandScape = windowSize.height < windowSize.width
199+ )
200+ }
201+ }
202+
203+ else -> {
204+ LoadingPlaceholder (uiState.embeddedUiRatio)
205+ }
184206 }
185207 }
186208 }
@@ -191,7 +213,7 @@ fun NewPlayerUI(
191213@Preview(device = " spec:width=1080px,height=700px,dpi=440,orientation=landscape" )
192214@Composable
193215private fun PlayerUIPreviewEmbedded () {
194- VideoPlayerTheme {
216+ VideoPlayerDarkTheme {
195217 NewPlayerUI (viewModel = NewPlayerViewModelDummy ())
196218 }
197219}
0 commit comments