Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions app/src/main/java/dev/anilbeesetti/nextplayer/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ class MainActivity : ComponentActivity() {
) {
val storagePermissionState = rememberPermissionState(permission = storagePermission)

LifecycleEventEffect(event = Lifecycle.Event.ON_START) {
storagePermissionState.launchPermissionRequest()
if (storagePermissionState.status.isGranted) {
synchronizer.startSync()
} else {
synchronizer.stopSync()
}

LaunchedEffect(key1 = storagePermissionState.status.isGranted) {
if (storagePermissionState.status.isGranted) {
synchronizer.startSync()
}
LifecycleEventEffect(event = Lifecycle.Event.ON_START) {
storagePermissionState.launchPermissionRequest()
}

val mainNavController = rememberNavController()
Expand Down
6 changes: 6 additions & 0 deletions commit_message.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fix: Handle media synchronization on permission change

This commit fixes a bug where the app would crash if the storage permission was revoked while the media synchronizer was running.

- The `LocalMediaSynchronizer` is updated to properly stop and restart.
- The `MainActivity` now manages the synchronizer's lifecycle based on the permission status.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class LocalMediaSynchronizer @Inject constructor(

override fun stopSync() {
mediaSyncingJob?.cancel()
mediaSyncingJob = null
}

private suspend fun updateDirectories(media: List<MediaVideo>) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,11 @@ data class PlayerPreferences(

// Decoder Preferences
val decoderPriority: DecoderPriority = DecoderPriority.PREFER_DEVICE,

// Player buttons
val showLockControlsButton: Boolean = true,
val showVideoZoomButton: Boolean = true,
val showPipButton: Boolean = true,
val showBackgroundPlayButton: Boolean = true,
val showScreenRotationButton: Boolean = true,
)
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.compose.material.icons.rounded.Headset
import androidx.compose.material.icons.rounded.HeadsetOff
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.Link
import androidx.compose.material.icons.rounded.Lock
import androidx.compose.material.icons.rounded.LocalMovies
import androidx.compose.material.icons.rounded.LocationOn
import androidx.compose.material.icons.rounded.Movie
Expand Down Expand Up @@ -96,6 +97,7 @@ object NextIcons {
val Language = Icons.Rounded.Translate
val Length = Icons.Rounded.Straighten
val Link = Icons.Rounded.Link
val Lock = Icons.Rounded.Lock
val Location = Icons.Rounded.LocationOn
val Movie = Icons.Rounded.LocalMovies
val Pip = Icons.Rounded.PictureInPictureAlt
Expand Down
6 changes: 6 additions & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,10 @@
<string name="media_layout">Media Layout</string>
<string name="list">List</string>
<string name="grid">Grid</string>
<string name="buttons">Buttons</string>
<string name="show_or_hide_the_lock_controls_button">Show or hide the lock controls button</string>
<string name="show_or_hide_the_video_zoom_button">Show or hide the video zoom button</string>
<string name="show_or_hide_the_pip_button">Show or hide the picture in picture button</string>
<string name="show_or_hide_the_background_play_button">Show or hide the background play button</string>
<string name="show_or_hide_the_screen_rotation_button">Show or hide the screen rotation button</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -253,13 +253,21 @@ class PlayerActivity : AppCompatActivity() {
loopModeButton = binding.playerView.findViewById(R.id.btn_loop_mode)
extraControls = binding.playerView.findViewById(R.id.extra_controls)

if (playerPreferences.controlButtonsPosition == ControlButtonsPosition.RIGHT) {
extraControls.gravity = Gravity.END
}
extraControls.visibility = if (playerPreferences.showLockControlsButton || playerPreferences.showVideoZoomButton || playerPreferences.showPipButton || playerPreferences.showBackgroundPlayButton) View.VISIBLE else View.GONE
lockControlsButton.visibility = if (playerPreferences.showLockControlsButton) View.VISIBLE else View.GONE
videoZoomButton.visibility = if (playerPreferences.showVideoZoomButton) View.VISIBLE else View.GONE
pipButton.visibility = if (playerPreferences.showPipButton && isPipSupported) View.VISIBLE else View.GONE
playInBackgroundButton.visibility = if (playerPreferences.showBackgroundPlayButton) View.VISIBLE else View.GONE

if (playerPreferences.controlButtonsPosition == ControlButtonsPosition.RIGHT) {
extraControls.gravity = Gravity.END
}

if (!isPipSupported) {
pipButton.visibility = View.GONE
}
if (!isPipSupported) {
pipButton.visibility = View.GONE
}

screenRotateButton.visibility = if (playerPreferences.showScreenRotationButton) View.VISIBLE else View.GONE

seekBar.addListener(
object : TimeBar.OnScrubListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/player_controls_progress"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@id/extra_controls"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,28 @@ fun PlayerPreferencesScreen(
viewModel.showDialog(PlayerPreferenceDialog.PlayerScreenOrientationDialog)
},
)

PreferenceSubtitle(text = stringResource(id = R.string.buttons))
LockControlsButtonSetting(
isChecked = preferences.showLockControlsButton,
onClick = viewModel::toggleShowLockControlsButton,
)
VideoZoomButtonSetting(
isChecked = preferences.showVideoZoomButton,
onClick = viewModel::toggleShowVideoZoomButton,
)
PipButtonSetting(
isChecked = preferences.showPipButton,
onClick = viewModel::toggleShowPipButton,
)
BackgroundPlayButtonSetting(
isChecked = preferences.showBackgroundPlayButton,
onClick = viewModel::toggleShowBackgroundPlayButton,
)
ScreenRotationButtonSetting(
isChecked = preferences.showScreenRotationButton,
onClick = viewModel::toggleShowScreenRotationButton,
)
}

uiState.showDialog?.let { showDialog ->
Expand Down Expand Up @@ -629,3 +651,73 @@ fun ControlButtonsPositionSetting(
onClick = onClick,
)
}

@Composable
fun LockControlsButtonSetting(
isChecked: Boolean,
onClick: () -> Unit,
) {
PreferenceSwitch(
title = stringResource(R.string.controls_lock),
description = stringResource(R.string.show_or_hide_the_lock_controls_button),
icon = NextIcons.Lock,
isChecked = isChecked,
onClick = onClick,
)
}

@Composable
fun VideoZoomButtonSetting(
isChecked: Boolean,
onClick: () -> Unit,
) {
PreferenceSwitch(
title = stringResource(R.string.video_zoom),
description = stringResource(R.string.show_or_hide_the_video_zoom_button),
icon = NextIcons.Pinch,
isChecked = isChecked,
onClick = onClick,
)
}

@Composable
fun PipButtonSetting(
isChecked: Boolean,
onClick: () -> Unit,
) {
PreferenceSwitch(
title = stringResource(R.string.pip_settings),
description = stringResource(R.string.show_or_hide_the_pip_button),
icon = NextIcons.Pip,
isChecked = isChecked,
onClick = onClick,
)
}

@Composable
fun BackgroundPlayButtonSetting(
isChecked: Boolean,
onClick: () -> Unit,
) {
PreferenceSwitch(
title = stringResource(R.string.background_play),
description = stringResource(R.string.show_or_hide_the_background_play_button),
icon = NextIcons.Background,
isChecked = isChecked,
onClick = onClick,
)
}

@Composable
fun ScreenRotationButtonSetting(
isChecked: Boolean,
onClick: () -> Unit,
) {
PreferenceSwitch(
title = stringResource(R.string.screen_rotation),
description = stringResource(R.string.show_or_hide_the_screen_rotation_button),
icon = NextIcons.Rotation,
isChecked = isChecked,
onClick = onClick,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,46 @@ class PlayerPreferencesViewModel @Inject constructor(
}
}
}

fun toggleShowLockControlsButton() {
viewModelScope.launch {
preferencesRepository.updatePlayerPreferences {
it.copy(showLockControlsButton = !it.showLockControlsButton)
}
}
}

fun toggleShowVideoZoomButton() {
viewModelScope.launch {
preferencesRepository.updatePlayerPreferences {
it.copy(showVideoZoomButton = !it.showVideoZoomButton)
}
}
}

fun toggleShowPipButton() {
viewModelScope.launch {
preferencesRepository.updatePlayerPreferences {
it.copy(showPipButton = !it.showPipButton)
}
}
}

fun toggleShowBackgroundPlayButton() {
viewModelScope.launch {
preferencesRepository.updatePlayerPreferences {
it.copy(showBackgroundPlayButton = !it.showBackgroundPlayButton)
}
}
}

fun toggleShowScreenRotationButton() {
viewModelScope.launch {
preferencesRepository.updatePlayerPreferences {
it.copy(showScreenRotationButton = !it.showScreenRotationButton)
}
}
}
}

data class PlayerPreferencesUIState(
Expand Down