Commit 01b5b08f authored by Geoffrey Métais's avatar Geoffrey Métais
Browse files

Video groups UI

parent ceebb04d
<?xml version="1.0" encoding="utf-8"?>
<layout 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" >
<data>
<variable
name="group"
type="org.videolan.medialibrary.interfaces.media.AbstractVideoGroup" />
<variable
name="bgColor"
type="int" />
<variable
name="cover"
type="android.graphics.drawable.BitmapDrawable" />
<variable
name="holder"
type="org.videolan.vlc.gui.videogroups.VideoGroupsAdapter.ViewHolder" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:background="@{bgColor}"
android:onClick="@{holder::onClick}" >
<ImageView
android:id="@+id/folder_image"
android:layout_width="128dp"
android:layout_height="80dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:media="@{group}"
android:scaleType="centerCrop"
android:src="@{cover}" />
<TextView
android:id="@+id/folder_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toTopOf="@+id/group_desc"
app:layout_constraintEnd_toStartOf="@+id/folder_more"
app:layout_constraintStart_toEndOf="@+id/folder_image"
app:layout_constraintTop_toTopOf="@+id/folder_image"
app:layout_constraintVertical_chainStyle="packed"
android:text="@{group.title}"
app:ellipsizeMode="@{true}"
android:singleLine="true"
android:maxLines="1"
android:textColor="?attr/list_title"
android:textSize="16sp"
android:lineSpacingMultiplier="1.1"/>
<TextView
android:id="@+id/group_desc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/folder_image"
app:layout_constraintEnd_toStartOf="@+id/folder_more"
app:layout_constraintStart_toEndOf="@+id/folder_image"
app:layout_constraintTop_toBottomOf="@+id/folder_name"
tools:text="Description"
android:maxLines="1"
android:textColor="?attr/list_subtitle"
android:textSize="12sp" />
<ImageView
android:id="@+id/folder_more"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:clickable="true"
android:contentDescription="@string/more_actions"
android:onClick="@{holder::onCtxClick}"
android:scaleType="center"
android:src="@drawable/ic_more" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/button_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<org.videolan.vlc.gui.view.SwipeRefreshLayout
android:id="@+id/swipeLayout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/searchButton">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/groups_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fadingEdge="none"
android:fastScrollEnabled="true"
android:gravity="center"
android:numColumns="auto_fit"
android:padding="@dimen/half_default_margin"
android:scrollbarStyle="outsideInset"
android:scrollbars="vertical"
android:stretchMode="none" />
</org.videolan.vlc.gui.view.SwipeRefreshLayout>
<TextView
android:id="@+id/textview_nomedia"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:drawableBottom="@drawable/ic_empty"
android:drawablePadding="@dimen/default_margin"
android:gravity="center"
android:maxWidth="600dp"
android:text="@string/nomedia"
android:textSize="20sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -101,6 +101,10 @@
android:orderInCategory="2"
android:id="@+id/video_min_group_length_folder"
android:title="@string/video_min_group_length_folder" />
<item
android:orderInCategory="2"
android:id="@+id/video_min_group_length_name"
android:title="@string/video_min_group_length_name" />
</menu>
</item>
<item
......
......@@ -315,6 +315,7 @@
<string name="video_min_group_length_title">Group videos</string>
<string name="video_min_group_length_disable">Disable</string>
<string name="video_min_group_length_folder">Group by folder</string>
<string name="video_min_group_length_name">Group by name</string>
<string name="video_min_group_length_first">First letter only</string>
<string name="video_min_group_length_short">Short number of letters (6)</string>
<string name="video_min_group_length_long">Long number of letters (9)</string>
......
......@@ -44,6 +44,7 @@ import org.videolan.vlc.gui.video.VideoGridFragment
import org.videolan.vlc.reloadLibrary
import org.videolan.vlc.util.AndroidDevices
import org.videolan.vlc.util.KEY_FOLDER
import org.videolan.vlc.util.KEY_GROUP
import org.videolan.vlc.util.RESULT_RESCAN
@ExperimentalCoroutinesApi
......@@ -125,6 +126,7 @@ class SecondaryActivity : ContentActivity() {
fragment = VideoGridFragment().apply {
arguments = Bundle(1).apply {
putParcelable(KEY_FOLDER, intent.getParcelableExtra<Parcelable>(KEY_FOLDER))
putParcelable(KEY_GROUP, intent.getParcelableExtra<Parcelable>(KEY_GROUP))
}
}
}
......
......@@ -295,6 +295,11 @@ abstract class MediaBrowserFragment<T : SortableModel> : Fragment(), ActionMode.
(activity as MainActivity).forceLoadVideoFragment()
return true
}
R.id.video_min_group_length_name -> {
Settings.getInstance(requireActivity()).edit().putString("video_min_group_length", "6").apply()
(activity as MainActivity).forceLoadVideoFragment()
return true
}
else -> return super.onOptionsItemSelected(item)
}
}
......
......@@ -16,6 +16,7 @@ import org.videolan.libvlc.util.AndroidUtil
import org.videolan.medialibrary.interfaces.media.AbstractFolder
import org.videolan.tools.MultiSelectAdapter
import org.videolan.tools.MultiSelectHelper
import org.videolan.vlc.R
import org.videolan.vlc.databinding.FolderItemBinding
import org.videolan.vlc.gui.helpers.SelectorViewHolder
import org.videolan.vlc.util.UPDATE_SELECTION
......@@ -38,7 +39,7 @@ class FoldersAdapter(val actor: SendChannel<FolderAction>) : PagedListAdapter<Ab
launch {
val count = withContext(Dispatchers.IO) { folder?.mediaCount(AbstractFolder.TYPE_FOLDER_VIDEO) ?: 0 }
holder.binding.folderDesc.visibility = if (count == 0) View.GONE else View.VISIBLE
if (count > 0) holder.binding.folderDesc.text = "$count videos"
if (count > 0) holder.binding.folderDesc.text = holder.itemView.context.resources.getQuantityString(R.plurals.videos_quantity, count, count)
}
}
......
......@@ -59,10 +59,8 @@ class FoldersFragment : MediaBrowserFragment<FoldersViewModel>(), CtxActionRecei
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!this::adapter.isInitialized) {
adapter = FoldersAdapter(actor)
viewModel = getViewModel()
}
adapter = FoldersAdapter(actor)
viewModel = getViewModel()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
......@@ -112,7 +110,7 @@ class FoldersFragment : MediaBrowserFragment<FoldersViewModel>(), CtxActionRecei
when (option) {
CTX_PLAY -> launch { viewModel.play(position) }
CTX_APPEND -> launch { viewModel.append(position) }
CTX_ADD_TO_PLAYLIST -> viewModel.provider.pagedList.value?.get(position)?.let { UiTools.addToPlaylist(requireActivity(), it.getAll()) }
CTX_ADD_TO_PLAYLIST -> viewModel.addToPlaylist(requireActivity(), position)
}
}
......
......@@ -69,10 +69,10 @@ fun loadImage(v: View, item: MediaLibraryItem?, imageWidth: Int = 0) {
updateImageView(UiTools.getDefaultVideoDrawable(v.context).bitmap, v, binding)
return
}
val isGroup = isMedia && (item as AbstractMediaWrapper).type == AbstractMediaWrapper.TYPE_GROUP
val isGroup = isMedia && item.itemType == MediaLibraryItem.TYPE_VIDEO_GROUP
val isFolder = !isMedia && item.itemType == MediaLibraryItem.TYPE_FOLDER
val cacheKey = when {
isGroup -> "group:${item.title}"
isGroup -> "videogroup:${item.title}"
isFolder -> "folder:${item.title}"
else -> ThumbnailsProvider.getMediaCacheKey(isMedia, item)
}
......@@ -80,7 +80,7 @@ fun loadImage(v: View, item: MediaLibraryItem?, imageWidth: Int = 0) {
if (bitmap !== null) updateImageView(bitmap, v, binding)
else {
val scope = (v.context as? CoroutineScope) ?: AppScope
scope.launch { getImage(v, findInLibrary(item, isMedia, isGroup), binding, imageWidth) }
scope.launch { getImage(v, findInLibrary(item, isMedia), binding, imageWidth) }
}
}
......@@ -275,8 +275,8 @@ fun updateImageView(bitmap: Bitmap?, target: View, vdb: ViewDataBinding?, update
}
}
private suspend fun findInLibrary(item: MediaLibraryItem, isMedia: Boolean, isGroup: Boolean): MediaLibraryItem {
if (isMedia && !isGroup && item.id == 0L) {
private suspend fun findInLibrary(item: MediaLibraryItem, isMedia: Boolean): MediaLibraryItem {
if (isMedia && item.id == 0L) {
val mw = item as AbstractMediaWrapper
val type = mw.type
val isMediaFile = type == AbstractMediaWrapper.TYPE_AUDIO || type == AbstractMediaWrapper.TYPE_VIDEO
......
......@@ -58,6 +58,7 @@ import org.videolan.vlc.gui.folders.FoldersFragment
import org.videolan.vlc.gui.network.MRLPanelFragment
import org.videolan.vlc.gui.preferences.PreferencesActivity
import org.videolan.vlc.gui.video.VideoGridFragment
import org.videolan.vlc.gui.videogroups.VideoGroupsFragment
import org.videolan.vlc.gui.view.HackyDrawerLayout
import org.videolan.vlc.util.*
......@@ -142,8 +143,11 @@ class Navigator: NavigationView.OnNavigationItemSelectedListener, LifecycleObser
R.id.nav_mrl -> MRLPanelFragment()
else -> {
val group = Integer.valueOf(Settings.getInstance(activity.applicationContext).getString("video_min_group_length", "6")!!)
if (group == 0) FoldersFragment()
else VideoGridFragment()
when {
group > 0 -> VideoGroupsFragment()
group == 0 -> FoldersFragment()
else -> VideoGridFragment()
}
}
}
}
......
......@@ -40,6 +40,7 @@ import kotlinx.coroutines.launch
import org.videolan.medialibrary.interfaces.AbstractMedialibrary
import org.videolan.medialibrary.interfaces.media.AbstractFolder
import org.videolan.medialibrary.interfaces.media.AbstractMediaWrapper
import org.videolan.medialibrary.interfaces.media.AbstractVideoGroup
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.tools.MultiSelectHelper
import org.videolan.vlc.R
......@@ -78,7 +79,6 @@ class VideoGridFragment : MediaBrowserFragment<VideosViewModel>(), SwipeRefreshL
private var gridItemDecoration: RecyclerView.ItemDecoration? = null
class VideoGridFragmentHandler(private val videoGridFragment: WeakReference<VideoGridFragment>) : Handler() {
override fun handleMessage(msg: Message?) {
when (msg?.what) {
UPDATE_LIST -> {
......@@ -104,7 +104,10 @@ class VideoGridFragment : MediaBrowserFragment<VideosViewModel>(), SwipeRefreshL
multiSelectHelper = videoListAdapter.multiSelectHelper
val folder = if (savedInstanceState != null) savedInstanceState.getParcelable<AbstractFolder>(KEY_FOLDER)
else arguments?.getParcelable(KEY_FOLDER)
viewModel = getViewModel(folder)
val group = if (savedInstanceState != null ) savedInstanceState.getParcelable<AbstractVideoGroup>(KEY_GROUP)
else arguments?.getParcelable(KEY_GROUP)
Log.d(TAG, "group ${group?.title}")
viewModel = getViewModel(folder, group)
viewModel.provider.pagedList.observe(this, this)
viewModel.provider.loading.observe(this, Observer { loading ->
if (loading) handler.sendEmptyMessageDelayed(SET_REFRESHING, 300L)
......@@ -184,6 +187,7 @@ class VideoGridFragment : MediaBrowserFragment<VideosViewModel>(), SwipeRefreshL
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelable(KEY_FOLDER, viewModel.folder)
outState.putParcelable(KEY_GROUP, viewModel.group)
}
override fun onDestroy() {
......@@ -196,7 +200,7 @@ class VideoGridFragment : MediaBrowserFragment<VideosViewModel>(), SwipeRefreshL
if (list != null) videoListAdapter.submitList(list)
}
override fun getTitle() = viewModel.folder?.title ?: getString(R.string.video)
override fun getTitle() = viewModel.folder?.title ?: viewModel.group?.title ?: getString(R.string.video)
override fun getMultiHelper(): MultiSelectHelper<VideosViewModel>? = if (::videoListAdapter.isInitialized) videoListAdapter.multiSelectHelper as? MultiSelectHelper<VideosViewModel> else null
......
package org.videolan.vlc.gui.videogroups
import android.annotation.TargetApi
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.channels.SendChannel
import org.videolan.libvlc.util.AndroidUtil
import org.videolan.medialibrary.interfaces.media.AbstractVideoGroup
import org.videolan.tools.MultiSelectAdapter
import org.videolan.tools.MultiSelectHelper
import org.videolan.vlc.R
import org.videolan.vlc.databinding.VideogroupItemBinding
import org.videolan.vlc.gui.helpers.SelectorViewHolder
import org.videolan.vlc.util.UPDATE_SELECTION
class VideoGroupsAdapter (val actor: SendChannel<VideoGroupAction>) : PagedListAdapter<AbstractVideoGroup,
VideoGroupsAdapter.ViewHolder>(DIFF_CALLBACK), MultiSelectAdapter<AbstractVideoGroup>,
CoroutineScope by MainScope() {
private lateinit var inflater: LayoutInflater
val multiSelectHelper = MultiSelectHelper(this, UPDATE_SELECTION)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
if (!this::inflater.isInitialized) inflater = LayoutInflater.from(parent.context)
return ViewHolder(VideogroupItemBinding.inflate(inflater, parent, false))
}
override fun getItem(position: Int) = super.getItem(position)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val group = getItem(position)
holder.binding.group = group
val count = group?.mediaCount() ?: 0
holder.binding.groupDesc.visibility = if (count == 0) View.GONE else View.VISIBLE
if (count > 0) holder.binding.groupDesc.text = holder.itemView.context.resources.getQuantityString(R.plurals.videos_quantity, count, count)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
if (payloads.isNullOrEmpty()) super.onBindViewHolder(holder, position, payloads)
else {
for (payload in payloads) {
when (payload as? Int) {
UPDATE_SELECTION -> holder.selectView(multiSelectHelper.isSelected(position))
}
}
}
}
@TargetApi(Build.VERSION_CODES.M)
inner class ViewHolder(binding: VideogroupItemBinding) : SelectorViewHolder<VideogroupItemBinding>(binding) {
init {
binding.holder = this
itemView.setOnLongClickListener {
getItem(layoutPosition)?.let { folder -> actor.offer(VideoGroupLongClick(layoutPosition, folder)) }
true
}
if (AndroidUtil.isMarshMallowOrLater) itemView.setOnContextClickListener {
onCtxClick(itemView)
true
}
}
fun onClick(v: View) {
getItem(layoutPosition)?.let { folder -> actor.offer(VideoGroupClick(layoutPosition, folder)) }
}
fun onCtxClick(v: View) {
getItem(layoutPosition)?.let { folder -> actor.offer(VideoGroupCtxClick(layoutPosition, folder)) }
}
}
}
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<AbstractVideoGroup>() {
override fun areItemsTheSame(oldItem: AbstractVideoGroup, newItem: AbstractVideoGroup) = oldItem == newItem
override fun areContentsTheSame(oldItem: AbstractVideoGroup, newItem: AbstractVideoGroup) = true
}
\ No newline at end of file
package org.videolan.vlc.gui.videogroups
import android.content.Intent
import android.os.Bundle
import android.view.*
import androidx.appcompat.view.ActionMode
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.videogroups_fragment.*
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.actor
import org.videolan.medialibrary.interfaces.media.AbstractVideoGroup
import org.videolan.tools.MultiSelectHelper
import org.videolan.vlc.R
import org.videolan.vlc.gui.SecondaryActivity
import org.videolan.vlc.gui.browser.MediaBrowserFragment
import org.videolan.vlc.gui.dialogs.CtxActionReceiver
import org.videolan.vlc.gui.dialogs.showContext
import org.videolan.vlc.gui.helpers.UiTools
import org.videolan.vlc.media.MediaUtils
import org.videolan.vlc.media.PlaylistManager
import org.videolan.vlc.media.getAll
import org.videolan.vlc.reloadLibrary
import org.videolan.vlc.util.*
import org.videolan.vlc.viewmodels.mobile.VideogroupsViewModel
import org.videolan.vlc.viewmodels.mobile.getViewModel
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class VideoGroupsFragment : MediaBrowserFragment<VideogroupsViewModel>(), CtxActionReceiver {
private lateinit var adapter: VideoGroupsAdapter
private val actor = actor<VideoGroupAction> {
for (action in channel) when(action) {
is VideoGroupClick -> {
if (actionMode != null) {
adapter.multiSelectHelper.toggleSelection(action.position)
invalidateActionMode()
} else {
val i = Intent(activity, SecondaryActivity::class.java)
i.putExtra("fragment", SecondaryActivity.VIDEO_GROUP_LIST)
i.putExtra(KEY_GROUP, action.group)
activity?.startActivityForResult(i, SecondaryActivity.ACTIVITY_RESULT_SECONDARY)
}
}
is VideoGroupLongClick -> {
adapter.multiSelectHelper.toggleSelection(action.position, true)
if (actionMode == null) {
startActionMode()
}
}
is VideoGroupCtxClick -> {
showContext(requireActivity(), this@VideoGroupsFragment, action.position, action.group.title, CTX_FOLDER_FLAGS)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
adapter = VideoGroupsAdapter(actor)
viewModel = getViewModel()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.videogroups_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
groups_list.layoutManager = LinearLayoutManager(view.context, RecyclerView.VERTICAL, false)
groups_list.adapter = adapter
swipeRefreshLayout.setOnRefreshListener { activity?.reloadLibrary() }
viewModel.provider.pagedList.observe(requireActivity(), Observer {
swipeRefreshLayout.isRefreshing = false
adapter.submitList(it)
restoreMultiSelectHelper()
})
}
override fun onStart() {
super.onStart()
setFabPlayVisibility(true)
fabPlay?.setImageResource(R.drawable.ic_fab_play)
}
override fun getTitle() = getString(R.string.video)
override fun getMultiHelper(): MultiSelectHelper<VideogroupsViewModel>? = if (::adapter.isInitialized) adapter.multiSelectHelper as? MultiSelectHelper<VideogroupsViewModel> else null
override fun onRefresh() = viewModel.refresh()
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
menu.findItem(R.id.ml_menu_last_playlist)?.isVisible = true
menu.findItem(R.id.ml_menu_video_group).isVisible = true
}
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem): Boolean {
val selection = adapter.multiSelectHelper.getSelection()
when (item.itemId) {
R.id.action_folder_play -> viewModel.playSelection(selection)
R.id.action_folder_append -> viewModel.appendSelection(selection)
R.id.action_folder_add_playlist -> launch { UiTools.addToPlaylist(requireActivity(), withContext(Dispatchers.Default) { selection.getAll() }) }
else -> return false
}
stopActionMode()
return true
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
mode?.apply { menuInflater.inflate(R.menu.action_mode_folder, menu) }
return true
}
override fun onFabPlayClick(view: View) {
MediaUtils.playAllTracks(context, viewModel.provider, 0, false)
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
val count = adapter.multiSelectHelper.getSelectionCount()
if (count == 0) {
stopActionMode()
return false
}
menu.findItem(R.id.action_video_append)?.isVisible = PlaylistManager.hasMedia()
return true
}
override fun onDestroyActionMode(mode: ActionMode?) {
actionMode = null
adapter.multiSelectHelper.clearSelection()
}
override fun onCtxAction(position: Int, option: Int) {
when (option) {
CTX_PLAY -> viewModel.play(position)
CTX_APPEND -> viewModel.append(position)
CTX_ADD_TO_PLAYLIST -> viewModel.addToPlaylist(requireActivity(), position)
}
}
}
sealed class VideoGroupAction
class VideoGroupClick(val position: Int, val group: AbstractVideoGroup) : VideoGroupAction()
class VideoGroupLongClick(val position: Int, val group: AbstractVideoGroup) : VideoGroupAction()
class VideoGroupCtxClick(val position: Int, val group: AbstractVideoGroup) : VideoGroupAction()
\ No newline at end of file
......@@ -23,10 +23,7 @@ import org.videolan.libvlc.util.AndroidUtil
import org.videolan.medialibrary.MLServiceLocator
import org.videolan.medialibrary.Tools
import org.videolan.medialibrary.interfaces.AbstractMedialibrary
import org.videolan.medialibrary.interfaces.media.AbstractAlbum