Commit 566ba602 authored by Nicolas Pomepuy's avatar Nicolas Pomepuy
Browse files

Allow searching in Video playlist and UI improvements

parent c69ee409
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:color="@color/orange500transparent" />
<item android:state_selected="true" android:color="@color/orange500transparent" />
<item android:state_pressed="true" android:color="@color/orange500transparent" />
<item android:state_focused="true" android:color="@color/orange500focus"/>
<item android:state_selected="true" android:color="@color/orange500focus"/>
<item android:state_pressed="true" android:color="@color/orange500focus"/>
<item android:color="@color/playerbackground" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:drawable="@drawable/circle_orange"/>
<item android:state_selected="true" android:drawable="@drawable/circle_orange"/>
<item android:state_pressed="true" android:drawable="@drawable/circle_orange"/>
<item android:drawable="@drawable/empty"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/orange500focus"></solid>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/orange500focus"/>
<corners
android:topRightRadius="24dp"
android:bottomRightRadius="24dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:drawable="@drawable/rectangle_circle_right_orange"/>
<item android:state_selected="true" android:drawable="@drawable/rectangle_circle_right_orange"/>
<item android:state_pressed="true" android:drawable="@drawable/rectangle_circle_right_orange"/>
<item android:drawable="@drawable/empty"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/player_root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:keepScreenOn="true">
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/player_root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:keepScreenOn="true">
<!--
the double FrameLayout is necessary here to do cropping on the bottom right
......@@ -11,92 +12,131 @@
-->
<org.videolan.libvlc.util.VLCVideoLayout
android:id="@+id/video_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"/>
android:id="@+id/video_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"/>
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/player_seek_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
android:layout="@layout/player_overlay_seek" />
<RelativeLayout
android:id="@+id/player_ui_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >
android:id="@+id/player_seek_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
android:layout="@layout/player_overlay_seek"/>
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/player_overlay_tips"
<RelativeLayout
android:id="@+id/player_ui_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/player_tips" />
android:fitsSystemWindows="true">
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/player_overlay_tips"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/player_tips"/>
<ImageView
android:id="@+id/player_overlay_loading"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:visibility="invisible"
android:src="@drawable/ic_cone_o" />
android:id="@+id/player_overlay_loading"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:visibility="invisible"
android:src="@drawable/ic_cone_o"/>
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/player_info_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginBottom="@dimen/default_margin"
android:layout="@layout/player_overlay_info"/>
android:id="@+id/player_info_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginBottom="@dimen/default_margin"
android:layout="@layout/player_overlay_info"/>
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/player_overlay_settings_stub"
android:layout="@layout/player_overlay_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="@dimen/default_margin" />
android:id="@+id/player_overlay_settings_stub"
android:layout="@layout/player_overlay_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="@dimen/default_margin"/>
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/player_hud_stub"
android:layout_width="800dp"
android:layout_height="wrap_content"
android:layout="@layout/player_hud"
android:layout_marginBottom="@dimen/overlay_margin"
android:layout_marginRight="@dimen/overlay_margin"
android:layout_marginLeft="@dimen/overlay_margin"
android:layout_alignParentBottom="true" />
android:id="@+id/player_hud_stub"
android:layout_width="800dp"
android:layout_height="wrap_content"
android:layout="@layout/player_hud"
android:layout_marginBottom="@dimen/overlay_margin"
android:layout_marginRight="@dimen/overlay_margin"
android:layout_marginLeft="@dimen/overlay_margin"
android:layout_alignParentBottom="true"/>
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/player_hud_right_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginLeft="@dimen/overlay_margin"
android:layout_marginTop="@dimen/overlay_margin"
android:layout_marginRight="@dimen/overlay_margin"
android:layout_marginBottom="@dimen/overlay_margin"
android:layout="@layout/player_hud_right" />
android:id="@+id/player_hud_right_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginLeft="@dimen/overlay_margin"
android:layout_marginTop="@dimen/overlay_margin"
android:layout_marginRight="@dimen/overlay_margin"
android:layout_marginBottom="@dimen/overlay_margin"
android:layout="@layout/player_hud_right"/>
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/video_playlist"
android:layout_width="480dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/rounded_corners"
android:visibility="gone"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:maxWidth="480dp"
android:layout_centerHorizontal="true"
android:background="@color/playerbackground"
android:id="@+id/video_playlist_container"
android:visibility="gone"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/playlist_search_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:focusable="true"
android:nextFocusDown="@+id/video_playlist"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:layout_marginTop="8dp">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/search_hint"
android:imeOptions="actionSearch"
android:inputType="textFilter"/>
</com.google.android.material.textfield.TextInputLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/video_playlist"
android:layout_width="match_parent"
android:layout_height="0dp"
android:focusable="true"
android:descendantFocusability="afterDescendants"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/playlist_search_text"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/player_options_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/player_options" />
android:id="@+id/player_options_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/player_options"/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:layout_gravity="top"
android:background="@color/transparent"
android:textColor="@color/white"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textSize="15sp"
android:shadowColor="@color/black"
android:shadowDx="3"
android:shadowDy="3"
android:shadowRadius="1.5" />
<!-- Useless views to fix Chrome OS build -->
<Space
android:id="@+id/player_overlay_systime"
android:layout_width="0dp"
android:layout_height="0dp" />
<Space
android:id="@+id/player_overlay_battery"
android:layout_width="0dp"
android:layout_height="0dp" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View"/>
<import type="android.text.TextUtils"/>
<import type="org.videolan.vlc.util.Strings"/>
<variable
name="holder"
type="org.videolan.vlc.gui.audio.PlaylistAdapter.ViewHolder"/>
name="holder"
type="org.videolan.vlc.gui.audio.PlaylistAdapter.ViewHolder"/>
<variable
name="media"
name="media"
type="org.videolan.medialibrary.interfaces.media.AbstractMediaWrapper"/>
<variable
name="subTitle"
type="String"/>
<variable
name="titleColor"
type="int"/>
name="subTitle"
type="String"/>
</data>
<RelativeLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="40dp"
android:layout_margin="5dip"
android:clickable="true"
android:onClick="@{(view) -> holder.onClick(view, media)}" >
<LinearLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/item_more"
android:layout_toStartOf="@+id/item_more"
android:orientation="vertical">
<!-- TextView must be set to singleLine
see https://code.google.com/p/android/issues/detail?id=33868 -->
<TextView
android:minHeight="40dp">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerVertical="true"
android:background="@drawable/rectangle_circle_right_orange_selector"
android:focusable="true"
android:layout_alignParentStart="true"
android:clickable="true"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:onClick="@{(view) -> holder.onClick(view, media)}"
android:layout_toStartOf="@+id/item_more"
android:orientation="vertical"
android:id="@+id/selector"
app:layout_constraintEnd_toStartOf="@+id/playing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/playing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/item_more"
android:layout_marginEnd="8dp"/>
<TextView
android:id="@+id/audio_item_title"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:singleLine="true"
android:ellipsize="middle"
android:maxLines="1"
android:text="@{media.title}"
android:textColor="@{titleColor}"
android:textSize="16sp" />
<TextView
android:textSize="16sp"
android:textColor="?attr/font_default"
app:layout_constraintEnd_toStartOf="@+id/playing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintBottom_toTopOf="@+id/audio_item_subtitle"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="4dp"
app:layout_constraintStart_toStartOf="@+id/selector"/>
<TextView
android:id="@+id/audio_item_subtitle"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{subTitle}"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:singleLine="true"
android:ellipsize="middle"
android:maxLines="1"
android:textColor="?attr/font_light"
android:textColor="?attr/font_default"
android:fontFamily="sans-serif"
android:textSize="12sp"
android:visibility="@{TextUtils.isEmpty(subTitle) ? View.GONE : View.VISIBLE}"/>
</LinearLayout>
android:visibility="@{TextUtils.isEmpty(subTitle) ? View.GONE : View.VISIBLE}"
app:layout_constraintTop_toBottomOf="@+id/audio_item_title"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/playing"/>
<ImageView
android:id="@+id/item_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingRight="10dp"
android:paddingLeft="10dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:scaleType="center"
android:background="@drawable/ic_more"
android:onClick="@{holder::onMoreClick}"
android:clickable="true" />
</RelativeLayout>
android:id="@+id/item_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@drawable/button_circle_orange_selector"
android:scaleType="center"
android:layout_marginRight="4dp"
android:src="@drawable/ic_more_normal_w"
android:onClick="@{holder::onMoreClick}"
android:clickable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
......@@ -22,6 +22,7 @@
<color name="red500transparent">#b4ff0000</color>
<color name="orange500transparent">#b4ff8800</color>
<color name="orange500focus">#86ff8800</color>
<color name="orange200transparent">#64ffca7d</color>
<color name="grey50">#fafafa</color>
......
......@@ -25,6 +25,7 @@ package org.videolan.vlc.gui.audio
import android.annotation.TargetApi
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Message
import android.view.LayoutInflater
......@@ -35,6 +36,8 @@ import androidx.annotation.MainThread
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.videolan.libvlc.util.AndroidUtil
......@@ -87,11 +90,24 @@ class PlaylistAdapter(private val player: IPlayer) : DiffUtilAdapter<AbstractMed
val ctx = holder.itemView.context
val media = getItem(position)
holder.binding!!.media = media
holder.binding!!.subTitle = MediaUtils.getMediaSubtitle(media!!)
holder.binding!!.titleColor = if (currentIndex == position)
UiTools.getColorFromAttribute(ctx, R.attr.list_title_last)
else
UiTools.getColorFromAttribute(ctx, R.attr.list_title)
holder.binding!!.subTitle = MediaUtils.getMediaSubtitle(media)
val drawableNowPlaying = AnimatedVectorDrawableCompat.create(ctx, R.drawable.anim_now_playing)!!
if (currentIndex == position) {
holder.binding!!.playing.setImageDrawable(drawableNowPlaying)
drawableNowPlaying.start()
drawableNowPlaying.registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
super.onAnimationEnd(drawable)
drawableNowPlaying.start()
}
})
holder.binding!!.playing.visibility = View.VISIBLE
} else {
holder.binding!!.playing.setImageDrawable(drawableNowPlaying)
holder.binding!!.playing.visibility = View.INVISIBLE
}
holder.binding!!.executePendingBindings()
}
......@@ -125,12 +141,11 @@ class PlaylistAdapter(private val player: IPlayer) : DiffUtilAdapter<AbstractMed
}
override fun onItemMoved(dragFrom: Int, dragTo: Int) {
}
override fun onItemDismiss(position: Int) {
val media = getItem(position)
val message = String.format(VLCApplication.appResources.getString(R.string.remove_playlist_item), media!!.title)
val message = String.format(VLCApplication.appResources.getString(R.string.remove_playlist_item), media.title)
if (player is Fragment) {
val v = (player as Fragment).view
val cancelAction = Runnable { mModel!!.insertMedia(position, media) }
......@@ -196,17 +211,12 @@ class PlaylistAdapter(private val player: IPlayer) : DiffUtilAdapter<AbstractMed
companion object {
internal val ACTION_MOVE = 0
internal val ACTION_MOVED = 1
const val ACTION_MOVE = 0
const val ACTION_MOVED = 1
}
}
override fun createCB(): DiffUtilAdapter.DiffCallback<AbstractMediaWrapper> {
override fun createCB(): DiffCallback<AbstractMediaWrapper> {
return MediaItemDiffCallback()
}
companion object {
private val TAG = "VLC/PlaylistAdapter"
}
}
......@@ -37,7 +37,9 @@ import android.graphics.Color
import android.media.AudioManager
import android.net.Uri
import android.os.*
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.util.DisplayMetrics
import android.util.Log
import android.util.Rational
......@@ -52,7 +54,6 @@ import androidx.annotation.StringRes
import androidx.annotation.WorkerThread
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.ViewStubCompat
......@@ -72,6 +73,7 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.google.android.material.circularreveal.CircularRevealCompat
import com.google.android.material.circularreveal.CircularRevealWidget
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout
import kotlinx.android.synthetic.main.player_overlay_seek.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
......@@ -109,7 +111,7 @@ import java.util.*
@Suppress("DEPRECATION")
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
open class VideoPlayerActivity : AppCompatActivity(), IPlaybackSettingsController, PlaybackService.Callback, PlaylistAdapter.IPlayer, OnClickListener, OnLongClickListener, StoragePermissionsDelegate.CustomActionController, Observer<PlaybackService> {
open class VideoPlayerActivity : AppCompatActivity(), IPlaybackSettingsController, PlaybackService.Callback, PlaylistAdapter.IPlayer, OnClickListener, OnLongClickListener, StoragePermissionsDelegate.CustomActionController, Observer<PlaybackService>, TextWatcher {
private var wasPlaying = true
......@@ -123,7 +125,9 @@ open class VideoPlayerActivity : AppCompatActivity(), IPlaybackSettingsControlle
private var videoUri: Uri? = null
private var askResume = true
private lateinit var playlistContainer: View
private lateinit var playlist: RecyclerView
private lateinit var playlistSearchText: TextInputLayout
private lateinit var playlistAdapter: PlaylistAdapter
private var playlistModel: PlaylistModel? = null
......@@ -365,7 +369,7 @@ open class VideoPlayerActivity : AppCompatActivity(), IPlaybackSettingsControlle
private var optionsDelegate: PlayerOptionsDelegate? = null
val isPlaylistVisible: Boolean
get() = playlist.visibility == View.VISIBLE
get() = playlistContainer.visibility == View.VISIBLE
private val btReceiver = object : BroadcastReceiver() {