Skip to content

Commit

Permalink
[feature|optimize|build|doc] Support show buffer progress on player p…
Browse files Browse the repository at this point in the history
…rogress slider, optimize player slider experience; optimize Feed page experience; update actions/upload-artifact GitHub Actions version; update README
  • Loading branch information
SkyD666 committed May 25, 2024
1 parent 3efe7bb commit c266a1b
Show file tree
Hide file tree
Showing 15 changed files with 406 additions and 50 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/pre_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,39 +44,39 @@ jobs:
bash ./gradlew assembleGitHubRelease
# Upload apk (arm64-v8a)
- name: Upload Pre-Release Apk (arm64-v8a)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Pre-Release Apk (arm64-v8a)
path: app/build/outputs/apk/GitHub/release/*arm64-v8a*.apk
# Upload apk (armeabi-v7a)
- name: Upload Pre-Release Apk (armeabi-v7a)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Pre-Release Apk (armeabi-v7a)
path: app/build/outputs/apk/GitHub/release/*armeabi-v7a*.apk
# Upload apk (x86_64)
- name: Upload Pre-Release Apk (x86_64)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Pre-Release Apk (x86_64)
path: app/build/outputs/apk/GitHub/release/*x86_64*.apk
# Upload apk (x86)
- name: Upload Pre-Release Apk (x86)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Pre-Release Apk (x86)
path: |
app/build/outputs/apk/GitHub/release/*x86*.apk
!app/build/outputs/apk/GitHub/release/*x86_64*.apk
# Upload apk (universal)
- name: Upload Pre-Release Apk (universal)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Pre-Release Apk (universal)
path: app/build/outputs/apk/GitHub/release/*universal*.apk
# Upload mapping
- name: Upload Pre-Release Mapping
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Pre-Release Mapping
path: app/build/outputs/mapping/GitHubRelease/mapping.txt
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
## 🚧 Todo

1. Automatically **download new videos**
2. **Customize player settings**, such as default screen scale, surface type used by the player, and more
3. **Float** video playback **window**
4. **Automatically** play the **next video**

Expand Down Expand Up @@ -86,7 +85,7 @@ If you are interested, please help us **translate**, thank you.
- **Room**
- **Paging 3**
- **Hilt**
- Media3 **ExoPlayer**
- **MPV**
- **WorkManager**
- **DataStore**
- Splash Screen
Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ android {
minSdk = 24
targetSdk = 34
versionCode = 16
versionName = "1.1-beta33"
versionName = "1.1-beta34"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fun FeedScreen() {
}

val windowWidth = with(density) { currentWindowSize().width.toDp() }
val feedListWidth by remember(windowWidth) { mutableStateOf(windowWidth * 0.36f) }
val feedListWidth by remember(windowWidth) { mutableStateOf(windowWidth * 0.31f) }

ListDetailPaneScaffold(
modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/java/com/skyd/anivu/ui/mpv/MPVView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,22 @@ class MPVView(context: Context, attrs: AttributeSet?) : SurfaceView(context, att

private val scope = CoroutineScope(Dispatchers.IO)

@Volatile
private var initialized = false

fun initialize(
configDir: String,
cacheDir: String,
fontDir: String,
logLvl: String = "v",
vo: String = "gpu",
) {
if (initialized) return
synchronized(MPVView::class) {
if (initialized) return
initialized = true
}

MPVLib.create(this.context, logLvl)
MPVLib.setOptionString("config", "yes")
MPVLib.setOptionString("config-dir", configDir)
Expand Down Expand Up @@ -131,6 +140,7 @@ class MPVView(context: Context, attrs: AttributeSet?) : SurfaceView(context, att
Property("video-pan-x", MPV_FORMAT_DOUBLE),
Property("video-pan-y", MPV_FORMAT_DOUBLE),
Property("speed", MPV_FORMAT_DOUBLE),
Property("demuxer-cache-duration", MPV_FORMAT_DOUBLE),
Property("playlist-pos", MPV_FORMAT_INT64),
Property("playlist-count", MPV_FORMAT_INT64),
Property("video-format"),
Expand Down Expand Up @@ -315,6 +325,9 @@ class MPVView(context: Context, attrs: AttributeSet?) : SurfaceView(context, att
val videoAspect: Double?
get() = MPVLib.getPropertyDouble("video-params/aspect")

val demuxerCacheDuration: Double
get() = MPVLib.getPropertyDouble("demuxer-cache-duration") ?: 0.0

class TrackDelegate(private val name: String) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
val v = MPVLib.getPropertyString(name)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/com/skyd/anivu/ui/mpv/PlayerCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ sealed interface PlayerCommand {
data class SetAudioTrack(val trackId: Int) : PlayerCommand
data object Screenshot : PlayerCommand
data class AddSubtitle(val filePath: String) : PlayerCommand
data object GetBuffer : PlayerCommand
}
7 changes: 7 additions & 0 deletions app/src/main/java/com/skyd/anivu/ui/mpv/PlayerView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ private fun MPVView.solveCommand(
onVideoOffset: (Offset) -> Unit,
onSpeedChanged: (Float) -> Unit,
onSaveScreenshot: (File) -> Unit,
onCacheBufferStateChanged: (Float) -> Unit,
) {
when (command) {
is PlayerCommand.SetUri -> uri().resolveUri(context)?.let { loadFile(it) }
Expand Down Expand Up @@ -106,6 +107,8 @@ private fun MPVView.solveCommand(
addSubtitle(command.filePath)
onSubtitleTrack(subtitleTrack)
}

PlayerCommand.GetBuffer -> onCacheBufferStateChanged(demuxerCacheDuration.toFloat())
}
}

Expand Down Expand Up @@ -185,6 +188,7 @@ fun PlayerView(
"video-pan-y" -> commandQueue.trySend(PlayerCommand.GetVideoOffsetY)
"speed" -> commandQueue.trySend(PlayerCommand.GetSpeed)
"track-list" -> commandQueue.trySend(PlayerCommand.LoadAllTracks)
"demuxer-cache-duration" -> commandQueue.trySend(PlayerCommand.GetBuffer)
}
}

Expand Down Expand Up @@ -286,6 +290,9 @@ fun PlayerView(
},
onSpeedChanged = { playState = playState.copy(speed = it) },
onSaveScreenshot = onSaveScreenshot,
onCacheBufferStateChanged = {
playState = playState.copy(bufferDuration = it.toInt())
}
)
}
.collect()
Expand Down
50 changes: 16 additions & 34 deletions app/src/main/java/com/skyd/anivu/ui/mpv/controller/bar/BottomBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ClosedCaption
import androidx.compose.material.icons.rounded.MusicNote
Expand All @@ -44,10 +43,7 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.materialkolor.ktx.toColor
import com.materialkolor.ktx.toHct
import com.skyd.anivu.R
import com.skyd.anivu.ext.alwaysLight
import com.skyd.anivu.ui.mpv.controller.ControllerBarGray
import com.skyd.anivu.ui.mpv.controller.state.PlayState
import com.skyd.anivu.ui.mpv.controller.state.PlayStateCallback
Expand All @@ -68,7 +64,7 @@ fun BottomBar(
bottomBarCallback: BottomBarCallback,
onRestartAutoHideControllerRunnable: () -> Unit,
) {
val playPositionStateValue = playState()
val playStateValue = playState()

Column(
modifier = modifier
Expand All @@ -92,16 +88,16 @@ fun BottomBar(
) {
val sliderInteractionSource = remember { MutableInteractionSource() }
var sliderValue by rememberSaveable {
mutableFloatStateOf(playPositionStateValue.currentPosition.toFloat())
mutableFloatStateOf(playStateValue.currentPosition.toFloat())
}
var valueIsChanging by rememberSaveable { mutableStateOf(false) }
if (!valueIsChanging && !playPositionStateValue.isSeeking &&
sliderValue != playPositionStateValue.currentPosition.toFloat()
if (!valueIsChanging && !playStateValue.isSeeking &&
sliderValue != playStateValue.currentPosition.toFloat()
) {
sliderValue = playPositionStateValue.currentPosition.toFloat()
sliderValue = playStateValue.currentPosition.toFloat()
}
Text(
text = playPositionStateValue.currentPosition.toDurationString(),
text = playStateValue.currentPosition.toDurationString(),
style = MaterialTheme.typography.labelLarge,
color = Color.White,
)
Expand All @@ -120,40 +116,26 @@ fun BottomBar(
playStateCallback.onSeekTo(sliderValue.toInt())
valueIsChanging = false
},
valueRange = 0f..playPositionStateValue.duration.toFloat(),
colors = SliderDefaults.colors(),
interactionSource = sliderInteractionSource,
thumb = {
Box(
modifier = Modifier.fillMaxHeight(),
contentAlignment = Alignment.Center,
) {
Spacer(
modifier = Modifier
.padding(horizontal = 3.dp)
.clip(CircleShape)
.size(14.dp)
.background(
MaterialTheme.colorScheme.primary
.alwaysLight(true)
.toHct()
.withTone(90.0)
.toColor()
)
)
Thumb(interactionSource = sliderInteractionSource)
}
},
track = {
Spacer(
modifier = Modifier
.clip(RoundedCornerShape(6.dp))
.fillMaxWidth()
.height(3.dp)
.background(SliderDefaults.colors().activeTrackColor)
track = { sliderState ->
Track(
sliderState = sliderState,
bufferDurationValue = playStateValue.bufferDuration.toFloat()
)
},
valueRange = 0f..playStateValue.duration.toFloat(),
)
Text(
text = playPositionStateValue.duration.toDurationString(),
text = playStateValue.duration.toDurationString(),
style = MaterialTheme.typography.labelLarge,
color = Color.White,
)
Expand All @@ -170,8 +152,8 @@ fun BottomBar(
.size(50.dp)
.clickable(onClick = playStateCallback.onPlayStateChanged)
.padding(7.dp),
imageVector = if (playPositionStateValue.isPlaying) Icons.Rounded.Pause else Icons.Rounded.PlayArrow,
contentDescription = stringResource(if (playPositionStateValue.isPlaying) R.string.pause else R.string.play),
imageVector = if (playStateValue.isPlaying) Icons.Rounded.Pause else Icons.Rounded.PlayArrow,
contentDescription = stringResource(if (playStateValue.isPlaying) R.string.pause else R.string.play),
)

Spacer(modifier = Modifier.weight(1f))
Expand Down
62 changes: 62 additions & 0 deletions app/src/main/java/com/skyd/anivu/ui/mpv/controller/bar/Thumb.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.skyd.anivu.ui.mpv.controller.bar

import androidx.compose.foundation.background
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.DragInteraction
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.SliderColors
import androidx.compose.material3.SliderDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp


internal val ThumbSize = 14.dp

@Composable
fun Thumb(
interactionSource: MutableInteractionSource,
modifier: Modifier = Modifier,
colors: SliderColors = SliderDefaults.colors(),
enabled: Boolean = true,
thumbSize: DpSize = DpSize(ThumbSize, ThumbSize),
) {
val interactions = remember { mutableStateListOf<Interaction>() }
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect { interaction ->
when (interaction) {
is PressInteraction.Press -> interactions.add(interaction)
is PressInteraction.Release -> interactions.remove(interaction.press)
is PressInteraction.Cancel -> interactions.remove(interaction.press)
is DragInteraction.Start -> interactions.add(interaction)
is DragInteraction.Stop -> interactions.remove(interaction.start)
is DragInteraction.Cancel -> interactions.remove(interaction.start)
}
}
}

val size = if (interactions.isNotEmpty()) {
thumbSize.copy(width = thumbSize.width / 1.5f)
} else {
thumbSize
}
Spacer(
modifier
.size(size)
.hoverable(interactionSource = interactionSource)
.background(colors.thumbColor(enabled), CircleShape)
)
}

internal fun SliderColors.thumbColor(enabled: Boolean): Color =
if (enabled) thumbColor else disabledThumbColor
Loading

0 comments on commit c266a1b

Please sign in to comment.