feat: lock player controls (#372)
* feat: lock player controls Add Lock Player feature. This feature is similar to the feature found in the stock Jellyfin Android app and in the VLC app. When enabled, it disables the gestures (seek, volume and brightness control), disables the default player controls and leaves only two buttons: a back button and an "unlock" button. Pressing the unlock button reverts the player back to the initial state, e.g. gestures enabled and default buttons shown. Works with ExoPlayer and MPV Player. Let me know of any issues. * Update PlayerGestureHelper.kt * Fixed spacing issues * fixed bug + formatting * Simplified code * Fixed spacing * fixed trailing line? * refactor: set locked layout initial visibility in xml --------- Co-authored-by: jarnedemeulemeester <jarnedemeulemeester@gmail.com>
This commit is contained in:
parent
12b819bc7a
commit
a886baf907
7 changed files with 399 additions and 226 deletions
|
@ -1,11 +1,13 @@
|
||||||
package dev.jdtech.jellyfin
|
package dev.jdtech.jellyfin
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
@ -29,6 +31,8 @@ import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
var isControlsLocked: Boolean = false
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PlayerActivity : BasePlayerActivity() {
|
class PlayerActivity : BasePlayerActivity() {
|
||||||
|
|
||||||
|
@ -67,6 +71,11 @@ class PlayerActivity : BasePlayerActivity() {
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.playerView.findViewById<View>(R.id.back_button_alt).setOnClickListener {
|
||||||
|
finish()
|
||||||
|
isControlsLocked = false
|
||||||
|
}
|
||||||
|
|
||||||
val videoNameTextView = binding.playerView.findViewById<TextView>(R.id.video_name)
|
val videoNameTextView = binding.playerView.findViewById<TextView>(R.id.video_name)
|
||||||
|
|
||||||
viewModel.currentItemTitle.observe(this) { title ->
|
viewModel.currentItemTitle.observe(this) { title ->
|
||||||
|
@ -77,10 +86,15 @@ class PlayerActivity : BasePlayerActivity() {
|
||||||
val subtitleButton = binding.playerView.findViewById<ImageButton>(R.id.btn_subtitle)
|
val subtitleButton = binding.playerView.findViewById<ImageButton>(R.id.btn_subtitle)
|
||||||
val speedButton = binding.playerView.findViewById<ImageButton>(R.id.btn_speed)
|
val speedButton = binding.playerView.findViewById<ImageButton>(R.id.btn_speed)
|
||||||
val skipIntroButton = binding.playerView.findViewById<Button>(R.id.btn_skip_intro)
|
val skipIntroButton = binding.playerView.findViewById<Button>(R.id.btn_skip_intro)
|
||||||
|
val lockButton = binding.playerView.findViewById<ImageButton>(R.id.btn_lockview)
|
||||||
|
val unlockButton = binding.playerView.findViewById<ImageButton>(R.id.btn_unlock)
|
||||||
|
|
||||||
audioButton.isEnabled = false
|
audioButton.isEnabled = false
|
||||||
audioButton.imageAlpha = 75
|
audioButton.imageAlpha = 75
|
||||||
|
|
||||||
|
lockButton.isEnabled = false
|
||||||
|
lockButton.imageAlpha = 75
|
||||||
|
|
||||||
subtitleButton.isEnabled = false
|
subtitleButton.isEnabled = false
|
||||||
subtitleButton.imageAlpha = 75
|
subtitleButton.imageAlpha = 75
|
||||||
|
|
||||||
|
@ -120,6 +134,23 @@ class PlayerActivity : BasePlayerActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val exoPlayerControlView = findViewById<FrameLayout>(R.id.player_controls)
|
||||||
|
val lockedLayout = findViewById<FrameLayout>(R.id.locked_player_view)
|
||||||
|
|
||||||
|
lockButton.setOnClickListener {
|
||||||
|
exoPlayerControlView.visibility = View.GONE
|
||||||
|
lockedLayout.visibility = View.VISIBLE
|
||||||
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||||
|
isControlsLocked = true
|
||||||
|
}
|
||||||
|
|
||||||
|
unlockButton.setOnClickListener {
|
||||||
|
exoPlayerControlView.visibility = View.VISIBLE
|
||||||
|
lockedLayout.visibility = View.GONE
|
||||||
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||||
|
isControlsLocked = false
|
||||||
|
}
|
||||||
|
|
||||||
subtitleButton.setOnClickListener {
|
subtitleButton.setOnClickListener {
|
||||||
when (viewModel.player) {
|
when (viewModel.player) {
|
||||||
is MPVPlayer -> {
|
is MPVPlayer -> {
|
||||||
|
@ -189,6 +220,8 @@ class PlayerActivity : BasePlayerActivity() {
|
||||||
if (it) {
|
if (it) {
|
||||||
audioButton.isEnabled = true
|
audioButton.isEnabled = true
|
||||||
audioButton.imageAlpha = 255
|
audioButton.imageAlpha = 255
|
||||||
|
lockButton.isEnabled = true
|
||||||
|
lockButton.imageAlpha = 255
|
||||||
subtitleButton.isEnabled = true
|
subtitleButton.isEnabled = true
|
||||||
subtitleButton.imageAlpha = 255
|
subtitleButton.imageAlpha = 255
|
||||||
speedButton.isEnabled = true
|
speedButton.isEnabled = true
|
||||||
|
|
|
@ -18,6 +18,7 @@ import androidx.media3.ui.PlayerView
|
||||||
import dev.jdtech.jellyfin.AppPreferences
|
import dev.jdtech.jellyfin.AppPreferences
|
||||||
import dev.jdtech.jellyfin.Constants
|
import dev.jdtech.jellyfin.Constants
|
||||||
import dev.jdtech.jellyfin.PlayerActivity
|
import dev.jdtech.jellyfin.PlayerActivity
|
||||||
|
import dev.jdtech.jellyfin.isControlsLocked
|
||||||
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -65,6 +66,8 @@ class PlayerGestureHelper(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||||
|
// Disables double tap gestures if view is locked
|
||||||
|
if (isControlsLocked) return false
|
||||||
val viewCenterX = playerView.measuredWidth / 2
|
val viewCenterX = playerView.measuredWidth / 2
|
||||||
val currentPos = playerView.player?.currentPosition ?: 0
|
val currentPos = playerView.player?.currentPosition ?: 0
|
||||||
|
|
||||||
|
@ -90,6 +93,8 @@ class PlayerGestureHelper(
|
||||||
): Boolean {
|
): Boolean {
|
||||||
// Excludes area where app gestures conflicting with system gestures
|
// Excludes area where app gestures conflicting with system gestures
|
||||||
if (inExclusionArea(firstEvent)) return false
|
if (inExclusionArea(firstEvent)) return false
|
||||||
|
// Disables seek gestures if view is locked
|
||||||
|
if (isControlsLocked) return false
|
||||||
|
|
||||||
// Check whether swipe was oriented vertically
|
// Check whether swipe was oriented vertically
|
||||||
if (abs(distanceY / distanceX) < 2) {
|
if (abs(distanceY / distanceX) < 2) {
|
||||||
|
@ -128,6 +133,8 @@ class PlayerGestureHelper(
|
||||||
): Boolean {
|
): Boolean {
|
||||||
// Excludes area where app gestures conflicting with system gestures
|
// Excludes area where app gestures conflicting with system gestures
|
||||||
if (inExclusionArea(firstEvent)) return false
|
if (inExclusionArea(firstEvent)) return false
|
||||||
|
// Disables volume gestures when player is locked
|
||||||
|
if (isControlsLocked) return false
|
||||||
|
|
||||||
if (abs(distanceY / distanceX) < 2) return false
|
if (abs(distanceY / distanceX) < 2) return false
|
||||||
|
|
||||||
|
@ -213,6 +220,8 @@ class PlayerGestureHelper(
|
||||||
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean = true
|
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean = true
|
||||||
|
|
||||||
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
||||||
|
// Disables zoom gesture if view is locked
|
||||||
|
if (isControlsLocked) return false
|
||||||
lastScaleEvent = SystemClock.elapsedRealtime()
|
lastScaleEvent = SystemClock.elapsedRealtime()
|
||||||
val scaleFactor = detector.scaleFactor
|
val scaleFactor = detector.scaleFactor
|
||||||
if (abs(scaleFactor - Constants.ZOOM_SCALE_BASE) > Constants.ZOOM_SCALE_THRESHOLD) {
|
if (abs(scaleFactor - Constants.ZOOM_SCALE_BASE) > Constants.ZOOM_SCALE_THRESHOLD) {
|
||||||
|
|
64
app/phone/src/main/res/layout/exo_locked_controls.xml
Normal file
64
app/phone/src/main/res/layout/exo_locked_controls.xml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/locked_player_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="38dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/extra_buttons_alt"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/back_button_alt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/rounded_corner"
|
||||||
|
android:contentDescription="@string/player_controls_exit"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_arrow_left" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/extra_buttons_alt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_unlock"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:background="@drawable/rounded_corner"
|
||||||
|
android:contentDescription="@string/select_playback_speed"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_unlock"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
249
app/phone/src/main/res/layout/exo_main_controls.xml
Normal file
249
app/phone/src/main/res/layout/exo_main_controls.xml
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/player_controls"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/player_background">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/extra_buttons"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/back_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:contentDescription="@string/player_controls_exit"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_arrow_left" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/video_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
tools:text="The Dawn of Despair" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/extra_buttons"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_lockview"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:contentDescription="Locks the player"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_lock"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_speed"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:contentDescription="@string/select_playback_speed"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_gauge"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_audio_track"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:contentDescription="@string/select_audio_track"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_speaker"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_subtitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:contentDescription="@string/select_subtile_track"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_closed_caption"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/exo_prev"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_skip_back" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/exo_rew"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_rewind" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/exo_play_pause"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/circle_background"
|
||||||
|
android:backgroundTint="@android:color/white"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_play"
|
||||||
|
app:tint="@android:color/black" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/exo_pause"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/circle_background"
|
||||||
|
android:backgroundTint="@android:color/white"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_pause"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:tint="@android:color/black" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/exo_ffwd"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_fast_forward" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/exo_next"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:background="@drawable/transparent_circle_background"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:src="@drawable/ic_skip_forward" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image_preview"
|
||||||
|
android:layout_width="160dp"
|
||||||
|
android:layout_height="90dp"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/exo_position"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
tools:text="00:00" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="8dp"
|
||||||
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@android:color/white" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="8dp"
|
||||||
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/exo_duration"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
tools:text="24:21" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.media3.ui.DefaultTimeBar
|
||||||
|
android:id="@+id/exo_progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:played_color="?attr/colorPrimary" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
|
@ -1,232 +1,14 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/player_controls"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:background="@color/player_background">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<include layout="@layout/exo_main_controls"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/exo_locked_controls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_margin="8dp"
|
android:layout_gravity="bottom|end" />
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<LinearLayout
|
</FrameLayout>
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/extra_buttons"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/back_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/transparent_circle_background"
|
|
||||||
android:contentDescription="@string/player_controls_exit"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_arrow_left" />
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="0dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/video_name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
|
|
||||||
android:textColor="@android:color/white"
|
|
||||||
tools:text="The Dawn of Despair" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/extra_buttons"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/btn_speed"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:background="@drawable/transparent_circle_background"
|
|
||||||
android:contentDescription="@string/select_playback_speed"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_gauge"
|
|
||||||
app:tint="@android:color/white" />
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="0dp" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/btn_audio_track"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:background="@drawable/transparent_circle_background"
|
|
||||||
android:contentDescription="@string/select_audio_track"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_speaker"
|
|
||||||
app:tint="@android:color/white" />
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="0dp" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/btn_subtitle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:background="@drawable/transparent_circle_background"
|
|
||||||
android:contentDescription="@string/select_subtile_track"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_closed_caption"
|
|
||||||
app:tint="@android:color/white" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/exo_prev"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="32dp"
|
|
||||||
android:background="@drawable/transparent_circle_background"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_skip_back" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/exo_rew"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="32dp"
|
|
||||||
android:background="@drawable/transparent_circle_background"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_rewind" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/exo_play_pause"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/circle_background"
|
|
||||||
android:backgroundTint="@android:color/white"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_play"
|
|
||||||
app:tint="@android:color/black" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/exo_pause"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/circle_background"
|
|
||||||
android:backgroundTint="@android:color/white"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_pause"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:tint="@android:color/black" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/exo_ffwd"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="32dp"
|
|
||||||
android:background="@drawable/transparent_circle_background"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_fast_forward" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/exo_next"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="32dp"
|
|
||||||
android:background="@drawable/transparent_circle_background"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_skip_forward" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/image_preview"
|
|
||||||
android:layout_width="160dp"
|
|
||||||
android:layout_height="90dp"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingStart="8dp"
|
|
||||||
android:paddingEnd="8dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/exo_position"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textColor="@android:color/white"
|
|
||||||
android:textSize="14sp"
|
|
||||||
tools:text="00:00" />
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="8dp"
|
|
||||||
android:layout_height="0dp" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="4dp"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="@android:color/white" />
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="8dp"
|
|
||||||
android:layout_height="0dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/exo_duration"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textColor="@android:color/white"
|
|
||||||
android:textSize="14sp"
|
|
||||||
tools:text="24:21" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<androidx.media3.ui.DefaultTimeBar
|
|
||||||
android:id="@+id/exo_progress"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:played_color="?attr/colorPrimary" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
20
core/src/debug/res/drawable/ic_unlock.xml
Normal file
20
core/src/debug/res/drawable/ic_unlock.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M5,11L19,11A2,2 0,0 1,21 13L21,20A2,2 0,0 1,19 22L5,22A2,2 0,0 1,3 20L3,13A2,2 0,0 1,5 11z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M7,11V7a5,5 0,0 1,9.9 -1"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
16
core/src/debug/res/drawable/rounded_corner.xml
Normal file
16
core/src/debug/res/drawable/rounded_corner.xml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:color="?attr/colorControlHighlight">
|
||||||
|
<item android:id="@android:id/mask">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#72000000" />
|
||||||
|
<corners android:radius="10000dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
|
Loading…
Reference in a new issue