Skip to content

Commit

Permalink
feat(player): Show the current chapter in player controls ui (#1363)
Browse files Browse the repository at this point in the history
Co-authored-by: jmir1 <[email protected]>
  • Loading branch information
abdallahmehiz and jmir1 authored Jan 30, 2024
1 parent 16361e5 commit 4295669
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ class PlayerActivity : BaseActivity() {
field = value
runOnUiThread {
playerControls.seekbar.updateSeekbar(chapters = value)
playerControls.chapterText.updateCurrentChapterText(chapters = value)
}
}

Expand Down Expand Up @@ -1766,7 +1767,6 @@ class PlayerActivity : BaseActivity() {
emptyList()
}
val combinedChapters = (startChapter + playerChapters + filteredAniskipChapters).sortedBy { it.time }
runOnUiThread { binding.playerControls.binding.chaptersBtn.isVisible = combinedChapters.isNotEmpty() }
videoChapters = combinedChapters
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,17 @@ fun VideoChaptersSheet(
fontSize = 20.sp,
)

videoChapters.forEachIndexed { index, videoChapter ->
val currentChapter = videoChapters.last { it.time <= currentTimePosition }

videoChapters.forEach { videoChapter ->
val videoChapterTime = videoChapter.time.roundToInt()
val videoChapterName = if (videoChapter.title.isNullOrBlank()) {
Utils.prettyTime(videoChapterTime)
} else {
"${videoChapter.title} (${Utils.prettyTime(videoChapterTime)})"
}

val nextChapterTime = videoChapters.getOrNull(index + 1)?.time?.toInt()

val selected = (index == videoChapters.lastIndex && currentTimePosition >= videoChapterTime) ||
(
currentTimePosition >= videoChapterTime &&
(
nextChapterTime == null ||
currentTimePosition < nextChapterTime
)
)
val selected = videoChapter == currentChapter

val onClick = {
currentTimePosition = videoChapter.time.roundToInt()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.core.view.isVisible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.PlayerControlsBinding
import eu.kanade.tachiyomi.ui.player.PlayerActivity
import eu.kanade.tachiyomi.ui.player.viewer.components.CurrentChapter
import eu.kanade.tachiyomi.ui.player.viewer.components.Seekbar
import `is`.xyz.mpv.MPVLib
import `is`.xyz.mpv.Utils
Expand Down Expand Up @@ -44,6 +45,11 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
onValueChangeFinished = ::onValueChangeFinished,
)

val chapterText: CurrentChapter = CurrentChapter(
view = binding.currentChapter,
onClick = { activity.viewModel.showVideoChapters() },
)

private fun onValueChange(value: Float, wasSeeking: Boolean) {
if (!wasSeeking) {
SeekState.mode = SeekState.SEEKBAR
Expand Down Expand Up @@ -146,8 +152,6 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr

binding.streamsBtn.setOnClickListener { activity.viewModel.showStreamsCatalog() }

binding.chaptersBtn.setOnClickListener { activity.viewModel.showVideoChapters() }

binding.titleMainTxt.setOnClickListener { activity.viewModel.showEpisodeList() }

binding.titleSecondaryTxt.setOnClickListener { activity.viewModel.showEpisodeList() }
Expand Down Expand Up @@ -319,6 +323,7 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
activity.viewModel.onSecondReached(position, duration)
}
seekbar.updateSeekbar(value = position.toFloat())
chapterText.updateCurrentChapterText(value = position.toFloat())
}

@SuppressLint("SetTextI18n")
Expand Down Expand Up @@ -371,6 +376,9 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
binding.bottomLeftControlsGroup.startAnimation(
AnimationUtils.loadAnimation(context, R.anim.player_exit_left),
)
binding.currentChapter.startAnimation(
AnimationUtils.loadAnimation(context, R.anim.player_exit_left),
)
binding.middleControlsGroup.startAnimation(
AnimationUtils.loadAnimation(context, R.anim.player_fade_out),
)
Expand Down Expand Up @@ -399,6 +407,9 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
binding.bottomLeftControlsGroup.startAnimation(
AnimationUtils.loadAnimation(context, R.anim.player_enter_left),
)
binding.currentChapter.startAnimation(
AnimationUtils.loadAnimation(context, R.anim.player_enter_left),
)
binding.middleControlsGroup.startAnimation(
AnimationUtils.loadAnimation(context, R.anim.player_fade_in),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package eu.kanade.tachiyomi.ui.player.viewer.components

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.view.setComposeContent
import `is`.xyz.mpv.MPVView.Chapter
import `is`.xyz.mpv.Utils
import tachiyomi.presentation.core.components.material.padding

class CurrentChapter(
private val view: ComposeView,
private val onClick: () -> Unit,
) {
private var value: Float = 0F
private var chapters: List<Chapter> = listOf()

fun updateCurrentChapterText(
value: Float? = null,
chapters: List<Chapter>? = null,
) {
if (value != null) {
this.value = value
}
if (chapters != null) {
this.chapters = chapters
}
if (this.chapters.isEmpty()) {
return
}
val chapter = this.chapters.last { it.time <= (value ?: 0F) }
view.setComposeContent {
CurrentChapterComposable(
chapter = chapter,
modifier = Modifier
.clickable { onClick() }
.padding(end = MaterialTheme.padding.large)
.wrapContentSize(Alignment.CenterStart),
)
}
}

@Composable
private fun CurrentChapterComposable(
chapter: Chapter,
modifier: Modifier = Modifier,
) {
Box(
modifier = modifier
.clip(RoundedCornerShape(25))
.background(MaterialTheme.colorScheme.background.copy(alpha = 0.6F))
.padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small),
) {
AnimatedContent(
targetState = chapter,
transitionSpec = {
if (targetState.time > initialState.time) {
(slideInVertically { height -> height } + fadeIn())
.togetherWith(slideOutVertically { height -> -height } + fadeOut())
} else {
(slideInVertically { height -> -height } + fadeIn())
.togetherWith(slideOutVertically { height -> height } + fadeOut())
}.using(
SizeTransform(clip = false),
)
},
label = "Chapter",
) { currentChapter ->
Row {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_video_chapter_20dp),
contentDescription = null,
modifier = Modifier
.padding(end = MaterialTheme.padding.small)
.size(16.dp),
)
Text(
text = Utils.prettyTime(currentChapter.time.toInt()),
textAlign = TextAlign.Center,
fontWeight = FontWeight.ExtraBold,
maxLines = 1,
overflow = TextOverflow.Clip,
color = MaterialTheme.colorScheme.tertiary,
)
currentChapter.title?.let {
Text(
text = "",
textAlign = TextAlign.Center,
maxLines = 1,
overflow = TextOverflow.Clip,
)
Text(
text = it,
textAlign = TextAlign.Center,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onBackground,
)
}
}
}
}
}
}
30 changes: 13 additions & 17 deletions app/src/main/res/layout/player_controls.xml
Original file line number Diff line number Diff line change
Expand Up @@ -129,32 +129,19 @@
android:background="?attr/selectableItemBackground"
android:contentDescription="Tracks"
android:src="@drawable/ic_video_settings_20dp"
app:layout_constraintLeft_toRightOf="@id/chaptersBtn"
app:layout_constraintLeft_toRightOf="@id/toggleAutoplay"
app:layout_constraintRight_toLeftOf="@id/settingsBtn"
app:layout_constraintTop_toTopOf="@id/settingsBtn"
app:tint="?attr/colorOnPrimarySurface" />

<ImageButton
android:id="@+id/chaptersBtn"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="Settings"
android:src="@drawable/ic_video_chapter_20dp"
android:visibility="gone"
app:layout_constraintLeft_toRightOf="@id/toggleAutoplay"
app:layout_constraintRight_toLeftOf="@id/streamsBtn"
app:layout_constraintTop_toTopOf="@id/streamsBtn"
app:tint="?attr/colorOnPrimarySurface" />

<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/toggleAutoplay"
android:layout_width="50dp"
android:layout_height="50dp"
tools:checked="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/chaptersBtn"
app:layout_constraintTop_toTopOf="@id/chaptersBtn" />
app:layout_constraintRight_toLeftOf="@id/streamsBtn"
app:layout_constraintTop_toTopOf="@id/streamsBtn" />

<!-- Audio -->

Expand Down Expand Up @@ -263,6 +250,16 @@
android:layoutDirection="ltr"
android:visibility="visible">

<androidx.compose.ui.platform.ComposeView
android:id="@+id/currentChapter"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:layout_weight="80"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottomRightControlsGroup"
app:layout_constraintStart_toEndOf="@+id/bottomLeftControlsGroup" />

<LinearLayout
android:id="@+id/bottomLeftControlsGroup"
android:layout_width="wrap_content"
Expand Down Expand Up @@ -390,7 +387,6 @@
</RelativeLayout>



<!-- Extra Controls -->

<LinearLayout
Expand Down

0 comments on commit 4295669

Please sign in to comment.