Skip to content

Commit d50e85e

Browse files
author
sentinelweb
committed
#489 app exoplayer remote volume
1 parent e994053 commit d50e85e

File tree

7 files changed

+76
-29
lines changed

7 files changed

+76
-29
lines changed

app/src/main/java/uk/co/sentinelweb/cuer/app/di/Modules.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ object Modules {
273273
}
274274
factory { ServiceWrapper(androidApplication(), get()) }
275275
factory { EdgeToEdgeWrapper() }
276+
factory { HideStatusBarWrapper() }
276277
factory { AppListBuilder(androidApplication(), get()) }
277278
factory { PlayerConnectedChecker(get(), get()) }
278279
}

app/src/main/java/uk/co/sentinelweb/cuer/app/ui/exoplayer/ExoActivity.kt

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ package uk.co.sentinelweb.cuer.app.ui.exoplayer
1717

1818
import android.content.Context
1919
import android.content.Intent
20-
import android.content.Intent.*
20+
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
2121
import android.os.Bundle
2222
import android.util.Log
2323
import androidx.activity.compose.setContent
@@ -50,9 +50,7 @@ import uk.co.sentinelweb.cuer.app.ui.common.dialog.AlertDialogContract
5050
import uk.co.sentinelweb.cuer.app.ui.common.dialog.AlertDialogCreator
5151
import uk.co.sentinelweb.cuer.app.ui.common.dialog.SelectDialogCreator
5252
import uk.co.sentinelweb.cuer.app.ui.common.dialog.support.SupportDialogFragment
53-
import uk.co.sentinelweb.cuer.app.ui.common.navigation.LinkNavigator
5453
import uk.co.sentinelweb.cuer.app.ui.common.navigation.NavigationModel.Param.PLAYLIST_AND_ITEM
55-
import uk.co.sentinelweb.cuer.app.ui.common.navigation.NavigationRouter
5654
import uk.co.sentinelweb.cuer.app.ui.common.navigation.navigationRouter
5755
import uk.co.sentinelweb.cuer.app.ui.common.skip.SkipContract
5856
import uk.co.sentinelweb.cuer.app.ui.common.skip.SkipPresenter
@@ -71,43 +69,29 @@ import uk.co.sentinelweb.cuer.app.ui.share.ShareNavigationHack
7169
import uk.co.sentinelweb.cuer.app.ui.ytplayer.ItemLoader
7270
import uk.co.sentinelweb.cuer.app.ui.ytplayer.LocalPlayerCastListener
7371
import uk.co.sentinelweb.cuer.app.ui.ytplayer.PlayerModule
74-
import uk.co.sentinelweb.cuer.app.ui.ytplayer.ShowHideUi
7572
import uk.co.sentinelweb.cuer.app.ui.ytplayer.ayt_land.AytLandActivity
7673
import uk.co.sentinelweb.cuer.app.ui.ytplayer.floating.FloatingPlayerServiceManager
77-
import uk.co.sentinelweb.cuer.app.util.chromecast.ChromeCastWrapper
7874
import uk.co.sentinelweb.cuer.app.util.extension.activityScopeWithSource
79-
import uk.co.sentinelweb.cuer.app.util.wrapper.EdgeToEdgeWrapper
80-
import uk.co.sentinelweb.cuer.app.util.wrapper.ResourceWrapper
81-
import uk.co.sentinelweb.cuer.app.util.wrapper.ToastWrapper
82-
import uk.co.sentinelweb.cuer.core.providers.CoroutineContextProvider
83-
import uk.co.sentinelweb.cuer.core.wrapper.LogWrapper
75+
import uk.co.sentinelweb.cuer.app.util.wrapper.HideStatusBarWrapper
8476
import uk.co.sentinelweb.cuer.domain.PlaylistAndItemDomain
8577
import uk.co.sentinelweb.cuer.domain.PlaylistDomain
86-
import uk.co.sentinelweb.cuer.domain.PlaylistItemDomain
8778
import uk.co.sentinelweb.cuer.domain.ext.serialise
8879

