Skip to content

Commit

Permalink
feat: playbackSpeed sheet
Browse files Browse the repository at this point in the history
* per video playback speed
* show number of items inside directories in file picker
  • Loading branch information
abdallahmehiz committed Aug 20, 2024
1 parent 3f43746 commit 6742c88
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 29 deletions.
9 changes: 8 additions & 1 deletion app/src/main/java/live/mehiz/mpvkt/database/Migrations.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

val Migrations: Array<Migration> = arrayOf(
MIGRATION1to2
MIGRATION1to2,
MIGRATION2to3,
)

private object MIGRATION1to2 : Migration(1, 2) {
Expand All @@ -15,3 +16,9 @@ private object MIGRATION1to2 : Migration(1, 2) {
db.execSQL("ALTER TABLE PlaybackStateEntity ADD COLUMN subSpeed REAL NOT NULL DEFAULT 0")
}
}

private object MIGRATION2to3 : Migration(2, 3) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE PlaybackStateEntity ADD COLUMN playbackSpeed REAL NOT NULL DEFAULT 0")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import androidx.room.RoomDatabase
import live.mehiz.mpvkt.database.dao.PlaybackStateDao
import live.mehiz.mpvkt.database.entities.PlaybackStateEntity

@Database(entities = [PlaybackStateEntity::class], version = 2)
@Database(entities = [PlaybackStateEntity::class], version = 3)
abstract class MpvKtDatabase : RoomDatabase() {
abstract fun videoDataDao(): PlaybackStateDao
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.room.PrimaryKey
data class PlaybackStateEntity(
@PrimaryKey val mediaTitle: String,
val lastPosition: Int, // in seconds
val playbackSpeed: Double,
val sid: Int,
val subDelay: Int,
val subSpeed: Double,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import live.mehiz.mpvkt.ui.theme.spacing

@Composable
fun SliderItem(
Expand Down Expand Up @@ -78,8 +79,8 @@ fun SliderItem(
valueText: String,
onChange: (Float) -> Unit,
max: Float,
steps: Int,
modifier: Modifier = Modifier,
steps: Int = 0,
min: Float = 0f,
icon: @Composable () -> Unit = {},
) {
Expand All @@ -89,11 +90,11 @@ fun SliderItem(
modifier = modifier
.fillMaxWidth()
.padding(
horizontal = 16.dp,
vertical = 8.dp,
horizontal = MaterialTheme.spacing.medium,
vertical = MaterialTheme.spacing.smaller,
),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(24.dp),
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.large),
) {
icon()
Column(modifier = Modifier.weight(0.5f)) {
Expand Down Expand Up @@ -137,10 +138,10 @@ fun VerticalSliderItem(
modifier = modifier
.fillMaxHeight()
.padding(
horizontal = 16.dp,
vertical = 8.dp,
horizontal = MaterialTheme.spacing.medium,
vertical = MaterialTheme.spacing.smaller,
),
verticalArrangement = Arrangement.spacedBy(24.dp),
verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.larger),
horizontalAlignment = Alignment.CenterHorizontally,
) {
icon()
Expand Down
16 changes: 12 additions & 4 deletions app/src/main/java/live/mehiz/mpvkt/ui/home/FilePickerScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ data class FilePickerScreen(val uri: String) : Screen() {
MaterialTheme.colorScheme.surfaceContainerHigh
},
),
items = if(fileManager.isDirectory(file)) fileManager.listFiles(file).size else null,
items = if (fileManager.isDirectory(file)) fileManager.listFiles(file).size else null,
onClick = { onNavigate(file) },
)
}
Expand All @@ -142,9 +142,9 @@ data class FilePickerScreen(val uri: String) : Screen() {
isDirectory: Boolean,
lastModified: Long?,
length: Long?,
items: Int? = null,
onClick: () -> Unit,
modifier: Modifier = Modifier,
items: Int? = null,
) {
var size: String? by remember { mutableStateOf(null) }
var time: String? by remember { mutableStateOf(null) }
Expand Down Expand Up @@ -187,9 +187,17 @@ data class FilePickerScreen(val uri: String) : Screen() {
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium,
)
if ((size != null && !isDirectory) || (items != null && isDirectory)) {
if (size != null || items != null) {
Text(
text = if(isDirectory) pluralStringResource(id = R.plurals.plural_items, count = items!!, items) else size!!,
text = if (isDirectory) {
pluralStringResource(
id = R.plurals.plural_items,
count = items!!,
items
)
} else {
size!!
},
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium,
)
Expand Down
18 changes: 9 additions & 9 deletions app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,8 @@ class PlayerActivity : AppCompatActivity() {
internal fun onObserverEvent(property: String, value: Long) {
when (property) {
"time-pos" -> viewModel.updatePlayBackPos(value.toFloat())
"duration" -> viewModel.duration.update { value.toFloat() }
"demuxer-cache-time" -> viewModel.updateReadAhead(value = value)
"duration" -> viewModel.duration.update { value.toFloat() }
}
}

Expand Down Expand Up @@ -440,8 +440,10 @@ class PlayerActivity : AppCompatActivity() {
}
}

@Suppress("EmptyFunctionBlock", "UnusedParameter")
internal fun onObserverEvent(property: String, value: String) {
when (property) {
"speed" -> viewModel.playbackSpeed.update { value.toFloat() }
}
}

internal fun event(eventId: Int) {
Expand All @@ -450,11 +452,7 @@ class PlayerActivity : AppCompatActivity() {
getFileName(intent)?.let { fileName = it }
viewModel.mediaTitle.update {
val mediaTitle = MPVLib.getPropertyString("media-title")
if (mediaTitle.isBlank() || mediaTitle.isDigitsOnly()) {
fileName
} else {
mediaTitle
}
if (mediaTitle.isBlank() || mediaTitle.isDigitsOnly()) fileName else mediaTitle
}
CoroutineScope(Dispatchers.IO).launch {
loadVideoPlaybackState(fileName)
Expand Down Expand Up @@ -482,8 +480,9 @@ class PlayerActivity : AppCompatActivity() {
if (!::fileName.isInitialized) return
mpvKtDatabase.videoDataDao().upsert(
PlaybackStateEntity(
fileName,
if (playerPreferences.savePositionOnQuit.get()) player.timePos ?: 0 else 0,
mediaTitle = fileName,
lastPosition = if (playerPreferences.savePositionOnQuit.get()) player.timePos ?: 0 else 0,
playbackSpeed = player.playbackSpeed ?: playerPreferences.defaultSpeed.get().toDouble(),
sid = player.sid,
subDelay = (MPVLib.getPropertyDouble("sub-delay") * 1000).toInt(),
subSpeed = MPVLib.getPropertyDouble("sub-speed"),
Expand All @@ -509,6 +508,7 @@ class PlayerActivity : AppCompatActivity() {
player.aid = it.aid
player.subDelay = subDelay
player.secondarySubDelay = secondarySubDelay
player.playbackSpeed = it.playbackSpeed
MPVLib.setPropertyDouble("audio-delay", audioDelay)
}
player.timePos = if (playerPreferences.savePositionOnQuit.get()) state?.lastPosition ?: 0 else 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum class Debanding {

enum class Sheets {
None,
PlaybackSpeed,
SubtitleTracks,
AudioTracks,
Chapters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class PlayerViewModel(
val mediaTitle = MutableStateFlow("")

val isLoading = MutableStateFlow(true)
val playbackSpeed = MutableStateFlow(0f)

private val _subtitleTracks = MutableStateFlow<List<Track>>(emptyList())
val subtitleTracks = _subtitleTracks.asStateFlow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import `is`.xyz.mpv.MPVLib
import kotlinx.coroutines.flow.update
import live.mehiz.mpvkt.R
import live.mehiz.mpvkt.preferences.PlayerPreferences
import live.mehiz.mpvkt.preferences.preference.collectAsState
import live.mehiz.mpvkt.ui.player.PlayerViewModel
import live.mehiz.mpvkt.ui.player.Sheets
import live.mehiz.mpvkt.ui.player.controls.components.ControlsButton
Expand All @@ -42,14 +41,16 @@ fun BottomLeftPlayerControls(modifier: Modifier = Modifier) {
icon = Icons.Default.ScreenRotation,
onClick = { viewModel.cycleScreenRotations() }
)
val defaultSpeed by playerPreferences.defaultSpeed.collectAsState()
val currentSpeed by viewModel.playbackSpeed.collectAsState()
ControlsButton(
text = stringResource(R.string.player_speed, defaultSpeed),
text = stringResource(R.string.player_speed, currentSpeed),
onClick = {
val newSpeed = if (defaultSpeed >= 2) 0.25f else defaultSpeed + 0.25f
val newSpeed = if (currentSpeed >= 2) 0.25f else currentSpeed + 0.25f
viewModel.playbackSpeed.update { newSpeed }
MPVLib.setPropertyDouble("speed", newSpeed.toDouble())
playerPreferences.defaultSpeed.set(newSpeed)
}
},
onLongClick = { viewModel.sheetShown.update { Sheets.PlaybackSpeed } }
)
AnimatedVisibility(
currentChapter != null && playerPreferences.currentChaptersIndicator.get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import live.mehiz.mpvkt.ui.player.controls.components.sheets.AudioTracksSheet
import live.mehiz.mpvkt.ui.player.controls.components.sheets.ChaptersSheet
import live.mehiz.mpvkt.ui.player.controls.components.sheets.DecodersSheet
import live.mehiz.mpvkt.ui.player.controls.components.sheets.MoreSheet
import live.mehiz.mpvkt.ui.player.controls.components.sheets.PlaybackSpeedSheet
import live.mehiz.mpvkt.ui.player.controls.components.sheets.SubtitlesSheet
import org.koin.compose.koinInject

Expand Down Expand Up @@ -107,5 +108,9 @@ fun PlayerSheets() {
}
)
}

Sheets.PlaybackSpeed -> {
PlaybackSpeedSheet(onDismissRequest = onDismissRequest)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,27 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import `is`.xyz.mpv.MPVView
import `is`.xyz.mpv.Utils
import kotlinx.collections.immutable.ImmutableList
import live.mehiz.mpvkt.R
import live.mehiz.mpvkt.ui.theme.spacing

@Composable
fun ChaptersSheet(
chapters: ImmutableList<MPVView.Chapter>,
currentChapter: Int,
onClick: (Int) -> Unit,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
) {
GenericTracksSheet(
chapters,
Expand All @@ -37,6 +39,8 @@ fun ChaptersSheet(
)
},
onDismissRequest = onDismissRequest,
modifier = modifier
.padding(vertical = MaterialTheme.spacing.medium)
)
}

Expand All @@ -53,7 +57,7 @@ fun ChapterTrack(
modifier = modifier
.fillMaxWidth()
.clickable(onClick = onClick)
.padding(vertical = 8.dp, horizontal = 16.dp),
.padding(vertical = MaterialTheme.spacing.smaller, horizontal = MaterialTheme.spacing.medium),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package live.mehiz.mpvkt.ui.player.controls.components.sheets

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.RestartAlt
import androidx.compose.material3.Button
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import `is`.xyz.mpv.MPVLib
import kotlinx.coroutines.flow.update
import live.mehiz.mpvkt.R
import live.mehiz.mpvkt.preferences.AudioPreferences
import live.mehiz.mpvkt.preferences.PlayerPreferences
import live.mehiz.mpvkt.preferences.preference.collectAsState
import live.mehiz.mpvkt.presentation.components.PlayerSheet
import live.mehiz.mpvkt.presentation.components.SliderItem
import live.mehiz.mpvkt.ui.player.PlayerViewModel
import live.mehiz.mpvkt.ui.theme.spacing
import me.zhanghai.compose.preference.ProvidePreferenceLocals
import me.zhanghai.compose.preference.SwitchPreference
import org.koin.compose.koinInject

@Composable
fun PlaybackSpeedSheet(
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
) {
val preferences = koinInject<PlayerPreferences>()
val viewModel = koinInject<PlayerViewModel>()
val currentSpeed by viewModel.playbackSpeed.collectAsState()
PlayerSheet(onDismissRequest = onDismissRequest) {
Column(
modifier.padding(MaterialTheme.spacing.medium),
) {
SliderItem(
label = stringResource(id = R.string.player_sheets_speed_slider_label),
value = currentSpeed,
valueText = stringResource(id = R.string.player_speed, currentSpeed),
onChange = { newSpeed ->
viewModel.playbackSpeed.update { newSpeed }
MPVLib.setPropertyDouble("speed", newSpeed.toDouble())
},
max = 6f,
min = 0.01f,
)
ProvidePreferenceLocals {
val audioPreferences = koinInject<AudioPreferences>()
val pitchCorrection by audioPreferences.audioPitchCorrection.collectAsState()
SwitchPreference(
value = pitchCorrection,
onValueChange = { audioPreferences.audioPitchCorrection.set(it) },
title = { Text(text = stringResource(id = R.string.pref_audio_pitch_correction_title)) },
summary = { Text(text = stringResource(id = R.string.pref_audio_pitch_correction_summary)) },
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.smaller),
) {
Button(
modifier = Modifier.weight(1f),
onClick = {
preferences.defaultSpeed.set(currentSpeed)
},
) {
Text(text = stringResource(id = R.string.player_sheets_speed_make_default))
}
FilledIconButton(
onClick = {
preferences.defaultSpeed.delete()
viewModel.playbackSpeed.update { 1f }
MPVLib.setPropertyDouble("speed", 1.0)
},
) {
Icon(imageVector = Icons.Default.RestartAlt, contentDescription = null)
}
}
}
}
}
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@
<string name="player_sheets_filters_hue">Hue</string>
<string name="player_sheets_filters_warning">Some filters may not work on your current video driver</string>

<string name="player_sheets_speed_slider_label">Speed</string>
<string name="player_sheets_speed_make_default">Make default speed</string>

<string name="numeric_chooser_value_too_big">Value too big</string>
<string name="numeric_chooser_value_too_small">Value too small</string>

Expand Down

0 comments on commit 6742c88

Please sign in to comment.