Skip to content

Commit

Permalink
feat(player): add brightness manager
Browse files Browse the repository at this point in the history
An attempt to resolve issue #94
  • Loading branch information
rhenwinch committed Jul 5, 2024
1 parent 29a8d44 commit aa71b7c
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -287,18 +287,6 @@ abstract class BasePlayerViewModel(
_dialogState.update { SourceDataState.Idle }
}

fun updateVolume(strength: Float) {
_uiState.update {
it.copy(volume = strength)
}
}

fun updateScreenBrightness(strength: Float) {
_uiState.update {
it.copy(screenBrightness = strength)
}
}

fun onServerChange(index: Int? = null) {
val preferredQuality = appSettings.value.preferredQuality
val indexToUse = index ?: sourceData.cachedLinks.getIndexOfPreferredQuality(preferredQuality = preferredQuality)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,5 @@ data class PlayerUiState(
val selectedProvider: String? = null,
val selectedProviderState: PlayerProviderState = PlayerProviderState.SELECTED,
val selectedResizeMode: Int = 0,
val lastOpenedPanel: Int = 0,
val screenBrightness: Float = 1F,
val volume: Float = 0F
val lastOpenedPanel: Int = 0
)
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ import com.flixclusive.core.ui.player.util.updatePiPParams
import com.flixclusive.core.util.android.getActivity
import com.flixclusive.core.util.film.FilmType
import com.flixclusive.feature.mobile.player.controls.PlayerControls
import com.flixclusive.feature.mobile.player.util.BrightnessManager
import com.flixclusive.feature.mobile.player.util.LocalBrightnessManager
import com.flixclusive.feature.mobile.player.util.PlayerPipReceiver
import com.flixclusive.feature.mobile.player.util.getBrightness
import com.flixclusive.feature.mobile.player.util.percentOfVolume
import com.flixclusive.feature.mobile.player.util.setBrightness
import com.flixclusive.feature.mobile.player.util.VolumeManager
import com.flixclusive.model.provider.SourceData
import com.flixclusive.model.provider.SourceDataState
import com.flixclusive.model.tmdb.Film
Expand All @@ -78,7 +78,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.roundToInt
import kotlin.random.Random

interface PlayerScreenNavigator : GoBackAction {
Expand Down Expand Up @@ -116,7 +115,11 @@ fun PlayerScreen(
val isInPipMode by rememberPipMode()

val context = LocalContext.current.getActivity<ComponentActivity>()
val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager }
val brightnessManager = remember { BrightnessManager(context) }
val volumeManager = remember {
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
VolumeManager(audioManager)
}

val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val dialogState by viewModel.dialogState.collectAsStateWithLifecycle()
Expand Down Expand Up @@ -205,7 +208,10 @@ fun PlayerScreen(
}
}

CompositionLocalProvider(LocalPlayerManager provides viewModel.player) {
CompositionLocalProvider(
LocalPlayerManager provides viewModel.player,
LocalBrightnessManager provides brightnessManager,
) {
PlayerPipReceiver(
action = ACTION_PIP_CONTROL,
onReceive = { broadcastIntent ->
Expand Down Expand Up @@ -277,18 +283,14 @@ fun PlayerScreen(
context.toggleSystemBars(isVisible = false)

// Initialize brightness
val userDefaultBrightnessLevel = context.getBrightness()
viewModel.updateScreenBrightness(userDefaultBrightnessLevel)

// Initialize volume level
viewModel.updateVolume(context.percentOfVolume())
val userDefaultBrightnessLevel = brightnessManager.currentBrightness

onDispose {
// Lock the screen to landscape only if we're just changing
// episodes. This is really bad code bruh.
if (!isChangingEpisode) {
context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
context.setBrightness(userDefaultBrightnessLevel)
brightnessManager.setBrightness(userDefaultBrightnessLevel)
context.toggleSystemBars(isVisible = true)
}

Expand All @@ -297,29 +299,13 @@ fun PlayerScreen(
}

ListenKeyEvents { code, _ ->
val currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)

when (code) {
KeyEvent.KEYCODE_VOLUME_UP -> {
val newVolume = currentVolume + 1F

audioManager.setStreamVolume(
/* streamType = */ AudioManager.STREAM_MUSIC,
/* index = */ newVolume.roundToInt(),
/* flags = */ 0
)
viewModel.updateVolume((newVolume / maxVolume).coerceIn(0F, 1F))
volumeManager.increaseVolume()
true
}
KeyEvent.KEYCODE_VOLUME_DOWN -> {
val newVolume = currentVolume - 1F
audioManager.setStreamVolume(
/* streamType = */ AudioManager.STREAM_MUSIC,
/* index = */ newVolume.roundToInt(),
/* flags = */ 0
)
viewModel.updateVolume((newVolume / maxVolume).coerceIn(0F, 1F))
volumeManager.decreaseVolume()
true
}
else -> false
Expand Down Expand Up @@ -395,9 +381,8 @@ fun PlayerScreen(
resizeMode = uiState.selectedResizeMode,
onInitialize = {
viewModel.run {
val (currentPosition, _) = getSavedTimeForSourceData(
currentSelectedEpisode
)
val (currentPosition, _)
= getSavedTimeForSourceData(currentSelectedEpisode)

player.initialize()
sourceData.run {
Expand Down Expand Up @@ -470,18 +455,6 @@ fun PlayerScreen(
toggleVideoTimeReverse = viewModel::toggleVideoTimeReverse,
showControls = { showControls(it) },
toggleControlLock = { viewModel.areControlsLocked = it },
onBrightnessChange = {
context.setBrightness(it)
viewModel.updateScreenBrightness(it)
},
onVolumeChange = {
viewModel.player.run {
val newVolume = (it * 15).roundToInt()

setDeviceVolume(newVolume)
viewModel.updateVolume(it)
}
},
addSubtitle = { sourceData.cachedSubtitles.add(index = 0, element = it) },
onEpisodeClick = {
viewModel.run {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ import com.flixclusive.feature.mobile.player.controls.dialogs.settings.PlayerSet
import com.flixclusive.feature.mobile.player.controls.episodes.EpisodesScreen
import com.flixclusive.feature.mobile.player.controls.gestures.GestureDirection
import com.flixclusive.feature.mobile.player.controls.gestures.SeekerAndSliderGestures
import com.flixclusive.feature.mobile.player.util.rememberBrightnessManager
import com.flixclusive.model.database.WatchHistoryItem
import com.flixclusive.model.datastore.AppSettings
import com.flixclusive.model.provider.SourceLink
import com.flixclusive.model.provider.Subtitle
import com.flixclusive.model.tmdb.common.tv.Season
import com.flixclusive.model.tmdb.common.tv.Episode
import com.flixclusive.model.tmdb.common.tv.Season
import com.flixclusive.provider.ProviderApi
import com.flixclusive.core.ui.player.R as PlayerR
import com.flixclusive.core.util.R as UtilR
Expand All @@ -59,8 +60,6 @@ internal fun PlayerControls(
stateProvider: () -> PlayerUiState,
seasonDataProvider: () -> Resource<Season?>,
currentEpisodeSelected: Episode?,
onBrightnessChange: (Float) -> Unit,
onVolumeChange: (Float) -> Unit,
showControls: (Boolean) -> Unit,
toggleControlLock: (Boolean) -> Unit,
onBack: () -> Unit,
Expand All @@ -79,6 +78,8 @@ internal fun PlayerControls(
val isVisible by rememberUpdatedState(visibilityProvider())
val state by rememberUpdatedState(stateProvider())
val seasonData by rememberUpdatedState(seasonDataProvider())

val brightnessManager = rememberBrightnessManager()

val volumeIconId = remember(state.volume) {
when {
Expand Down Expand Up @@ -146,9 +147,10 @@ internal fun PlayerControls(
areControlsVisible = isVisible,
seekerIconId = PlayerR.drawable.round_keyboard_double_arrow_left_24,
seekAction = player::seekBack,
sliderValue = state.screenBrightness,
sliderValue = brightnessManager.currentBrightness,
sliderValueRange = 0F..brightnessManager.maxBrightness,
sliderIconId = R.drawable.round_wb_sunny_24,
slideAction = onBrightnessChange,
slideAction = brightnessManager::setBrightness,
showControls = showControls
)

Expand All @@ -162,8 +164,9 @@ internal fun PlayerControls(
seekerIconId = PlayerR.drawable.round_keyboard_double_arrow_right_24,
seekAction = player::seekForward,
sliderValue = state.volume,
sliderValueRange = 0F..1F,
sliderIconId = volumeIconId,
slideAction = onVolumeChange,
slideAction = {},
showControls = showControls
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ internal fun PlayerVerticalSlider(
@DrawableRes iconId: Int,
value: Float,
onValueChange: (Float) -> Unit,
valueRange: ClosedFloatingPointRange<Float>,
) {
val sliderColors = SliderDefaults.colors(
thumbColor = Color.White,
Expand Down Expand Up @@ -92,6 +93,7 @@ internal fun PlayerVerticalSlider(
}
}
.width(120.dp),
valueRange = valueRange,
value = value,
onValueChange = onValueChange,
colors = sliderColors,
Expand Down Expand Up @@ -129,7 +131,8 @@ private fun VerticalSliderPreview() {
isVisible = true,
iconId = sliderIconId,
value = value,
onValueChange = onValueChange
onValueChange = onValueChange,
valueRange = 0F..1F
)

PlayerVerticalSlider(
Expand All @@ -143,7 +146,8 @@ private fun VerticalSliderPreview() {
isVisible = true,
iconId = sliderIconId,
value = value,
onValueChange = onValueChange
onValueChange = onValueChange,
valueRange = 0F..1F
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ internal fun SeekerAndSliderGestures(
seekAction: () -> Unit,
slideAction: (Float) -> Unit,
showControls: (Boolean) -> Unit,
sliderValueRange: ClosedFloatingPointRange<Float> = 0F..1F,
) {
val playerManager by rememberLocalPlayerManager()

Expand Down Expand Up @@ -270,6 +271,7 @@ internal fun SeekerAndSliderGestures(
isVisible = isVisible || isSliderVisible,
iconId = sliderIconId,
value = sliderValue,
valueRange = sliderValueRange,
onValueChange = {
if (sliderVisibilityTimeout?.isActive == true) {
sliderVisibilityTimeout = sliderVisibilityTimeout!!.run {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.flixclusive.feature.mobile.player.util

import android.app.Activity
import android.view.WindowManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.rememberUpdatedState


internal val LocalBrightnessManager = compositionLocalOf<BrightnessManager> {
error("BrightnessManager not provided")
}

@Composable
internal fun rememberBrightnessManager()
= rememberUpdatedState(LocalBrightnessManager.current).value

internal class BrightnessManager(private val activity: Activity) {
var currentBrightness = activity.currentBrightness
val maxBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL

fun setBrightness(brightness: Float) {
currentBrightness = brightness.coerceIn(0F, maxBrightness)
val layoutParams = activity.window.attributes
layoutParams.screenBrightness = currentBrightness
activity.window.attributes = layoutParams
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Context
import android.media.AudioManager
import android.provider.Settings
import android.view.WindowManager

internal fun Context.percentOfVolume(
volume: Int? = null
Expand All @@ -16,56 +17,8 @@ internal fun Context.percentOfVolume(
return ((volume ?: currentVolume) / maxVolume.toFloat()).coerceIn(0F, 1F)
}

internal fun Activity.setBrightness(
strength: Float,
useTrueSystemBrightness: Boolean = false
) {
if (useTrueSystemBrightness) {
try {
Settings.System.putInt(
contentResolver,
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL
)

Settings.System.putInt(
contentResolver,
Settings.System.SCREEN_BRIGHTNESS, (strength * 255).toInt()
)
} catch (e: Exception) {
setBrightness(
strength = strength,
useTrueSystemBrightness = false
)
}
} else {
window?.apply {
attributes = attributes?.apply {
screenBrightness = strength
}
}
}

}

internal fun Activity.getBrightness(useTrueSystemBrightness: Boolean = true): Float {
return if (useTrueSystemBrightness) {
try {
Settings.System.getInt(
contentResolver,
Settings.System.SCREEN_BRIGHTNESS
) / 255F
} catch (e: Exception) {
// because true system brightness requires
// permission, this is a lazy way to check
// as it will throw an error if we do not have it
return getBrightness(false)
}
} else {
try {
window?.attributes?.screenBrightness ?: 0F
} catch (e: Exception) {
0F
}
}
}
internal val Activity.currentBrightness: Float
get() = when (val brightness = window.attributes.screenBrightness) {
in WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF..WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL -> brightness
else -> Settings.System.getFloat(contentResolver, Settings.System.SCREEN_BRIGHTNESS) / 255
}

0 comments on commit aa71b7c

Please sign in to comment.