8980
class ExoActivity : FragmentActivity(), AndroidScopeComponent {
9081

9182
override val scope: Scope by activityScopeWithSource<AytLandActivity>()
9283

9384
private val controller: PlayerController by inject()
94-
private val log: LogWrapper by inject()
95-
private val coroutines: CoroutineContextProvider by inject()
96-
private val edgeToEdgeWrapper: EdgeToEdgeWrapper by inject()
97-
private val navRouter: NavigationRouter by inject()
98-
private val toast: ToastWrapper by inject()
99-
private val res: ResourceWrapper by inject()
85+
private val hideStatusBarWrapper: HideStatusBarWrapper by inject()
10086
private val castListener: LocalPlayerCastListener by inject()
101-
private val chromeCastWrapper: ChromeCastWrapper by inject()
10287
private val floatingService: FloatingPlayerServiceManager by inject()
10388

104-
private var currentItem: PlaylistItemDomain? = null
105-
10689
private lateinit var mviView: MviViewImpl
10790

10891
override fun onCreate(savedInstanceState: Bundle?) {
10992
super.onCreate(savedInstanceState)
11093
castListener.listen()
94+
hideStatusBarWrapper.hide(this)
11195
mviView = MviViewImpl()
11296
enableEdgeToEdge()
11397
setContent {
@@ -135,7 +119,6 @@ class ExoActivity : FragmentActivity(), AndroidScopeComponent {
135119
)
136120
}
137121

138-
// region MVI view
139122
inner class MviViewImpl :
140123
BaseMviView<Model, Event>(),
141124
PlayerContract.View {
@@ -170,7 +153,6 @@ class ExoActivity : FragmentActivity(), AndroidScopeComponent {
170153
}
171154
}
172155

173-
174156
companion object {
175157

176158
// todo cleanup
@@ -230,11 +212,10 @@ class ExoActivity : FragmentActivity(), AndroidScopeComponent {
230212
playlistItemOrchestrator = get(),
231213
playerSessionManager = get(),
232214
playerSessionListener = get(),
233-
config = PlayerContract.PlayerConfig(100f),
215+
config = PlayerContract.PlayerConfig(1f),
234216
prefs = get(),
235217
).create()
236218
}
237-
scoped { ShowHideUi(get<ExoActivity>()) }
238219
scoped<PlayerContract.PlaylistItemLoader> { ItemLoader(get(), get()) }
239220
scoped { navigationRouter(false, get<ExoActivity>(), withNavHost = false) }
240221
scoped<SkipContract.External> {
@@ -255,7 +236,6 @@ class ExoActivity : FragmentActivity(), AndroidScopeComponent {
255236
}
256237
factory<AlertDialogContract.Creator> { AlertDialogCreator(get(), get()) }
257238
scoped { LocalPlayerCastListener(get(), get()) }
258-
scoped { LinkNavigator(get(), get(), get(), get(), get(), get(), false) }
259239
scoped { ShareNavigationHack() }
260240
}
261241
}

app/src/main/java/uk/co/sentinelweb/cuer/app/ui/exoplayer/ExoPlayerComposebles.kt

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ import androidx.media3.common.Player
2020
import androidx.media3.common.VideoSize
2121
import androidx.media3.exoplayer.ExoPlayer
2222
import httpLocalNetworkUrl
23-
import kotlinx.coroutines.Job
2423
import kotlinx.coroutines.delay
2524
import org.koin.core.component.KoinComponent
2625
import org.koin.core.component.inject
2726
import uk.co.sentinelweb.cuer.app.ui.common.compose.CuerSharedTheme
2827
import uk.co.sentinelweb.cuer.app.ui.player.PlayerComposeables
28+
import uk.co.sentinelweb.cuer.app.ui.player.PlayerComposeables.PlayerTransport
29+
import uk.co.sentinelweb.cuer.app.ui.player.PlayerComposeables.VolumeDisplay
2930
import uk.co.sentinelweb.cuer.app.ui.player.PlayerContract.MviStore.Label.Command
3031
import uk.co.sentinelweb.cuer.app.ui.player.PlayerContract.MviStore.Label.None
3132
import uk.co.sentinelweb.cuer.app.ui.player.PlayerContract.PlayerCommand
@@ -36,6 +37,8 @@ import uk.co.sentinelweb.cuer.remote.server.LocalRepository
3637

3738
private const val LOG_TAG = "ExoPlayerComposebles"
3839

40+
private const val HIDE_CONTROLS_TIMEOUT = 3000L
41+
3942
object ExoPlayerComposebles : KoinComponent {
4043

4144
private val localRepository: LocalRepository by inject()
@@ -50,6 +53,8 @@ object ExoPlayerComposebles : KoinComponent {
5053

5154
var aspectRatioState by remember { mutableStateOf(1f) }
5255
var controlsVisible by remember { mutableStateOf(true) }
56+
var volumeVisible by remember { mutableStateOf(true) }
57+
5358
val exoPlayer = remember {
5459
ExoPlayer.Builder(context).build().apply {
5560
prepare()
@@ -82,26 +87,45 @@ object ExoPlayerComposebles : KoinComponent {
8287
}
8388
}
8489

90+
LaunchedEffect(state.value.volume) {
91+
exoPlayer.volume = state.value.volume
92+
.also { volumeVisible = true }
93+
.also { Log.d(LOG_TAG, "set volume = $it") }
94+
}
95+
8596
LaunchedEffect(Unit) {
8697
while (true) {
8798
if (controlsVisible) {
88-
delay(3000L) // 3 seconds delay
99+
delay(HIDE_CONTROLS_TIMEOUT) // 3 seconds delay
89100
controlsVisible = false
90101
} else {
91102
delay(200L) // Short delay to keep checking
92103
}
93104
}
94105
}
95106

107+
LaunchedEffect(Unit) {
108+
while (true) {
109+
if (volumeVisible) {
110+
delay(HIDE_CONTROLS_TIMEOUT) // 3 seconds delay
111+
volumeVisible = false
112+
} else {
113+
delay(200L) // Short delay to keep checking
114+
}
115+
}
116+
}
117+
96118
DisposableEffect(lifecycleOwner, exoPlayer) {
97119
val lifecycleObserver = LifecycleEventObserver { _, event ->
98120
when (event) {
99121
Lifecycle.Event.ON_PAUSE ->
100122
view.dispatch(PlayPauseClicked(true))
123+
101124
Lifecycle.Event.ON_RESUME -> {
102125
// fixme not resuming properly stte needs to be updted but doesnt seem to .. caching?
103126
view.dispatch(PlayPauseClicked(exoPlayer.isPlaying))
104127
}
128+
105129
Lifecycle.Event.ON_DESTROY -> exoPlayer.release()
106130
else -> {}
107131
}
@@ -128,16 +152,22 @@ object ExoPlayerComposebles : KoinComponent {
128152
modifier = Modifier
129153
.align(Alignment.Center)
130154
.pointerInput(Unit) {
131-
detectTapGestures(onTap = { controlsVisible = !controlsVisible })
155+
detectTapGestures(onTap = {
156+
controlsVisible = !controlsVisible
157+
volumeVisible = !volumeVisible
158+
})
132159
},
133160
)
134161
if (controlsVisible) {
135-
PlayerComposeables.PlayerTransport(
162+
PlayerTransport(
136163
model = state.value,
137164
view = view,
138165
modifier = Modifier.align(Alignment.BottomCenter)
139166
)
140167
}
168+
if (volumeVisible) {
169+
VolumeDisplay(exoPlayer.volume, modifier = Modifier.Companion.align(Alignment.TopEnd))
170+
}
141171
}
142172
}
143173
}

app/src/main/java/uk/co/sentinelweb/cuer/app/util/remote/AppPlayerLaunchHost.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class AppPlayerLaunchHost(
1818
}
1919

2020
override fun launchVideo(item: PlaylistItemDomain, screenIndex: Int?) {
21+
// todo try to launch on second screen
2122
log.d("launchVideo: item = ${item.media.title}")
2223
ExoActivity.start(appContext, PlaylistAndItemDomain(item, null, null))
2324
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package uk.co.sentinelweb.cuer.app.util.wrapper
2+
3+
import android.app.Activity
4+
import androidx.core.view.WindowCompat
5+
import androidx.core.view.WindowInsetsCompat
6+
import androidx.core.view.WindowInsetsControllerCompat
7+
8+
// Hide the status bar
9+
class HideStatusBarWrapper() {
10+
11+
fun hide(a:Activity) {
12+
WindowCompat.setDecorFitsSystemWindows(a.window, false)
13+
val controller = WindowInsetsControllerCompat(a.window, a.window.decorView)
14+
controller.hide(WindowInsetsCompat.Type.statusBars())
15+
}
16+
}

shared/src/commonMain/composeResources/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
<string name="cast_control_floating_window">Floating window</string>
4646
<string name="cast_control_not_connected">Not Connected</string>
4747

48+
<!-- player -->
49+
<string name="player_volume">Volume: %1$s%</string>
50+
4851
<!-- misc -->
4952
<string name="up">Up</string>
5053
<string name="dismiss">Dismiss</string>

shared/src/commonMain/kotlin/uk/co/sentinelweb/cuer/app/ui/player/PlayerComposeables.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.compose.ui.graphics.Color
1010
import androidx.compose.ui.unit.dp
1111
import com.arkivanov.mvikotlin.core.view.BaseMviView
1212
import org.jetbrains.compose.resources.painterResource
13+
import org.jetbrains.compose.resources.stringResource
1314
import org.koin.core.component.KoinComponent
1415
import org.koin.core.component.inject
1516
import uk.co.sentinelweb.cuer.app.ui.common.compose.colorTransparentBlack
@@ -171,4 +172,19 @@ object PlayerComposeables : KoinComponent {
171172
)
172173
}
173174
}
175+
176+
@Composable
177+
fun VolumeDisplay(
178+
volume: Float, // 0..1
179+
modifier: Modifier,
180+
) {
181+
Row(modifier = modifier) {
182+
Text(
183+
stringResource(Res.string.player_volume, (volume * 100).toInt()),
184+
color = Color.White,
185+
style = MaterialTheme.typography.titleMedium,
186+
modifier = Modifier.padding(8.dp)
187+
)
188+
}
189+
}
174190
}

0 commit comments

Comments
 (0)