Add a HeaderView binder
This commit is contained in:
parent
5f716f5008
commit
e81b1ef8c2
|
@ -1,114 +0,0 @@
|
||||||
package org.moire.ultrasonic.util;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class AlbumHeader
|
|
||||||
{
|
|
||||||
private boolean isAllVideo;
|
|
||||||
private long totalDuration;
|
|
||||||
private Set<String> artists;
|
|
||||||
private Set<String> grandParents;
|
|
||||||
private Set<String> genres;
|
|
||||||
private Set<Integer> years;
|
|
||||||
|
|
||||||
public boolean getIsAllVideo()
|
|
||||||
{
|
|
||||||
return isAllVideo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalDuration()
|
|
||||||
{
|
|
||||||
return totalDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getArtists()
|
|
||||||
{
|
|
||||||
return artists;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getGrandParents()
|
|
||||||
{
|
|
||||||
return this.grandParents;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getGenres()
|
|
||||||
{
|
|
||||||
return this.genres;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Integer> getYears()
|
|
||||||
{
|
|
||||||
return this.years;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AlbumHeader()
|
|
||||||
{
|
|
||||||
this.artists = new HashSet<String>();
|
|
||||||
this.grandParents = new HashSet<String>();
|
|
||||||
this.genres = new HashSet<String>();
|
|
||||||
this.years = new HashSet<Integer>();
|
|
||||||
|
|
||||||
this.isAllVideo = true;
|
|
||||||
this.totalDuration = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AlbumHeader processEntries(Context context, Iterable<MusicDirectory.Entry> entries)
|
|
||||||
{
|
|
||||||
AlbumHeader albumHeader = new AlbumHeader();
|
|
||||||
|
|
||||||
for (MusicDirectory.Entry entry : entries)
|
|
||||||
{
|
|
||||||
if (!entry.isVideo())
|
|
||||||
{
|
|
||||||
albumHeader.isAllVideo = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entry.isDirectory())
|
|
||||||
{
|
|
||||||
if (Settings.getShouldUseFolderForArtistName())
|
|
||||||
{
|
|
||||||
albumHeader.processGrandParents(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.getArtist() != null)
|
|
||||||
{
|
|
||||||
Integer duration = entry.getDuration();
|
|
||||||
|
|
||||||
if (duration != null)
|
|
||||||
{
|
|
||||||
albumHeader.totalDuration += duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
albumHeader.artists.add(entry.getArtist());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.getGenre() != null)
|
|
||||||
{
|
|
||||||
albumHeader.genres.add(entry.getGenre());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.getYear() != null)
|
|
||||||
{
|
|
||||||
albumHeader.years.add(entry.getYear());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return albumHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processGrandParents(MusicDirectory.Entry entry)
|
|
||||||
{
|
|
||||||
String grandParent = Util.getGrandparent(entry.getPath());
|
|
||||||
|
|
||||||
if (grandParent != null)
|
|
||||||
{
|
|
||||||
this.grandParents.add(grandParent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
package org.moire.ultrasonic.util
|
||||||
|
|
||||||
|
import org.moire.ultrasonic.domain.Identifiable
|
||||||
|
import org.moire.ultrasonic.domain.MusicDirectory
|
||||||
|
import org.moire.ultrasonic.util.Settings.shouldUseFolderForArtistName
|
||||||
|
import org.moire.ultrasonic.util.Util.getGrandparent
|
||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
|
class AlbumHeader(
|
||||||
|
var entries: List<MusicDirectory.Entry>,
|
||||||
|
var name: String,
|
||||||
|
songCount: Int
|
||||||
|
): Identifiable {
|
||||||
|
var isAllVideo: Boolean
|
||||||
|
private set
|
||||||
|
|
||||||
|
var totalDuration: Long
|
||||||
|
private set
|
||||||
|
|
||||||
|
var childCount = 0
|
||||||
|
|
||||||
|
private val _artists: MutableSet<String>
|
||||||
|
private val _grandParents: MutableSet<String>
|
||||||
|
private val _genres: MutableSet<String>
|
||||||
|
private val _years: MutableSet<Int>
|
||||||
|
|
||||||
|
val artists: Set<String>
|
||||||
|
get() = _artists
|
||||||
|
|
||||||
|
val grandParents: Set<String>
|
||||||
|
get() = _grandParents
|
||||||
|
|
||||||
|
val genres: Set<String>
|
||||||
|
get() = _genres
|
||||||
|
|
||||||
|
val years: Set<Int>
|
||||||
|
get() = _years
|
||||||
|
|
||||||
|
private fun processGrandParents(entry: MusicDirectory.Entry) {
|
||||||
|
val grandParent = getGrandparent(entry.path)
|
||||||
|
if (grandParent != null) {
|
||||||
|
_grandParents.add(grandParent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NestedBlockDepth")
|
||||||
|
private fun processEntries(list: List<MusicDirectory.Entry>) {
|
||||||
|
entries = list
|
||||||
|
childCount = entries.size
|
||||||
|
for (entry in entries) {
|
||||||
|
if (!entry.isVideo) {
|
||||||
|
isAllVideo = false
|
||||||
|
}
|
||||||
|
if (!entry.isDirectory) {
|
||||||
|
if (shouldUseFolderForArtistName) {
|
||||||
|
processGrandParents(entry)
|
||||||
|
}
|
||||||
|
if (entry.artist != null) {
|
||||||
|
val duration = entry.duration
|
||||||
|
if (duration != null) {
|
||||||
|
totalDuration += duration.toLong()
|
||||||
|
}
|
||||||
|
_artists.add(entry.artist!!)
|
||||||
|
}
|
||||||
|
if (entry.genre != null) {
|
||||||
|
_genres.add(entry.genre!!)
|
||||||
|
}
|
||||||
|
if (entry.year != null) {
|
||||||
|
_years.add(entry.year!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
_artists = HashSet()
|
||||||
|
_grandParents = HashSet()
|
||||||
|
_genres = HashSet()
|
||||||
|
_years = HashSet()
|
||||||
|
|
||||||
|
isAllVideo = true
|
||||||
|
totalDuration = 0
|
||||||
|
|
||||||
|
processEntries(entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val id: String
|
||||||
|
get() = "HEADER"
|
||||||
|
|
||||||
|
override val longId: Long
|
||||||
|
get() = id.hashCode().toLong()
|
||||||
|
|
||||||
|
override fun compareTo(other: Identifiable): Int {
|
||||||
|
return this.longId.compareTo(other.longId)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package org.moire.ultrasonic.adapters
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.drakeet.multitype.ItemViewBinder
|
||||||
|
import org.koin.core.component.KoinComponent
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
import org.moire.ultrasonic.R
|
||||||
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||||
|
import org.moire.ultrasonic.util.AlbumHeader
|
||||||
|
import org.moire.ultrasonic.util.Util
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
import java.util.Random
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Binder can bind a list of entries into a Header
|
||||||
|
*/
|
||||||
|
class HeaderViewBinder(
|
||||||
|
context: Context
|
||||||
|
) : ItemViewBinder<AlbumHeader, HeaderViewBinder.ViewHolder>(), KoinComponent {
|
||||||
|
|
||||||
|
private val weakContext: WeakReference<Context> = WeakReference(context)
|
||||||
|
private val random: Random = Random()
|
||||||
|
private val imageLoaderProvider: ImageLoaderProvider by inject()
|
||||||
|
|
||||||
|
// Set our layout files
|
||||||
|
val layout = R.layout.select_album_header
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
|
||||||
|
return ViewHolder(inflater.inflate(layout, parent, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val coverArtView: ImageView = itemView.findViewById(R.id.select_album_art)
|
||||||
|
val titleView: TextView = itemView.findViewById(R.id.select_album_title)
|
||||||
|
val artistView: TextView = itemView.findViewById(R.id.select_album_artist)
|
||||||
|
val durationView: TextView = itemView.findViewById(R.id.select_album_duration)
|
||||||
|
val songCountView: TextView = itemView.findViewById(R.id.select_album_song_count)
|
||||||
|
val yearView: TextView = itemView.findViewById(R.id.select_album_year)
|
||||||
|
val genreView: TextView = itemView.findViewById(R.id.select_album_genre)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, item: AlbumHeader) {
|
||||||
|
|
||||||
|
val context = weakContext.get() ?: return
|
||||||
|
val resources = context.resources
|
||||||
|
|
||||||
|
|
||||||
|
val artworkSelection = random.nextInt(item.childCount)
|
||||||
|
|
||||||
|
imageLoaderProvider.getImageLoader().loadImage(
|
||||||
|
holder.coverArtView, item.entries[artworkSelection], false,
|
||||||
|
Util.getAlbumImageSize(context)
|
||||||
|
)
|
||||||
|
|
||||||
|
holder.titleView.text = item.name
|
||||||
|
|
||||||
|
|
||||||
|
// Don't show a header if all entries are videos
|
||||||
|
if (item.isAllVideo) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val artist: String = when {
|
||||||
|
item.artists.size == 1 -> item.artists.iterator().next()
|
||||||
|
item.grandParents.size == 1 -> item.grandParents.iterator().next()
|
||||||
|
else -> context.resources.getString(R.string.common_various_artists)
|
||||||
|
}
|
||||||
|
holder.artistView.text = artist
|
||||||
|
|
||||||
|
|
||||||
|
val genre: String = if (item.genres.size == 1) {
|
||||||
|
item.genres.iterator().next()
|
||||||
|
} else {
|
||||||
|
context.resources.getString(R.string.common_multiple_genres)
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.genreView.text = genre
|
||||||
|
|
||||||
|
|
||||||
|
val year: String = if (item.years.size == 1) {
|
||||||
|
item.years.iterator().next().toString()
|
||||||
|
} else {
|
||||||
|
resources.getString(R.string.common_multiple_years)
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.yearView.text = year
|
||||||
|
|
||||||
|
|
||||||
|
val songs = resources.getQuantityString(
|
||||||
|
R.plurals.select_album_n_songs, item.childCount,
|
||||||
|
item.childCount
|
||||||
|
)
|
||||||
|
holder.songCountView.text = songs
|
||||||
|
|
||||||
|
val duration = Util.formatTotalDuration(item.totalDuration)
|
||||||
|
holder.durationView.text = duration
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,8 @@
|
||||||
package org.moire.ultrasonic.adapters
|
package org.moire.ultrasonic.adapters
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Checkable
|
|
||||||
import androidx.recyclerview.selection.SelectionTracker
|
|
||||||
import com.drakeet.multitype.ItemViewBinder
|
import com.drakeet.multitype.ItemViewBinder
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
@ -14,7 +11,6 @@ import org.moire.ultrasonic.domain.Identifiable
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory
|
import org.moire.ultrasonic.domain.MusicDirectory
|
||||||
import org.moire.ultrasonic.service.DownloadFile
|
import org.moire.ultrasonic.service.DownloadFile
|
||||||
import org.moire.ultrasonic.service.Downloader
|
import org.moire.ultrasonic.service.Downloader
|
||||||
import org.moire.ultrasonic.util.Settings
|
|
||||||
|
|
||||||
class TrackViewBinder(
|
class TrackViewBinder(
|
||||||
val selectedSet: MutableSet<Long>,
|
val selectedSet: MutableSet<Long>,
|
||||||
|
@ -70,7 +66,7 @@ class TrackViewBinder(
|
||||||
checkable = checkable,
|
checkable = checkable,
|
||||||
draggable = draggable
|
draggable = draggable
|
||||||
)
|
)
|
||||||
|
|
||||||
// Observe download status
|
// Observe download status
|
||||||
// item.status.observe(
|
// item.status.observe(
|
||||||
// lifecycleOwner,
|
// lifecycleOwner,
|
||||||
|
|
|
@ -1,44 +1,27 @@
|
||||||
package org.moire.ultrasonic.fragment
|
package org.moire.ultrasonic.fragment
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.LifecycleOwner
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
import org.moire.ultrasonic.adapters.GenericRowAdapter
|
import org.moire.ultrasonic.adapters.MultiTypeDiffAdapter
|
||||||
|
import org.moire.ultrasonic.adapters.TrackViewBinder
|
||||||
|
import org.moire.ultrasonic.domain.Identifiable
|
||||||
import org.moire.ultrasonic.service.DownloadFile
|
import org.moire.ultrasonic.service.DownloadFile
|
||||||
import org.moire.ultrasonic.service.Downloader
|
import org.moire.ultrasonic.service.Downloader
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
import org.moire.ultrasonic.view.SongViewHolder
|
import java.util.TreeSet
|
||||||
|
|
||||||
class DownloadsFragment : GenericListFragment<DownloadFile, DownloadRowAdapter>() {
|
class DownloadsFragment : MultiListFragment<DownloadFile, MultiTypeDiffAdapter<Identifiable>>() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ViewModel to use to get the data
|
* The ViewModel to use to get the data
|
||||||
*/
|
*/
|
||||||
override val listModel: DownloadListModel by viewModels()
|
override val listModel: DownloadListModel by viewModels()
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the main layout
|
|
||||||
*/
|
|
||||||
override val mainLayout: Int = R.layout.generic_list
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the refresh view
|
|
||||||
*/
|
|
||||||
override val refreshListId: Int = R.id.generic_list_refresh
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the RecyclerView
|
|
||||||
*/
|
|
||||||
override val recyclerViewId = R.id.generic_list_recycler
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the target in the navigation graph where we should go,
|
* The id of the target in the navigation graph where we should go,
|
||||||
* after the user has clicked on an item
|
* after the user has clicked on an item
|
||||||
|
@ -56,15 +39,17 @@ class DownloadsFragment : GenericListFragment<DownloadFile, DownloadRowAdapter>(
|
||||||
/**
|
/**
|
||||||
* Provide the Adapter for the RecyclerView with a lazy delegate
|
* Provide the Adapter for the RecyclerView with a lazy delegate
|
||||||
*/
|
*/
|
||||||
override val viewAdapter: DownloadRowAdapter by lazy {
|
override val viewAdapter: MultiTypeDiffAdapter<Identifiable> by lazy {
|
||||||
DownloadRowAdapter(
|
val adapter = MultiTypeDiffAdapter<Identifiable>()
|
||||||
liveDataItems.value ?: listOf(),
|
adapter.register(
|
||||||
{ entry -> onItemClick(entry) },
|
TrackViewBinder(
|
||||||
{ menuItem, entry -> onContextMenuItemSelected(menuItem, entry) },
|
selectedSet = TreeSet(),
|
||||||
onMusicFolderUpdate,
|
checkable = false,
|
||||||
requireContext(),
|
draggable = false,
|
||||||
viewLifecycleOwner
|
context = requireContext()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onContextMenuItemSelected(menuItem: MenuItem, item: DownloadFile): Boolean {
|
override fun onContextMenuItemSelected(menuItem: MenuItem, item: DownloadFile): Boolean {
|
||||||
|
@ -81,63 +66,6 @@ class DownloadsFragment : GenericListFragment<DownloadFile, DownloadRowAdapter>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadRowAdapter(
|
|
||||||
itemList: List<DownloadFile>,
|
|
||||||
onItemClick: (DownloadFile) -> Unit,
|
|
||||||
onContextMenuClick: (MenuItem, DownloadFile) -> Boolean,
|
|
||||||
onMusicFolderUpdate: (String?) -> Unit,
|
|
||||||
val context: Context,
|
|
||||||
val lifecycleOwner: LifecycleOwner
|
|
||||||
) : GenericRowAdapter<DownloadFile>(
|
|
||||||
onItemClick,
|
|
||||||
onContextMenuClick,
|
|
||||||
onMusicFolderUpdate
|
|
||||||
) {
|
|
||||||
|
|
||||||
init {
|
|
||||||
super.submitList(itemList)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Set our layout files
|
|
||||||
override val layout = R.layout.song_list_item
|
|
||||||
override val contextMenuLayout = R.menu.artist_context_menu
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
|
||||||
if (holder is SongViewHolder) {
|
|
||||||
val downloadFile = currentList[position]
|
|
||||||
|
|
||||||
holder.setSong(downloadFile, checkable = false, draggable = false)
|
|
||||||
|
|
||||||
// Observe download status
|
|
||||||
downloadFile.status.observe(
|
|
||||||
lifecycleOwner,
|
|
||||||
{
|
|
||||||
holder.updateDownloadStatus(downloadFile)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
downloadFile.progress.observe(
|
|
||||||
lifecycleOwner,
|
|
||||||
{
|
|
||||||
holder.updateDownloadStatus(downloadFile)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of our ViewHolder class
|
|
||||||
*/
|
|
||||||
override fun newViewHolder(view: View): RecyclerView.ViewHolder {
|
|
||||||
return SongViewHolder(view, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class DownloadListModel(application: Application) : GenericListModel(application) {
|
class DownloadListModel(application: Application) : GenericListModel(application) {
|
||||||
private val downloader by inject<Downloader>()
|
private val downloader by inject<Downloader>()
|
||||||
|
|
|
@ -71,20 +71,20 @@ abstract class MultiListFragment<T : Identifiable, TA : MultiTypeAdapter> : Frag
|
||||||
*/
|
*/
|
||||||
protected abstract val itemClickTarget: Int
|
protected abstract val itemClickTarget: Int
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the RecyclerView
|
|
||||||
*/
|
|
||||||
protected abstract val recyclerViewId: Int
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the main layout
|
* The id of the main layout
|
||||||
*/
|
*/
|
||||||
abstract val mainLayout: Int
|
open val mainLayout: Int = R.layout.generic_list
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the refresh view
|
* The id of the refresh view
|
||||||
*/
|
*/
|
||||||
abstract val refreshListId: Int
|
open val refreshListId: Int = R.id.generic_list_refresh
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the RecyclerView
|
||||||
|
*/
|
||||||
|
open val recyclerViewId = R.id.generic_list_recycler
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The observer to be called if the available music folders have changed
|
* The observer to be called if the available music folders have changed
|
||||||
|
|
|
@ -31,13 +31,13 @@ import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
|
import org.moire.ultrasonic.adapters.HeaderViewBinder
|
||||||
import org.moire.ultrasonic.adapters.MultiTypeDiffAdapter
|
import org.moire.ultrasonic.adapters.MultiTypeDiffAdapter
|
||||||
import org.moire.ultrasonic.adapters.TrackViewBinder
|
import org.moire.ultrasonic.adapters.TrackViewBinder
|
||||||
import org.moire.ultrasonic.adapters.TrackViewHolder
|
import org.moire.ultrasonic.adapters.TrackViewHolder
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
||||||
import org.moire.ultrasonic.domain.Identifiable
|
import org.moire.ultrasonic.domain.Identifiable
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory
|
import org.moire.ultrasonic.domain.MusicDirectory
|
||||||
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.getTitle
|
|
||||||
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController
|
import org.moire.ultrasonic.service.MediaPlayerController
|
||||||
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
|
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
|
||||||
|
@ -51,17 +51,18 @@ import org.moire.ultrasonic.util.Settings
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.Random
|
|
||||||
import java.util.TreeSet
|
import java.util.TreeSet
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a group of tracks, eg. the songs of an album, of a playlist etc.
|
* Displays a group of tracks, eg. the songs of an album, of a playlist etc.
|
||||||
* TODO: Refactor this fragment and model to extend the GenericListFragment
|
* TODO: Move Clickhandler into ViewBinders
|
||||||
|
* TODO: Migrate Album/artistsRow
|
||||||
|
* TODO: Wrong count (selectall)
|
||||||
|
* TODO: Handle updates (playstatus, download status)
|
||||||
*/
|
*/
|
||||||
class TrackCollectionFragment :
|
class TrackCollectionFragment :
|
||||||
MultiListFragment<MusicDirectory.Entry, MultiTypeDiffAdapter<Identifiable>>() {
|
MultiListFragment<MusicDirectory.Entry, MultiTypeDiffAdapter<Identifiable>>() {
|
||||||
|
|
||||||
private var header: View? = null
|
|
||||||
private var albumButtons: View? = null
|
private var albumButtons: View? = null
|
||||||
private var emptyView: TextView? = null
|
private var emptyView: TextView? = null
|
||||||
private var selectButton: ImageView? = null
|
private var selectButton: ImageView? = null
|
||||||
|
@ -84,7 +85,6 @@ class TrackCollectionFragment :
|
||||||
private var cancellationToken: CancellationToken? = null
|
private var cancellationToken: CancellationToken? = null
|
||||||
|
|
||||||
override val listModel: TrackCollectionModel by viewModels()
|
override val listModel: TrackCollectionModel by viewModels()
|
||||||
private val random: Random = Random()
|
|
||||||
|
|
||||||
private var selectedSet: TreeSet<Long> = TreeSet()
|
private var selectedSet: TreeSet<Long> = TreeSet()
|
||||||
|
|
||||||
|
@ -136,11 +136,6 @@ class TrackCollectionFragment :
|
||||||
updateDisplay(true)
|
updateDisplay(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
header = LayoutInflater.from(context).inflate(
|
|
||||||
R.layout.select_album_header, listView,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
listModel.currentList.observe(viewLifecycleOwner, defaultObserver)
|
listModel.currentList.observe(viewLifecycleOwner, defaultObserver)
|
||||||
listModel.songsForGenre.observe(viewLifecycleOwner, songsForGenreObserver)
|
listModel.songsForGenre.observe(viewLifecycleOwner, songsForGenreObserver)
|
||||||
|
|
||||||
|
@ -231,17 +226,25 @@ class TrackCollectionFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
viewAdapter.register(
|
||||||
|
HeaderViewBinder(
|
||||||
|
context = requireContext()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
viewAdapter.register(
|
viewAdapter.register(
|
||||||
TrackViewBinder(
|
TrackViewBinder(
|
||||||
selectedSet = selectedSet,
|
selectedSet = selectedSet,
|
||||||
checkable = true,
|
checkable = true,
|
||||||
draggable = false,
|
draggable = false,
|
||||||
context = context!!
|
context = requireContext()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
enableButtons()
|
enableButtons()
|
||||||
|
|
||||||
|
// Loads the data
|
||||||
updateDisplay(false)
|
updateDisplay(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +256,7 @@ class TrackCollectionFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDisplay(refresh: Boolean) {
|
private fun updateDisplay(refresh: Boolean) {
|
||||||
|
// FIXME: Use refresh
|
||||||
getLiveData(requireArguments())
|
getLiveData(requireArguments())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,12 +387,32 @@ class TrackCollectionFragment :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val viewHolders: List<TrackViewHolder>
|
||||||
|
get() {
|
||||||
|
val list: MutableList<TrackViewHolder> = mutableListOf()
|
||||||
|
for (i in 0 until listView!!.childCount) {
|
||||||
|
val vh = listView!!.findViewHolderForAdapterPosition(i)
|
||||||
|
if (vh is TrackViewHolder) {
|
||||||
|
list.add(vh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
private val childCount: Int
|
||||||
|
get() {
|
||||||
|
if (listModel.showHeader) {
|
||||||
|
return listView!!.childCount - 1
|
||||||
|
} else {
|
||||||
|
return listView!!.childCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun playAll(shuffle: Boolean = false, append: Boolean = false) {
|
private fun playAll(shuffle: Boolean = false, append: Boolean = false) {
|
||||||
var hasSubFolders = false
|
var hasSubFolders = false
|
||||||
|
|
||||||
for (i in 0 until listView!!.childCount) {
|
for (vh in viewHolders) {
|
||||||
val vh = listView!!.findViewHolderForAdapterPosition(i) as TrackViewHolder?
|
val entry = vh.entry
|
||||||
val entry = vh?.entry
|
|
||||||
if (entry != null && entry.isDirectory) {
|
if (entry != null && entry.isDirectory) {
|
||||||
hasSubFolders = true
|
hasSubFolders = true
|
||||||
break
|
break
|
||||||
|
@ -427,20 +451,19 @@ class TrackCollectionFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun selectAllOrNone() {
|
private fun selectAllOrNone() {
|
||||||
val someUnselected = selectedSet.size < listView!!.childCount
|
val someUnselected = selectedSet.size < childCount
|
||||||
|
|
||||||
selectAll(someUnselected, true)
|
selectAll(someUnselected, true)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun selectAll(selected: Boolean, toast: Boolean) {
|
private fun selectAll(selected: Boolean, toast: Boolean) {
|
||||||
val count = listView!!.childCount
|
|
||||||
var selectedCount = 0
|
var selectedCount = 0
|
||||||
|
|
||||||
listView!!
|
listView!!
|
||||||
|
|
||||||
for (i in 0 until count) {
|
for (vh in viewHolders) {
|
||||||
val vh = listView!!.findViewHolderForAdapterPosition(i) as TrackViewHolder
|
|
||||||
val entry = vh.entry
|
val entry = vh.entry
|
||||||
|
|
||||||
if (entry != null && !entry.isDirectory && !entry.isVideo) {
|
if (entry != null && !entry.isDirectory && !entry.isVideo) {
|
||||||
|
@ -579,16 +602,19 @@ class TrackCollectionFragment :
|
||||||
|
|
||||||
private val defaultObserver = Observer(this::updateInterfaceWithEntries)
|
private val defaultObserver = Observer(this::updateInterfaceWithEntries)
|
||||||
|
|
||||||
private fun updateInterfaceWithEntries(list: List<MusicDirectory.Entry>) {
|
private fun updateInterfaceWithEntries(newList: List<MusicDirectory.Entry>) {
|
||||||
|
|
||||||
|
val entryList: MutableList<MusicDirectory.Entry> = newList.toMutableList()
|
||||||
|
|
||||||
if (listModel.currentListIsSortable && Settings.shouldSortByDisc) {
|
if (listModel.currentListIsSortable && Settings.shouldSortByDisc) {
|
||||||
Collections.sort(list, EntryByDiscAndTrackComparator())
|
Collections.sort(entryList, EntryByDiscAndTrackComparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var allVideos = true
|
var allVideos = true
|
||||||
var songCount = 0
|
var songCount = 0
|
||||||
|
|
||||||
for (entry in list) {
|
for (entry in entryList) {
|
||||||
if (!entry.isVideo) {
|
if (!entry.isVideo) {
|
||||||
allVideos = false
|
allVideos = false
|
||||||
}
|
}
|
||||||
|
@ -600,18 +626,6 @@ class TrackCollectionFragment :
|
||||||
val listSize = requireArguments().getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0)
|
val listSize = requireArguments().getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0)
|
||||||
|
|
||||||
if (songCount > 0) {
|
if (songCount > 0) {
|
||||||
// if (listModel.showHeader) {
|
|
||||||
// val intentAlbumName = requireArguments().getString(Constants.INTENT_EXTRA_NAME_NAME)
|
|
||||||
// val directoryName = musicDirectory.name
|
|
||||||
// val header = createHeader(
|
|
||||||
// entries, intentAlbumName ?: directoryName,
|
|
||||||
// songCount
|
|
||||||
// )
|
|
||||||
//// if (header != null && listView!!.headerViewsCount == 0) {
|
|
||||||
//// listView!!.addHeaderView(header, null, false)
|
|
||||||
//// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pinButton!!.visibility = View.VISIBLE
|
pinButton!!.visibility = View.VISIBLE
|
||||||
unpinButton!!.visibility = View.VISIBLE
|
unpinButton!!.visibility = View.VISIBLE
|
||||||
downloadButton!!.visibility = View.VISIBLE
|
downloadButton!!.visibility = View.VISIBLE
|
||||||
|
@ -653,7 +667,7 @@ class TrackCollectionFragment :
|
||||||
playNextButton!!.visibility = View.GONE
|
playNextButton!!.visibility = View.GONE
|
||||||
playLastButton!!.visibility = View.GONE
|
playLastButton!!.visibility = View.GONE
|
||||||
|
|
||||||
if (listSize == 0 || list.size < listSize) {
|
if (listSize == 0 || entryList.size < listSize) {
|
||||||
albumButtons!!.visibility = View.GONE
|
albumButtons!!.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
moreButton!!.visibility = View.VISIBLE
|
moreButton!!.visibility = View.VISIBLE
|
||||||
|
@ -666,7 +680,7 @@ class TrackCollectionFragment :
|
||||||
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE
|
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE
|
||||||
)
|
)
|
||||||
|
|
||||||
playAllButtonVisible = !(isAlbumList || list.isEmpty()) && !allVideos
|
playAllButtonVisible = !(isAlbumList || entryList.isEmpty()) && !allVideos
|
||||||
shareButtonVisible = !isOffline() && songCount > 0
|
shareButtonVisible = !isOffline() && songCount > 0
|
||||||
|
|
||||||
// listView!!.removeHeaderView(emptyView!!)
|
// listView!!.removeHeaderView(emptyView!!)
|
||||||
|
@ -684,7 +698,18 @@ class TrackCollectionFragment :
|
||||||
shareButton!!.isVisible = shareButtonVisible
|
shareButton!!.isVisible = shareButtonVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
viewAdapter.submitList(list)
|
|
||||||
|
if (songCount > 0 && listModel.showHeader) {
|
||||||
|
var name = listModel.currentDirectory.value?.name
|
||||||
|
val intentAlbumName = requireArguments().getString(Constants.INTENT_EXTRA_NAME_NAME, "Name")!!
|
||||||
|
val albumHeader = AlbumHeader(newList, name?: intentAlbumName, songCount)
|
||||||
|
val mixedList: MutableList<Identifiable> = mutableListOf(albumHeader)
|
||||||
|
mixedList.addAll(entryList)
|
||||||
|
viewAdapter.submitList(mixedList)
|
||||||
|
} else {
|
||||||
|
viewAdapter.submitList(entryList)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val playAll = requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false)
|
val playAll = requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false)
|
||||||
if (playAll && songCount > 0) {
|
if (playAll && songCount > 0) {
|
||||||
|
@ -699,77 +724,10 @@ class TrackCollectionFragment :
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createHeader(
|
|
||||||
entries: List<MusicDirectory.Entry>,
|
|
||||||
name: CharSequence?,
|
|
||||||
songCount: Int
|
|
||||||
): View? {
|
|
||||||
val coverArtView = header!!.findViewById<View>(R.id.select_album_art) as ImageView
|
|
||||||
val artworkSelection = random.nextInt(entries.size)
|
|
||||||
imageLoaderProvider.getImageLoader().loadImage(
|
|
||||||
coverArtView, entries[artworkSelection], false,
|
|
||||||
Util.getAlbumImageSize(context)
|
|
||||||
)
|
|
||||||
|
|
||||||
val albumHeader = AlbumHeader.processEntries(context, entries)
|
|
||||||
|
|
||||||
val titleView = header!!.findViewById<View>(R.id.select_album_title) as TextView
|
|
||||||
titleView.text = name ?: getTitle(this@TrackCollectionFragment) // getActionBarSubtitle());
|
|
||||||
|
|
||||||
// Don't show a header if all entries are videos
|
|
||||||
if (albumHeader.isAllVideo) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val artistView = header!!.findViewById<TextView>(R.id.select_album_artist)
|
|
||||||
|
|
||||||
val artist: String = when {
|
|
||||||
albumHeader.artists.size == 1 -> albumHeader.artists.iterator().next()
|
|
||||||
albumHeader.grandParents.size == 1 -> albumHeader.grandParents.iterator().next()
|
|
||||||
else -> resources.getString(R.string.common_various_artists)
|
|
||||||
}
|
|
||||||
|
|
||||||
artistView.text = artist
|
|
||||||
|
|
||||||
val genreView = header!!.findViewById<TextView>(R.id.select_album_genre)
|
|
||||||
|
|
||||||
val genre: String = if (albumHeader.genres.size == 1)
|
|
||||||
albumHeader.genres.iterator().next()
|
|
||||||
else
|
|
||||||
resources.getString(R.string.common_multiple_genres)
|
|
||||||
|
|
||||||
genreView.text = genre
|
|
||||||
|
|
||||||
val yearView = header!!.findViewById<TextView>(R.id.select_album_year)
|
|
||||||
|
|
||||||
val year: String = if (albumHeader.years.size == 1)
|
|
||||||
albumHeader.years.iterator().next().toString()
|
|
||||||
else
|
|
||||||
resources.getString(R.string.common_multiple_years)
|
|
||||||
|
|
||||||
yearView.text = year
|
|
||||||
|
|
||||||
val songCountView = header!!.findViewById<TextView>(R.id.select_album_song_count)
|
|
||||||
val songs = resources.getQuantityString(
|
|
||||||
R.plurals.select_album_n_songs, songCount,
|
|
||||||
songCount
|
|
||||||
)
|
|
||||||
songCountView.text = songs
|
|
||||||
|
|
||||||
val duration = Util.formatTotalDuration(albumHeader.totalDuration)
|
|
||||||
|
|
||||||
val durationView = header!!.findViewById<TextView>(R.id.select_album_duration)
|
|
||||||
durationView.text = duration
|
|
||||||
|
|
||||||
return header
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSelectedSongs(): MutableList<MusicDirectory.Entry> {
|
private fun getSelectedSongs(): MutableList<MusicDirectory.Entry> {
|
||||||
val songs: MutableList<MusicDirectory.Entry> = mutableListOf()
|
val songs: MutableList<MusicDirectory.Entry> = mutableListOf()
|
||||||
|
|
||||||
for (i in 0 until listView!!.childCount) {
|
for (vh in viewHolders) {
|
||||||
val vh = listView!!.findViewHolderForAdapterPosition(i) as TrackViewHolder? ?: continue
|
|
||||||
|
|
||||||
if (vh.isChecked) {
|
if (vh.isChecked) {
|
||||||
songs.add(vh.entry!!)
|
songs.add(vh.entry!!)
|
||||||
}
|
}
|
||||||
|
|
|
@ -871,7 +871,7 @@ object Util {
|
||||||
|
|
||||||
val descriptionBuilder = MediaDescriptionCompat.Builder()
|
val descriptionBuilder = MediaDescriptionCompat.Builder()
|
||||||
val desc = readableEntryDescription(song)
|
val desc = readableEntryDescription(song)
|
||||||
var title = ""
|
val title: String
|
||||||
|
|
||||||
if (groupNameId != null)
|
if (groupNameId != null)
|
||||||
descriptionBuilder.setExtras(
|
descriptionBuilder.setExtras(
|
||||||
|
|
|
@ -1,316 +1,316 @@
|
||||||
package org.moire.ultrasonic.view
|
//package org.moire.ultrasonic.view
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.drawable.AnimationDrawable
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.Checkable
|
|
||||||
import android.widget.CheckedTextView
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import org.koin.core.component.KoinComponent
|
|
||||||
import org.koin.core.component.get
|
|
||||||
import org.koin.core.component.inject
|
|
||||||
import org.moire.ultrasonic.R
|
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider
|
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory
|
|
||||||
import org.moire.ultrasonic.featureflags.Feature
|
|
||||||
import org.moire.ultrasonic.featureflags.FeatureStorage
|
|
||||||
import org.moire.ultrasonic.fragment.DownloadRowAdapter
|
|
||||||
import org.moire.ultrasonic.service.DownloadFile
|
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController
|
|
||||||
import org.moire.ultrasonic.service.MusicServiceFactory
|
|
||||||
import org.moire.ultrasonic.util.Settings
|
|
||||||
import org.moire.ultrasonic.util.Util
|
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to display songs and videos in a `ListView`.
|
|
||||||
* TODO: Video List item
|
|
||||||
*/
|
|
||||||
class SongViewHolder(view: View, context: Context) : RecyclerView.ViewHolder(view), Checkable, KoinComponent {
|
|
||||||
var check: CheckedTextView = view.findViewById(R.id.song_check)
|
|
||||||
var rating: LinearLayout = view.findViewById(R.id.song_rating)
|
|
||||||
var fiveStar1: ImageView = view.findViewById(R.id.song_five_star_1)
|
|
||||||
var fiveStar2: ImageView = view.findViewById(R.id.song_five_star_2)
|
|
||||||
var fiveStar3: ImageView = view.findViewById(R.id.song_five_star_3)
|
|
||||||
var fiveStar4: ImageView = view.findViewById(R.id.song_five_star_4)
|
|
||||||
var fiveStar5: ImageView = view.findViewById(R.id.song_five_star_5)
|
|
||||||
var star: ImageView = view.findViewById(R.id.song_star)
|
|
||||||
var drag: ImageView = view.findViewById(R.id.song_drag)
|
|
||||||
var track: TextView = view.findViewById(R.id.song_track)
|
|
||||||
var title: TextView = view.findViewById(R.id.song_title)
|
|
||||||
var artist: TextView = view.findViewById(R.id.song_artist)
|
|
||||||
var duration: TextView = view.findViewById(R.id.song_duration)
|
|
||||||
var status: TextView = view.findViewById(R.id.song_status)
|
|
||||||
|
|
||||||
var entry: MusicDirectory.Entry? = null
|
|
||||||
private set
|
|
||||||
var downloadFile: DownloadFile? = null
|
|
||||||
private set
|
|
||||||
|
|
||||||
private var isMaximized = false
|
|
||||||
private var leftImage: Drawable? = null
|
|
||||||
private var previousLeftImageType: ImageType? = null
|
|
||||||
private var previousRightImageType: ImageType? = null
|
|
||||||
private var leftImageType: ImageType? = null
|
|
||||||
private var playing = false
|
|
||||||
|
|
||||||
private val features: FeatureStorage = get()
|
|
||||||
private val useFiveStarRating: Boolean = features.isFeatureEnabled(Feature.FIVE_STAR_RATING)
|
|
||||||
private val mediaPlayerController: MediaPlayerController by inject()
|
|
||||||
|
|
||||||
fun setSong(file: DownloadFile, checkable: Boolean, draggable: Boolean) {
|
|
||||||
val song = file.song
|
|
||||||
downloadFile = file
|
|
||||||
entry = song
|
|
||||||
|
|
||||||
val entryDescription = Util.readableEntryDescription(song)
|
|
||||||
|
|
||||||
artist.text = entryDescription.artist
|
|
||||||
title.text = entryDescription.title
|
|
||||||
duration.text = entryDescription.duration
|
|
||||||
|
|
||||||
|
|
||||||
if (Settings.shouldShowTrackNumber && song.track != null && song.track!! > 0) {
|
|
||||||
track.text = entryDescription.trackNumber
|
|
||||||
} else {
|
|
||||||
track.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
check.isVisible = (checkable && !song.isVideo)
|
|
||||||
drag.isVisible = draggable
|
|
||||||
|
|
||||||
if (ActiveServerProvider.isOffline()) {
|
|
||||||
star.isVisible = false
|
|
||||||
rating.isVisible = false
|
|
||||||
} else {
|
|
||||||
setupStarButtons(song)
|
|
||||||
}
|
|
||||||
update()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupStarButtons(song: MusicDirectory.Entry) {
|
|
||||||
if (useFiveStarRating) {
|
|
||||||
star.isVisible = false
|
|
||||||
val rating = if (song.userRating == null) 0 else song.userRating!!
|
|
||||||
fiveStar1.setImageDrawable(
|
|
||||||
if (rating > 0) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
fiveStar2.setImageDrawable(
|
|
||||||
if (rating > 1) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
fiveStar3.setImageDrawable(
|
|
||||||
if (rating > 2) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
fiveStar4.setImageDrawable(
|
|
||||||
if (rating > 3) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
fiveStar5.setImageDrawable(
|
|
||||||
if (rating > 4) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
rating.isVisible = false
|
|
||||||
star.setImageDrawable(
|
|
||||||
if (song.starred) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
|
|
||||||
star.setOnClickListener {
|
|
||||||
val isStarred = song.starred
|
|
||||||
val id = song.id
|
|
||||||
|
|
||||||
if (!isStarred) {
|
|
||||||
star.setImageDrawable(DownloadRowAdapter.starDrawable)
|
|
||||||
song.starred = true
|
|
||||||
} else {
|
|
||||||
star.setImageDrawable(DownloadRowAdapter.starHollowDrawable)
|
|
||||||
song.starred = false
|
|
||||||
}
|
|
||||||
Thread {
|
|
||||||
val musicService = MusicServiceFactory.getMusicService()
|
|
||||||
try {
|
|
||||||
if (!isStarred) {
|
|
||||||
musicService.star(id, null, null)
|
|
||||||
} else {
|
|
||||||
musicService.unstar(id, null, null)
|
|
||||||
}
|
|
||||||
} catch (all: Exception) {
|
|
||||||
Timber.e(all)
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
// TDOD: Should be removed
|
|
||||||
fun update() {
|
|
||||||
val song = entry ?: return
|
|
||||||
|
|
||||||
updateDownloadStatus(downloadFile!!)
|
|
||||||
|
|
||||||
if (entry?.starred != true) {
|
|
||||||
if (star.drawable !== DownloadRowAdapter.starHollowDrawable) {
|
|
||||||
star.setImageDrawable(DownloadRowAdapter.starHollowDrawable)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (star.drawable !== DownloadRowAdapter.starDrawable) {
|
|
||||||
star.setImageDrawable(DownloadRowAdapter.starDrawable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val rating = entry?.userRating ?: 0
|
|
||||||
fiveStar1.setImageDrawable(
|
|
||||||
if (rating > 0) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
fiveStar2.setImageDrawable(
|
|
||||||
if (rating > 1) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
fiveStar3.setImageDrawable(
|
|
||||||
if (rating > 2) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
fiveStar4.setImageDrawable(
|
|
||||||
if (rating > 3) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
fiveStar5.setImageDrawable(
|
|
||||||
if (rating > 4) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
|
||||||
)
|
|
||||||
|
|
||||||
val playing = mediaPlayerController.currentPlaying === downloadFile
|
|
||||||
|
|
||||||
if (playing) {
|
|
||||||
if (!this.playing) {
|
|
||||||
this.playing = true
|
|
||||||
title.setCompoundDrawablesWithIntrinsicBounds(
|
|
||||||
DownloadRowAdapter.playingImage, null, null, null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.playing) {
|
|
||||||
this.playing = false
|
|
||||||
title.setCompoundDrawablesWithIntrinsicBounds(
|
|
||||||
0, 0, 0, 0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateDownloadStatus(downloadFile: DownloadFile) {
|
|
||||||
|
|
||||||
if (downloadFile.isWorkDone) {
|
|
||||||
val newLeftImageType =
|
|
||||||
if (downloadFile.isSaved) ImageType.Pin else ImageType.Downloaded
|
|
||||||
|
|
||||||
if (leftImageType != newLeftImageType) {
|
|
||||||
leftImage = if (downloadFile.isSaved) {
|
|
||||||
DownloadRowAdapter.pinImage
|
|
||||||
} else {
|
|
||||||
DownloadRowAdapter.downloadedImage
|
|
||||||
}
|
|
||||||
leftImageType = newLeftImageType
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
leftImageType = ImageType.None
|
|
||||||
leftImage = null
|
|
||||||
}
|
|
||||||
|
|
||||||
val rightImageType: ImageType
|
|
||||||
val rightImage: Drawable?
|
|
||||||
|
|
||||||
if (downloadFile.isDownloading && !downloadFile.isDownloadCancelled) {
|
|
||||||
status.text = Util.formatPercentage(downloadFile.progress.value!!)
|
|
||||||
|
|
||||||
rightImageType = ImageType.Downloading
|
|
||||||
rightImage = DownloadRowAdapter.downloadingImage
|
|
||||||
} else {
|
|
||||||
rightImageType = ImageType.None
|
|
||||||
rightImage = null
|
|
||||||
|
|
||||||
val statusText = status.text
|
|
||||||
if (!statusText.isNullOrEmpty()) status.text = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousLeftImageType != leftImageType || previousRightImageType != rightImageType) {
|
|
||||||
previousLeftImageType = leftImageType
|
|
||||||
previousRightImageType = rightImageType
|
|
||||||
|
|
||||||
status.setCompoundDrawablesWithIntrinsicBounds(
|
|
||||||
leftImage, null, rightImage, null
|
|
||||||
)
|
|
||||||
|
|
||||||
if (rightImage === DownloadRowAdapter.downloadingImage) {
|
|
||||||
// FIXME
|
|
||||||
val frameAnimation = rightImage as AnimationDrawable?
|
|
||||||
|
|
||||||
frameAnimation?.setVisible(true, true)
|
|
||||||
frameAnimation?.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fun updateDownloadStatus2(
|
|
||||||
// downloadFile: DownloadFile,
|
|
||||||
// ) {
|
|
||||||
//
|
//
|
||||||
// var image: Drawable? = null
|
//import android.content.Context
|
||||||
|
//import android.graphics.drawable.AnimationDrawable
|
||||||
|
//import android.graphics.drawable.Drawable
|
||||||
|
//import android.view.View
|
||||||
|
//import android.widget.Checkable
|
||||||
|
//import android.widget.CheckedTextView
|
||||||
|
//import android.widget.ImageView
|
||||||
|
//import android.widget.LinearLayout
|
||||||
|
//import android.widget.TextView
|
||||||
|
//import androidx.core.view.isVisible
|
||||||
|
//import androidx.recyclerview.widget.RecyclerView
|
||||||
|
//import org.koin.core.component.KoinComponent
|
||||||
|
//import org.koin.core.component.get
|
||||||
|
//import org.koin.core.component.inject
|
||||||
|
//import org.moire.ultrasonic.R
|
||||||
|
//import org.moire.ultrasonic.data.ActiveServerProvider
|
||||||
|
//import org.moire.ultrasonic.domain.MusicDirectory
|
||||||
|
//import org.moire.ultrasonic.featureflags.Feature
|
||||||
|
//import org.moire.ultrasonic.featureflags.FeatureStorage
|
||||||
|
//import org.moire.ultrasonic.fragment.DownloadRowAdapter
|
||||||
|
//import org.moire.ultrasonic.service.DownloadFile
|
||||||
|
//import org.moire.ultrasonic.service.MediaPlayerController
|
||||||
|
//import org.moire.ultrasonic.service.MusicServiceFactory
|
||||||
|
//import org.moire.ultrasonic.util.Settings
|
||||||
|
//import org.moire.ultrasonic.util.Util
|
||||||
|
//import timber.log.Timber
|
||||||
//
|
//
|
||||||
// when (downloadFile.status.value) {
|
///**
|
||||||
// DownloadStatus.DONE -> {
|
// * Used to display songs and videos in a `ListView`.
|
||||||
// image = if (downloadFile.isSaved) DownloadRowAdapter.pinImage else DownloadRowAdapter.downloadedImage
|
// * TODO: Video List item
|
||||||
// status.text = null
|
// */
|
||||||
// }
|
//class SongViewHolder(view: View, context: Context) : RecyclerView.ViewHolder(view), Checkable, KoinComponent {
|
||||||
// DownloadStatus.DOWNLOADING -> {
|
// var check: CheckedTextView = view.findViewById(R.id.song_check)
|
||||||
// status.text = Util.formatPercentage(downloadFile.progress.value!!)
|
// var rating: LinearLayout = view.findViewById(R.id.song_rating)
|
||||||
// image = DownloadRowAdapter.downloadingImage
|
// var fiveStar1: ImageView = view.findViewById(R.id.song_five_star_1)
|
||||||
// }
|
// var fiveStar2: ImageView = view.findViewById(R.id.song_five_star_2)
|
||||||
// else -> {
|
// var fiveStar3: ImageView = view.findViewById(R.id.song_five_star_3)
|
||||||
// status.text = null
|
// var fiveStar4: ImageView = view.findViewById(R.id.song_five_star_4)
|
||||||
// }
|
// var fiveStar5: ImageView = view.findViewById(R.id.song_five_star_5)
|
||||||
|
// var star: ImageView = view.findViewById(R.id.song_star)
|
||||||
|
// var drag: ImageView = view.findViewById(R.id.song_drag)
|
||||||
|
// var track: TextView = view.findViewById(R.id.song_track)
|
||||||
|
// var title: TextView = view.findViewById(R.id.song_title)
|
||||||
|
// var artist: TextView = view.findViewById(R.id.song_artist)
|
||||||
|
// var duration: TextView = view.findViewById(R.id.song_duration)
|
||||||
|
// var status: TextView = view.findViewById(R.id.song_status)
|
||||||
|
//
|
||||||
|
// var entry: MusicDirectory.Entry? = null
|
||||||
|
// private set
|
||||||
|
// var downloadFile: DownloadFile? = null
|
||||||
|
// private set
|
||||||
|
//
|
||||||
|
// private var isMaximized = false
|
||||||
|
// private var leftImage: Drawable? = null
|
||||||
|
// private var previousLeftImageType: ImageType? = null
|
||||||
|
// private var previousRightImageType: ImageType? = null
|
||||||
|
// private var leftImageType: ImageType? = null
|
||||||
|
// private var playing = false
|
||||||
|
//
|
||||||
|
// private val features: FeatureStorage = get()
|
||||||
|
// private val useFiveStarRating: Boolean = features.isFeatureEnabled(Feature.FIVE_STAR_RATING)
|
||||||
|
// private val mediaPlayerController: MediaPlayerController by inject()
|
||||||
|
//
|
||||||
|
// fun setSong(file: DownloadFile, checkable: Boolean, draggable: Boolean) {
|
||||||
|
// val song = file.song
|
||||||
|
// downloadFile = file
|
||||||
|
// entry = song
|
||||||
|
//
|
||||||
|
// val entryDescription = Util.readableEntryDescription(song)
|
||||||
|
//
|
||||||
|
// artist.text = entryDescription.artist
|
||||||
|
// title.text = entryDescription.title
|
||||||
|
// duration.text = entryDescription.duration
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// if (Settings.shouldShowTrackNumber && song.track != null && song.track!! > 0) {
|
||||||
|
// track.text = entryDescription.trackNumber
|
||||||
|
// } else {
|
||||||
|
// track.isVisible = false
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // TODO: Migrate the image animation stuff from SongView into this class
|
// check.isVisible = (checkable && !song.isVideo)
|
||||||
|
// drag.isVisible = draggable
|
||||||
//
|
//
|
||||||
// if (image != null) {
|
// if (ActiveServerProvider.isOffline()) {
|
||||||
// status.setCompoundDrawablesWithIntrinsicBounds(
|
// star.isVisible = false
|
||||||
// image, null, null, null
|
// rating.isVisible = false
|
||||||
|
// } else {
|
||||||
|
// setupStarButtons(song)
|
||||||
|
// }
|
||||||
|
// update()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun setupStarButtons(song: MusicDirectory.Entry) {
|
||||||
|
// if (useFiveStarRating) {
|
||||||
|
// star.isVisible = false
|
||||||
|
// val rating = if (song.userRating == null) 0 else song.userRating!!
|
||||||
|
// fiveStar1.setImageDrawable(
|
||||||
|
// if (rating > 0) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
|
// )
|
||||||
|
// fiveStar2.setImageDrawable(
|
||||||
|
// if (rating > 1) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
|
// )
|
||||||
|
// fiveStar3.setImageDrawable(
|
||||||
|
// if (rating > 2) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
|
// )
|
||||||
|
// fiveStar4.setImageDrawable(
|
||||||
|
// if (rating > 3) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
|
// )
|
||||||
|
// fiveStar5.setImageDrawable(
|
||||||
|
// if (rating > 4) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
|
// )
|
||||||
|
// } else {
|
||||||
|
// rating.isVisible = false
|
||||||
|
// star.setImageDrawable(
|
||||||
|
// if (song.starred) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
// )
|
// )
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// if (image === DownloadRowAdapter.downloadingImage) {
|
// star.setOnClickListener {
|
||||||
// // FIXME
|
// val isStarred = song.starred
|
||||||
//// val frameAnimation = image as AnimationDrawable
|
// val id = song.id
|
||||||
////
|
//
|
||||||
//// frameAnimation.setVisible(true, true)
|
// if (!isStarred) {
|
||||||
//// frameAnimation.start()
|
// star.setImageDrawable(DownloadRowAdapter.starDrawable)
|
||||||
|
// song.starred = true
|
||||||
|
// } else {
|
||||||
|
// star.setImageDrawable(DownloadRowAdapter.starHollowDrawable)
|
||||||
|
// song.starred = false
|
||||||
|
// }
|
||||||
|
// Thread {
|
||||||
|
// val musicService = MusicServiceFactory.getMusicService()
|
||||||
|
// try {
|
||||||
|
// if (!isStarred) {
|
||||||
|
// musicService.star(id, null, null)
|
||||||
|
// } else {
|
||||||
|
// musicService.unstar(id, null, null)
|
||||||
|
// }
|
||||||
|
// } catch (all: Exception) {
|
||||||
|
// Timber.e(all)
|
||||||
|
// }
|
||||||
|
// }.start()
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
override fun setChecked(newStatus: Boolean) {
|
//
|
||||||
check.isChecked = newStatus
|
// @Synchronized
|
||||||
}
|
// // TDOD: Should be removed
|
||||||
|
// fun update() {
|
||||||
override fun isChecked(): Boolean {
|
// val song = entry ?: return
|
||||||
return check.isChecked
|
//
|
||||||
}
|
// updateDownloadStatus(downloadFile!!)
|
||||||
|
//
|
||||||
override fun toggle() {
|
// if (entry?.starred != true) {
|
||||||
check.toggle()
|
// if (star.drawable !== DownloadRowAdapter.starHollowDrawable) {
|
||||||
}
|
// star.setImageDrawable(DownloadRowAdapter.starHollowDrawable)
|
||||||
|
// }
|
||||||
fun maximizeOrMinimize() {
|
// } else {
|
||||||
isMaximized = !isMaximized
|
// if (star.drawable !== DownloadRowAdapter.starDrawable) {
|
||||||
|
// star.setImageDrawable(DownloadRowAdapter.starDrawable)
|
||||||
title.isSingleLine = !isMaximized
|
// }
|
||||||
artist.isSingleLine = !isMaximized
|
// }
|
||||||
}
|
//
|
||||||
|
// val rating = entry?.userRating ?: 0
|
||||||
enum class ImageType {
|
// fiveStar1.setImageDrawable(
|
||||||
None, Pin, Downloaded, Downloading
|
// if (rating > 0) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
}
|
// )
|
||||||
|
// fiveStar2.setImageDrawable(
|
||||||
|
// if (rating > 1) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
}
|
// )
|
||||||
|
// fiveStar3.setImageDrawable(
|
||||||
|
// if (rating > 2) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
|
// )
|
||||||
|
// fiveStar4.setImageDrawable(
|
||||||
|
// if (rating > 3) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
|
// )
|
||||||
|
// fiveStar5.setImageDrawable(
|
||||||
|
// if (rating > 4) DownloadRowAdapter.starDrawable else DownloadRowAdapter.starHollowDrawable
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// val playing = mediaPlayerController.currentPlaying === downloadFile
|
||||||
|
//
|
||||||
|
// if (playing) {
|
||||||
|
// if (!this.playing) {
|
||||||
|
// this.playing = true
|
||||||
|
// title.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
// DownloadRowAdapter.playingImage, null, null, null
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if (this.playing) {
|
||||||
|
// this.playing = false
|
||||||
|
// title.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
// 0, 0, 0, 0
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fun updateDownloadStatus(downloadFile: DownloadFile) {
|
||||||
|
//
|
||||||
|
// if (downloadFile.isWorkDone) {
|
||||||
|
// val newLeftImageType =
|
||||||
|
// if (downloadFile.isSaved) ImageType.Pin else ImageType.Downloaded
|
||||||
|
//
|
||||||
|
// if (leftImageType != newLeftImageType) {
|
||||||
|
// leftImage = if (downloadFile.isSaved) {
|
||||||
|
// DownloadRowAdapter.pinImage
|
||||||
|
// } else {
|
||||||
|
// DownloadRowAdapter.downloadedImage
|
||||||
|
// }
|
||||||
|
// leftImageType = newLeftImageType
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// leftImageType = ImageType.None
|
||||||
|
// leftImage = null
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// val rightImageType: ImageType
|
||||||
|
// val rightImage: Drawable?
|
||||||
|
//
|
||||||
|
// if (downloadFile.isDownloading && !downloadFile.isDownloadCancelled) {
|
||||||
|
// status.text = Util.formatPercentage(downloadFile.progress.value!!)
|
||||||
|
//
|
||||||
|
// rightImageType = ImageType.Downloading
|
||||||
|
// rightImage = DownloadRowAdapter.downloadingImage
|
||||||
|
// } else {
|
||||||
|
// rightImageType = ImageType.None
|
||||||
|
// rightImage = null
|
||||||
|
//
|
||||||
|
// val statusText = status.text
|
||||||
|
// if (!statusText.isNullOrEmpty()) status.text = null
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (previousLeftImageType != leftImageType || previousRightImageType != rightImageType) {
|
||||||
|
// previousLeftImageType = leftImageType
|
||||||
|
// previousRightImageType = rightImageType
|
||||||
|
//
|
||||||
|
// status.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
// leftImage, null, rightImage, null
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// if (rightImage === DownloadRowAdapter.downloadingImage) {
|
||||||
|
// // FIXME
|
||||||
|
// val frameAnimation = rightImage as AnimationDrawable?
|
||||||
|
//
|
||||||
|
// frameAnimation?.setVisible(true, true)
|
||||||
|
// frameAnimation?.start()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//// fun updateDownloadStatus2(
|
||||||
|
//// downloadFile: DownloadFile,
|
||||||
|
//// ) {
|
||||||
|
////
|
||||||
|
//// var image: Drawable? = null
|
||||||
|
////
|
||||||
|
//// when (downloadFile.status.value) {
|
||||||
|
//// DownloadStatus.DONE -> {
|
||||||
|
//// image = if (downloadFile.isSaved) DownloadRowAdapter.pinImage else DownloadRowAdapter.downloadedImage
|
||||||
|
//// status.text = null
|
||||||
|
//// }
|
||||||
|
//// DownloadStatus.DOWNLOADING -> {
|
||||||
|
//// status.text = Util.formatPercentage(downloadFile.progress.value!!)
|
||||||
|
//// image = DownloadRowAdapter.downloadingImage
|
||||||
|
//// }
|
||||||
|
//// else -> {
|
||||||
|
//// status.text = null
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// // TODO: Migrate the image animation stuff from SongView into this class
|
||||||
|
////
|
||||||
|
//// if (image != null) {
|
||||||
|
//// status.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
//// image, null, null, null
|
||||||
|
//// )
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// if (image === DownloadRowAdapter.downloadingImage) {
|
||||||
|
//// // FIXME
|
||||||
|
////// val frameAnimation = image as AnimationDrawable
|
||||||
|
//////
|
||||||
|
////// frameAnimation.setVisible(true, true)
|
||||||
|
////// frameAnimation.start()
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
// override fun setChecked(newStatus: Boolean) {
|
||||||
|
// check.isChecked = newStatus
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun isChecked(): Boolean {
|
||||||
|
// return check.isChecked
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun toggle() {
|
||||||
|
// check.toggle()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fun maximizeOrMinimize() {
|
||||||
|
// isMaximized = !isMaximized
|
||||||
|
//
|
||||||
|
// title.isSingleLine = !isMaximized
|
||||||
|
// artist.isSingleLine = !isMaximized
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// enum class ImageType {
|
||||||
|
// None, Pin, Downloaded, Downloading
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
Loading…
Reference in New Issue