Delete a bunch of now-unused classes

Also run KtLint
This commit is contained in:
tzugen 2021-11-23 21:58:58 +01:00
parent f8a87f7c85
commit eeb2d13d96
No known key found for this signature in database
GPG Key ID: 61E9C34BC10EC930
25 changed files with 64 additions and 1490 deletions

View File

@ -19,7 +19,6 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import androidx.navigation.Navigation
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
@ -41,7 +40,6 @@ import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util.toast
import org.moire.ultrasonic.view.ArtistAdapter
import org.moire.ultrasonic.view.EntryAdapter
import timber.log.Timber
/**
@ -75,16 +73,16 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
override val mainLayout: Int = R.layout.search
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
cancellationToken = CancellationToken()
setTitle(this, R.string.search_title)
setHasOptionsMenu(true)
val buttons = LayoutInflater.from(context).inflate(R.layout.search_buttons,
listView, false)
val buttons = LayoutInflater.from(context).inflate(
R.layout.search_buttons,
listView, false
)
if (buttons != null) {
artistsHeading = buttons.findViewById(R.id.search_artists)
@ -96,11 +94,12 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
moreSongsButton = buttons.findViewById(R.id.search_more_songs)
}
listModel.searchResult.observe(viewLifecycleOwner, {
if (it != null) populateList(it)
})
listModel.searchResult.observe(
viewLifecycleOwner,
{
if (it != null) populateList(it)
}
)
searchRefresh = view.findViewById(R.id.search_entries_refresh)
searchRefresh!!.isEnabled = false
@ -131,7 +130,6 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
registerForContextMenu(listView!!)
viewAdapter.register(
TrackViewBinder(
checkable = false,
@ -149,7 +147,6 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
)
)
// Fragment was started with a query (e.g. from voice search), try to execute search right away
val arguments = arguments
if (arguments != null) {
@ -432,14 +429,14 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
list.addAll(artists)
if (artists.size > DEFAULT_ARTISTS) {
// FIXME
//list.add((moreArtistsButton, true)
// list.add((moreArtistsButton, true)
}
}
val albums = searchResult.albums
if (albums.isNotEmpty()) {
//mergeAdapter!!.addView(albumsHeading)
// mergeAdapter!!.addView(albumsHeading)
list.addAll(albums)
//mergeAdapter!!.addAdapter(albumAdapter)
// mergeAdapter!!.addAdapter(albumAdapter)
// if (albums.size > DEFAULT_ALBUMS) {
// moreAlbumsAdapter = mergeAdapter!!.addView(moreAlbumsButton, true)
// }
@ -550,6 +547,5 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
// FIXME
override fun onItemClick(item: Identifiable) {
}
}

View File

@ -1,181 +0,0 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.view;
import android.content.Context;
import android.graphics.drawable.Drawable;
import timber.log.Timber;
import android.view.LayoutInflater;
import android.view.View;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.data.ActiveServerProvider;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.service.MusicService;
import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.imageloader.ImageLoader;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
/**
* Used to display albums in a {@code ListView}.
*
* @author Sindre Mehus
*/
public class AlbumView extends UpdateView
{
private static Drawable starDrawable;
private static Drawable starHollowDrawable;
private static String theme;
private final Context context;
private MusicDirectory.Entry entry;
private EntryAdapter.AlbumViewHolder viewHolder;
private final ImageLoader imageLoader;
private boolean maximized = false;
public AlbumView(Context context, ImageLoader imageLoader)
{
super(context);
this.context = context;
this.imageLoader = imageLoader;
String theme = Settings.getTheme();
boolean themesMatch = theme.equals(AlbumView.theme);
AlbumView.theme = theme;
if (starHollowDrawable == null || !themesMatch)
{
starHollowDrawable = Util.getDrawableFromAttribute(context, R.attr.star_hollow);
}
if (starDrawable == null || !themesMatch)
{
starDrawable = Util.getDrawableFromAttribute(context, R.attr.star_full);
}
}
public void setLayout()
{
LayoutInflater.from(context).inflate(R.layout.album_list_item_legacy, this, true);
viewHolder = new EntryAdapter.AlbumViewHolder();
viewHolder.title = findViewById(R.id.album_title);
viewHolder.artist = findViewById(R.id.album_artist);
viewHolder.cover_art = findViewById(R.id.album_coverart);
viewHolder.star = findViewById(R.id.album_star);
setTag(viewHolder);
}
public void setViewHolder(EntryAdapter.AlbumViewHolder viewHolder)
{
this.viewHolder = viewHolder;
this.viewHolder.cover_art.invalidate();
setTag(this.viewHolder);
}
public MusicDirectory.Entry getEntry()
{
return this.entry;
}
public boolean isMaximized() {
return maximized;
}
public void maximizeOrMinimize() {
maximized = !maximized;
if (this.viewHolder.title != null) {
this.viewHolder.title.setSingleLine(!maximized);
}
if (this.viewHolder.artist != null) {
this.viewHolder.artist.setSingleLine(!maximized);
}
}
public void setAlbum(final MusicDirectory.Entry album)
{
viewHolder.cover_art.setTag(album);
imageLoader.loadImage(viewHolder.cover_art, album, false, 0);
this.entry = album;
String title = album.getTitle();
String artist = album.getArtist();
boolean starred = album.getStarred();
viewHolder.title.setText(title);
viewHolder.artist.setText(artist);
viewHolder.artist.setVisibility(artist == null ? View.GONE : View.VISIBLE);
viewHolder.star.setImageDrawable(starred ? starDrawable : starHollowDrawable);
if (ActiveServerProvider.Companion.isOffline() || "-1".equals(album.getId()))
{
viewHolder.star.setVisibility(View.GONE);
}
else
{
viewHolder.star.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
final boolean isStarred = album.getStarred();
final String id = album.getId();
if (!isStarred)
{
viewHolder.star.setImageDrawable(starDrawable);
album.setStarred(true);
}
else
{
viewHolder.star.setImageDrawable(starHollowDrawable);
album.setStarred(false);
}
final MusicService musicService = MusicServiceFactory.getMusicService();
new Thread(new Runnable()
{
@Override
public void run()
{
boolean useId3 = Settings.getShouldUseId3Tags();
try
{
if (!isStarred)
{
musicService.star(!useId3 ? id : null, useId3 ? id : null, null);
}
else
{
musicService.unstar(!useId3 ? id : null, useId3 ? id : null, null);
}
}
catch (Exception e)
{
Timber.e(e);
}
}
}).start();
}
});
}
}
}

View File

@ -1,144 +0,0 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2010 (C) Sindre Mehus
*/
package org.moire.ultrasonic.view;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
import org.moire.ultrasonic.imageloader.ImageLoader;
import java.util.List;
/**
* This is the adapter for the display of a single list item (song, album, etc)
*
* @author Sindre Mehus
*/
public class EntryAdapter extends ArrayAdapter<Entry>
{
private final Context context;
private final ImageLoader imageLoader;
private final boolean checkable;
public EntryAdapter(Context context, ImageLoader imageLoader, List<Entry> entries, boolean checkable)
{
super(context, android.R.layout.simple_list_item_1, entries);
this.context = context;
this.imageLoader = imageLoader;
this.checkable = checkable;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
Entry entry = getItem(position);
if (entry.isDirectory())
{
AlbumView view;
if (convertView instanceof AlbumView)
{
AlbumView currentView = (AlbumView) convertView;
if (currentView.getEntry().equals(entry))
{
return currentView;
}
else
{
AlbumViewHolder viewHolder = (AlbumViewHolder) currentView.getTag();
view = currentView;
view.setViewHolder(viewHolder);
}
}
else
{
view = new AlbumView(context, imageLoader);
view.setLayout();
}
view.setAlbum(entry);
return view;
}
else
{
SongView view;
if (convertView instanceof SongView)
{
SongView currentView = (SongView) convertView;
if (currentView.getEntry().equals(entry))
{
currentView.update();
return currentView;
}
else
{
SongViewHolder viewHolder = (SongViewHolder) convertView.getTag();
view = currentView;
view.setViewHolder(viewHolder);
}
}
else
{
view = new SongView(context);
view.setLayout(entry);
}
view.setSong(entry, checkable, false);
return view;
}
}
public static class SongViewHolder
{
CheckedTextView check;
TextView track;
TextView title;
TextView status;
TextView artist;
TextView duration;
LinearLayout rating;
ImageView fiveStar1;
ImageView fiveStar2;
ImageView fiveStar3;
ImageView fiveStar4;
ImageView fiveStar5;
ImageView star;
ImageView drag;
}
public static class AlbumViewHolder
{
TextView artist;
ImageView cover_art;
ImageView star;
TextView title;
}
}

View File

@ -1,155 +0,0 @@
package org.moire.ultrasonic.view;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.WeakHashMap;
import timber.log.Timber;
/**
* A View that is periodically refreshed
* @deprecated
* Use LiveData to ensure that the content is up-to-date
**/
public class UpdateView extends LinearLayout
{
private static final WeakHashMap<UpdateView, ?> INSTANCES = new WeakHashMap<UpdateView, Object>();
private static Handler backgroundHandler;
private static Handler uiHandler;
private static Runnable updateRunnable;
public UpdateView(Context context)
{
super(context);
setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
INSTANCES.put(this, null);
startUpdater();
}
@Override
public void setPressed(boolean pressed)
{
}
private static synchronized void startUpdater()
{
if (uiHandler != null)
{
return;
}
uiHandler = new Handler();
updateRunnable = new Runnable()
{
@Override
public void run()
{
updateAll();
}
};
new Thread(new Runnable()
{
@Override
public void run()
{
Thread.currentThread().setName("startUpdater");
Looper.prepare();
backgroundHandler = new Handler(Looper.myLooper());
uiHandler.post(updateRunnable);
Looper.loop();
}
}).start();
}
private static void updateAll()
{
try
{
Collection<UpdateView> views = new ArrayList<UpdateView>();
for (UpdateView view : INSTANCES.keySet())
{
if (view.isShown())
{
views.add(view);
}
}
updateAllLive(views);
}
catch (Throwable x)
{
Timber.w(x, "Error when updating song views.");
}
}
private static void updateAllLive(final Iterable<UpdateView> views)
{
final Runnable runnable = new Runnable()
{
@Override
public void run()
{
try
{
for (UpdateView view : views)
{
view.update();
}
}
catch (Throwable x)
{
Timber.w(x, "Error when updating song views.");
}
uiHandler.postDelayed(updateRunnable, Settings.getViewRefreshInterval());
}
};
backgroundHandler.post(new Runnable()
{
@Override
public void run()
{
try
{
Thread.currentThread().setName("updateAllLive-Background");
for (UpdateView view : views)
{
view.updateBackground();
}
uiHandler.post(runnable);
}
catch (Throwable x)
{
Timber.w(x, "Error when updating song views.");
}
}
});
}
protected void updateBackground()
{
}
protected void update()
{
}
}

View File

@ -54,7 +54,7 @@ class AlbumRowBinder(
val popup = Helper.createPopupMenu(holder.itemView)
popup.setOnMenuItemClickListener { menuItem ->
onContextMenuClick(menuItem, item)
onContextMenuClick(menuItem, item)
}
true
@ -69,7 +69,6 @@ class AlbumRowBinder(
)
}
/**
* Holds the view properties of an Item row
*/
@ -84,7 +83,6 @@ class AlbumRowBinder(
var coverArtId: String? = null
}
/**
* Handles the star / unstar action for an album
*/
@ -118,4 +116,3 @@ class AlbumRowBinder(
return ViewHolder(inflater.inflate(layout, parent, false))
}
}

View File

@ -31,7 +31,7 @@ class ArtistRowBinder(
val onItemClick: (ArtistOrIndex) -> Unit,
val onContextMenuClick: (MenuItem, ArtistOrIndex) -> Boolean,
private val imageLoader: ImageLoader,
): ItemViewBinder<ArtistOrIndex, ArtistRowBinder.ViewHolder>(), KoinComponent {
) : ItemViewBinder<ArtistOrIndex, ArtistRowBinder.ViewHolder>(), KoinComponent {
val layout = R.layout.artist_list_item
val contextMenuLayout = R.menu.artist_context_menu

View File

@ -10,19 +10,20 @@ import android.widget.PopupMenu
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.drakeet.multitype.ItemViewBinder
import java.lang.ref.WeakReference
import org.koin.core.component.KoinComponent
import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.service.RxBus
import java.lang.ref.WeakReference
/**
* This little view shows the currently selected Folder (or catalog) on the music server.
* When clicked it will drop down a list of all available Folders and allow you to
* select one. The intended usage is to supply a filter to lists of artists, albums, etc
*/
class FolderSelectorBinder(context: Context
class FolderSelectorBinder(
context: Context
) : ItemViewBinder<FolderSelectorBinder.FolderHeader, FolderSelectorBinder.ViewHolder>(), KoinComponent {
private val weakContext: WeakReference<Context> = WeakReference(context)
@ -112,7 +113,7 @@ class FolderSelectorBinder(context: Context
data class FolderHeader(
val folders: List<MusicFolder>,
val selected: String?
): Identifiable {
) : Identifiable {
override val id: String
get() = "FOLDERSELECTOR"
@ -123,5 +124,4 @@ class FolderSelectorBinder(context: Context
return longId.compareTo(other.longId)
}
}
}

View File

@ -19,4 +19,4 @@ object Helper {
popup.show()
return popup
}
}
}

View File

@ -1,18 +0,0 @@
package org.moire.ultrasonic.adapters
import com.drakeet.multitype.MultiTypeAdapter
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
import org.moire.ultrasonic.domain.Identifiable
class SectionedAdapter<T : Identifiable> : MultiTypeAdapter(), FastScrollRecyclerView.SectionedAdapter {
override fun getSectionName(position: Int): String {
// var listPosition = if (selectFolderHeader != null) position - 1 else position
//
// // Show the first artist's initial in the popup when the list is
// // scrolled up to the "Select Folder" row
// if (listPosition < 0) listPosition = 0
//
// return getSectionFromName(currentList[listPosition].name ?: " ")
return "X"
}
}

View File

@ -13,7 +13,6 @@ import androidx.lifecycle.MutableLiveData
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
@ -21,7 +20,6 @@ import org.moire.ultrasonic.featureflags.Feature
import org.moire.ultrasonic.featureflags.FeatureStorage
import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.DownloadStatus
import org.moire.ultrasonic.service.MediaPlayerController
import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.service.RxBus
import org.moire.ultrasonic.util.Settings
@ -130,10 +128,10 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
// Minimize or maximize the Text view (if song title is very long)
itemView.setOnLongClickListener {
if (!song.isDirectory) {
maximizeOrMinimize()
true
}
if (!song.isDirectory) {
maximizeOrMinimize()
true
}
false
}
}
@ -152,7 +150,6 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
}
}
private fun setupStarButtons(song: MusicDirectory.Entry) {
if (useFiveStarRating) {
// Hide single star
@ -191,7 +188,6 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
}
}
@Suppress("MagicNumber")
private fun setFiveStars(rating: Int) {
fiveStar1.setImageDrawable(

View File

@ -1,69 +0,0 @@
package org.moire.ultrasonic.adapters.legacy
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.lifecycle.LifecycleOwner
import org.moire.ultrasonic.R
import org.moire.ultrasonic.adapters.ImageHelper
import org.moire.ultrasonic.adapters.TrackViewHolder
import org.moire.ultrasonic.service.DownloadFile
/**
* Legacy bridge to provide Views to a ListView using RecyclerView.ViewHolders
*/
class SongListAdapter(
ctx: Context,
entries: List<DownloadFile?>?,
val lifecycleOwner: LifecycleOwner
) :
ArrayAdapter<DownloadFile?>(ctx, android.R.layout.simple_list_item_1, entries!!) {
val layout = R.layout.song_list_item
private val imageHelper: ImageHelper = ImageHelper(context)
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val downloadFile = getItem(position)!!
var view = convertView
val holder: TrackViewHolder
if (view == null) {
val inflater = LayoutInflater.from(context)
view = inflater.inflate(layout, parent, false)
}
if (view?.tag is TrackViewHolder) {
holder = view.tag as TrackViewHolder
} else {
holder = TrackViewHolder(view!!)
view.tag = holder
}
holder.imageHelper = imageHelper
holder.setSong(
file = downloadFile,
checkable = false,
draggable = true
)
// Observe download status
downloadFile.status.observe(
lifecycleOwner,
{
holder.updateStatus(it)
}
)
downloadFile.progress.observe(
lifecycleOwner,
{
holder.updateProgress(it)
}
)
return view
}
}

View File

@ -73,7 +73,6 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Entry>() {
addOnScrollListener(scrollListener)
}
viewAdapter.register(
AlbumRowBinder(
{ entry -> onItemClick(entry) },
@ -82,8 +81,6 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Entry>() {
context = requireContext()
)
)
}
override fun onItemClick(item: MusicDirectory.Entry) {
@ -94,5 +91,4 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Entry>() {
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.parent)
findNavController().navigate(itemClickTarget, bundle)
}
}

View File

@ -11,7 +11,6 @@ import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.ArtistOrIndex
import org.moire.ultrasonic.model.ArtistListModel
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Settings
/**
* Displays the list of Artists from the media library
@ -44,7 +43,6 @@ class ArtistListFragment : EntryListFragment<ArtistOrIndex>() {
*/
override val itemClickTarget = R.id.selectArtistToSelectAlbum
/**
* The central function to pass a query to the model and return a LiveData object
*/
@ -78,6 +76,5 @@ class ArtistListFragment : EntryListFragment<ArtistOrIndex>() {
findNavController().navigate(itemClickTarget, bundle)
}
//Constants.ALPHABETICAL_BY_NAME
// Constants.ALPHABETICAL_BY_NAME
}

View File

@ -26,8 +26,6 @@ class BookmarksFragment : TrackCollectionFragment() {
// Why?
selectButton?.visibility = View.GONE
playNextButton?.visibility = View.GONE
playLastButton?.visibility = View.GONE
moreButton?.visibility = View.GONE
}
@ -41,26 +39,14 @@ class BookmarksFragment : TrackCollectionFragment() {
}
override fun enableButtons(selection: List<MusicDirectory.Entry>) {
val enabled = selection.isNotEmpty()
var unpinEnabled = false
var deleteEnabled = false
var pinnedCount = 0
for (song in selection) {
val downloadFile = mediaPlayerController.getDownloadFileForSong(song)
if (downloadFile.isWorkDone) {
deleteEnabled = true
}
if (downloadFile.isSaved) {
pinnedCount++
unpinEnabled = true
}
}
playNowButton?.isVisible = (enabled && deleteEnabled)
pinButton?.isVisible = (enabled && !isOffline() && selection.size > pinnedCount)
unpinButton!!.isVisible = (enabled && unpinEnabled)
downloadButton!!.isVisible = (enabled && !deleteEnabled && !isOffline())
deleteButton!!.isVisible = (enabled && deleteEnabled)
super.enableButtons(selection)
}
}

View File

@ -24,7 +24,7 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
// FIXME
fun showFolderHeader(): Boolean {
return listModel.showSelectFolderHeader(arguments) &&
!listModel.isOffline() && !Settings.shouldUseId3Tags
!listModel.isOffline() && !Settings.shouldUseId3Tags
}
@Suppress("LongMethod")

View File

@ -24,7 +24,6 @@ import org.moire.ultrasonic.subsonic.DownloadHandler
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.SelectMusicFolderView
/**
* An abstract Model, which can be extended to display a list of items of type T from the API
@ -38,7 +37,6 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
protected var refreshListView: SwipeRefreshLayout? = null
internal var listView: RecyclerView? = null
internal lateinit var viewManager: LinearLayoutManager
internal var selectFolderHeader: SelectMusicFolderView? = null
/**
* The Adapter for the RecyclerView
@ -162,10 +160,9 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
try {
bundle = arguments?.clone() as Bundle
} catch (ignored: Exception) {
bundle = Bundle()
bundle = Bundle()
}
return bundle
}
}

View File

@ -25,6 +25,7 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.Navigation
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.util.Collections
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
@ -48,7 +49,6 @@ import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import timber.log.Timber
import java.util.Collections
/**
* Displays a group of tracks, eg. the songs of an album, of a playlist etc.
@ -371,7 +371,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
}
}
val isArtist = arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, false)?: false
val isArtist = arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, false) ?: false
// FIXME WHICH id if no arguments?
val id = arguments?.getString(Constants.INTENT_EXTRA_NAME_ID)
@ -570,7 +570,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
moreButton!!.visibility = View.GONE
} else {
moreButton!!.visibility = View.VISIBLE
if (arguments?.getInt(Constants.INTENT_EXTRA_NAME_RANDOM, 0) ?:0 > 0) {
if (arguments?.getInt(Constants.INTENT_EXTRA_NAME_RANDOM, 0) ?: 0 > 0) {
moreButton!!.setOnClickListener {
val offset = requireArguments().getInt(
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
@ -594,7 +594,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
val isAlbumList = arguments?.containsKey(
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE
)?:false
) ?: false
playAllButtonVisible = !(isAlbumList || entryList.isEmpty()) && !allVideos
shareButtonVisible = !isOffline() && songCount > 0
@ -615,11 +615,11 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
viewAdapter.submitList(entryList)
}
val playAll = arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false)?:false
val playAll = arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false) ?: false
if (playAll && songCount > 0) {
playAll(
arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)?:false,
arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false) ?: false,
false
)
}

View File

@ -14,8 +14,6 @@ import org.moire.ultrasonic.util.Settings
class AlbumListModel(application: Application) : GenericListModel(application) {
val list: MutableLiveData<List<MusicDirectory.Entry>> = MutableLiveData(listOf())
var lastType: String? = null
private var loadedUntil: Int = 0
@ -38,28 +36,28 @@ class AlbumListModel(application: Application) : GenericListModel(application) {
fun getAlbumsOfArtist(musicService: MusicService, refresh: Boolean, id: String, name: String?) {
var root = MusicDirectory()
val musicDirectory = musicService.getArtist(id, name, refresh)
var root = MusicDirectory()
val musicDirectory = musicService.getArtist(id, name, refresh)
if (Settings.shouldShowAllSongsByArtist &&
musicDirectory.findChild(allSongsId) == null &&
hasOnlyFolders(musicDirectory)
) {
val allSongs = MusicDirectory.Entry(allSongsId)
if (Settings.shouldShowAllSongsByArtist &&
musicDirectory.findChild(allSongsId) == null &&
hasOnlyFolders(musicDirectory)
) {
val allSongs = MusicDirectory.Entry(allSongsId)
allSongs.isDirectory = true
allSongs.artist = name
allSongs.parent = id
allSongs.title = String.format(
context.resources.getString(R.string.select_album_all_songs), name
)
allSongs.isDirectory = true
allSongs.artist = name
allSongs.parent = id
allSongs.title = String.format(
context.resources.getString(R.string.select_album_all_songs), name
)
root.addFirst(allSongs)
root.addAll(musicDirectory.getChildren())
} else {
root = musicDirectory
}
list.postValue(root.getChildren())
root.addFirst(allSongs)
root.addAll(musicDirectory.getChildren())
} else {
root = musicDirectory
}
list.postValue(root.getChildren())
}
override fun load(
@ -138,5 +136,4 @@ class AlbumListModel(application: Application) : GenericListModel(application) {
albumListType != "highest" && albumListType != "recent" &&
albumListType != "frequent"
}
}

View File

@ -6,8 +6,6 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import kotlinx.coroutines.Dispatchers
@ -18,7 +16,6 @@ import org.koin.core.component.inject
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.data.ServerSetting
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.service.MusicService
import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.util.CommunicationError
@ -109,11 +106,10 @@ open class GenericListModel(application: Application) :
) {
// Update the list of available folders if enabled
if (showSelectFolderHeader(args) && !isOffline && !useId3Tags) {
//FIXME
// FIXME
}
}
/**
* Some shared helper functions
*/
@ -121,8 +117,7 @@ open class GenericListModel(application: Application) :
// Returns true if the directory contains only folders
internal fun hasOnlyFolders(musicDirectory: MusicDirectory) =
musicDirectory.getChildren(includeDirs = true, includeFiles = false).size ==
musicDirectory.getChildren(includeDirs = true, includeFiles = true).size
musicDirectory.getChildren(includeDirs = true, includeFiles = true).size
internal val allSongsId = "-1"
}

View File

@ -2,26 +2,15 @@ package org.moire.ultrasonic.model
import android.app.Application
import android.os.Bundle
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.SearchCriteria
import org.moire.ultrasonic.domain.SearchResult
import org.moire.ultrasonic.fragment.SearchFragment
import org.moire.ultrasonic.service.MusicService
import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.util.BackgroundTask
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.FragmentBackgroundTask
import org.moire.ultrasonic.util.MergeAdapter
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.view.ArtistAdapter
import org.moire.ultrasonic.view.EntryAdapter
import java.util.ArrayList
class SearchListModel(application: Application) : GenericListModel(application) {
@ -35,11 +24,8 @@ class SearchListModel(application: Application) : GenericListModel(application)
args: Bundle
) {
super.load(isOffline, useId3Tags, musicService, refresh, args)
}
suspend fun search(query: String) {
val maxArtists = Settings.maxArtists
val maxAlbums = Settings.maxAlbums
@ -69,5 +55,4 @@ class SearchListModel(application: Application) : GenericListModel(application)
// list.add(result.songs)
// return list
// }
}
}

View File

@ -8,14 +8,12 @@
package org.moire.ultrasonic.model
import android.app.Application
import android.os.Bundle
import androidx.lifecycle.MutableLiveData
import java.util.LinkedList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.service.MusicService
import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
@ -82,7 +80,6 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
}
}
// Given a Music directory "songs" it recursively adds all children to "songs"
private fun getSongsRecursively(
parent: MusicDirectory,
@ -257,5 +254,4 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
private fun updateList(root: MusicDirectory) {
currentList.postValue(root.getChildren())
}
}

View File

@ -78,7 +78,6 @@ class RxBus {
val skipToQueueItemCommandObservable: Observable<Long> =
skipToQueueItemCommandPublisher.observeOn(AndroidSchedulers.mainThread())
fun releaseMediaSessionToken() {
mediaSessionTokenPublisher = PublishSubject.create()
}

View File

@ -1,87 +0,0 @@
package org.moire.ultrasonic.view
import android.content.Context
import android.view.MenuItem
import android.view.View
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.MusicFolder
/**
* This little view shows the currently selected Folder (or catalog) on the music server.
* When clicked it will drop down a list of all available Folders and allow you to
* select one. The intended usage is to supply a filter to lists of artists, albums, etc
*/
class SelectMusicFolderView(
private val context: Context,
view: View,
private val onUpdate: (String?) -> Unit
) : RecyclerView.ViewHolder(view) {
private var musicFolders: List<MusicFolder> = mutableListOf()
private var selectedFolderId: String? = null
private val folderName: TextView = itemView.findViewById(R.id.select_folder_name)
private val layout: LinearLayout = itemView.findViewById(R.id.select_folder_header)
init {
folderName.text = context.getString(R.string.select_artist_all_folders)
layout.setOnClickListener { onFolderClick() }
}
fun setData(selectedId: String?, folders: List<MusicFolder>) {
selectedFolderId = selectedId
musicFolders = folders
if (selectedFolderId != null) {
for ((id, name) in musicFolders) {
if (id == selectedFolderId) {
folderName.text = name
break
}
}
} else {
folderName.text = context.getString(R.string.select_artist_all_folders)
}
}
private fun onFolderClick() {
val popup = PopupMenu(context, layout)
var menuItem = popup.menu.add(
MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders
)
if (selectedFolderId == null || selectedFolderId!!.isEmpty()) {
menuItem.isChecked = true
}
musicFolders.forEachIndexed { i, musicFolder ->
val (id, name) = musicFolder
menuItem = popup.menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, name)
if (id == selectedFolderId) {
menuItem.isChecked = true
}
}
popup.menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true)
popup.setOnMenuItemClickListener { item -> onFolderMenuItemSelected(item) }
popup.show()
}
private fun onFolderMenuItemSelected(menuItem: MenuItem): Boolean {
val selectedFolder = if (menuItem.itemId == -1) null else musicFolders[menuItem.itemId]
val musicFolderName = selectedFolder?.name
?: context.getString(R.string.select_artist_all_folders)
selectedFolderId = selectedFolder?.id
menuItem.isChecked = true
folderName.text = musicFolderName
onUpdate(selectedFolderId)
return true
}
companion object {
const val MENU_GROUP_MUSIC_FOLDER = 10
}
}

View File

@ -1,393 +0,0 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2020 (C) Jozsef Varga
*/
package org.moire.ultrasonic.view
import android.content.Context
import android.graphics.drawable.AnimationDrawable
import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.view.LayoutInflater
import android.widget.Checkable
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.Companion.isOffline
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.featureflags.Feature
import org.moire.ultrasonic.featureflags.FeatureStorage
import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.MediaPlayerController
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.EntryAdapter.SongViewHolder
import timber.log.Timber
/**
* Used to display songs and videos in a `ListView`.
*/
class SongView(context: Context) : UpdateView(context), Checkable, KoinComponent {
var entry: MusicDirectory.Entry? = 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 downloadFile: DownloadFile? = null
private var playing = false
private var viewHolder: SongViewHolder? = null
private val features: FeatureStorage = get()
private val useFiveStarRating: Boolean = features.isFeatureEnabled(Feature.FIVE_STAR_RATING)
private val mediaPlayerController: MediaPlayerController by inject()
fun setLayout(song: MusicDirectory.Entry) {
inflater?.inflate(
if (song.isVideo) R.layout.video_list_item
else R.layout.song_list_item,
this,
true
)
viewHolder = SongViewHolder()
viewHolder!!.check = findViewById(R.id.song_check)
viewHolder!!.rating = findViewById(R.id.song_rating)
viewHolder!!.fiveStar1 = findViewById(R.id.song_five_star_1)
viewHolder!!.fiveStar2 = findViewById(R.id.song_five_star_2)
viewHolder!!.fiveStar3 = findViewById(R.id.song_five_star_3)
viewHolder!!.fiveStar4 = findViewById(R.id.song_five_star_4)
viewHolder!!.fiveStar5 = findViewById(R.id.song_five_star_5)
viewHolder!!.star = findViewById(R.id.song_star)
viewHolder!!.drag = findViewById(R.id.song_drag)
viewHolder!!.track = findViewById(R.id.song_track)
viewHolder!!.title = findViewById(R.id.song_title)
viewHolder!!.artist = findViewById(R.id.song_artist)
viewHolder!!.duration = findViewById(R.id.song_duration)
viewHolder!!.status = findViewById(R.id.song_status)
tag = viewHolder
}
fun setViewHolder(viewHolder: SongViewHolder?) {
this.viewHolder = viewHolder
tag = this.viewHolder
}
fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean) {
updateBackground()
entry = song
downloadFile = mediaPlayerController.getDownloadFileForSong(song)
val artist = StringBuilder(60)
var bitRate: String? = null
if (song.bitRate != null)
bitRate = String.format(
this.context.getString(R.string.song_details_kbps), song.bitRate
)
val fileFormat: String?
val suffix = song.suffix
val transcodedSuffix = song.transcodedSuffix
fileFormat = if (
TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo
) suffix else String.format("%s > %s", suffix, transcodedSuffix)
val artistName = song.artist
if (artistName != null) {
if (Settings.shouldDisplayBitrateWithArtist) {
artist.append(artistName).append(" (").append(
String.format(
this.context.getString(R.string.song_details_all),
if (bitRate == null) "" else String.format("%s ", bitRate), fileFormat
)
).append(')')
} else {
artist.append(artistName)
}
}
val trackNumber = song.track ?: 0
if (Settings.shouldShowTrackNumber && trackNumber != 0) {
viewHolder?.track?.text = String.format("%02d.", trackNumber)
} else {
viewHolder?.track?.visibility = GONE
}
val title = StringBuilder(60)
title.append(song.title)
if (song.isVideo && Settings.shouldDisplayBitrateWithArtist) {
title.append(" (").append(
String.format(
this.context.getString(R.string.song_details_all),
if (bitRate == null) "" else String.format("%s ", bitRate), fileFormat
)
).append(')')
}
viewHolder?.title?.text = title
viewHolder?.artist?.text = artist
val duration = song.duration
if (duration != null) {
viewHolder?.duration?.text = Util.formatTotalDuration(duration.toLong())
}
viewHolder?.check?.visibility = if (checkable && !song.isVideo) VISIBLE else GONE
viewHolder?.drag?.visibility = if (draggable) VISIBLE else GONE
if (isOffline()) {
viewHolder?.star?.visibility = GONE
viewHolder?.rating?.visibility = GONE
} else {
if (useFiveStarRating) {
viewHolder?.star?.visibility = GONE
val rating = if (song.userRating == null) 0 else song.userRating!!
viewHolder?.fiveStar1?.setImageDrawable(
if (rating > 0) starDrawable else starHollowDrawable
)
viewHolder?.fiveStar2?.setImageDrawable(
if (rating > 1) starDrawable else starHollowDrawable
)
viewHolder?.fiveStar3?.setImageDrawable(
if (rating > 2) starDrawable else starHollowDrawable
)
viewHolder?.fiveStar4?.setImageDrawable(
if (rating > 3) starDrawable else starHollowDrawable
)
viewHolder?.fiveStar5?.setImageDrawable(
if (rating > 4) starDrawable else starHollowDrawable
)
} else {
viewHolder?.rating?.visibility = GONE
viewHolder?.star?.setImageDrawable(
if (song.starred) starDrawable else starHollowDrawable
)
viewHolder?.star?.setOnClickListener {
val isStarred = song.starred
val id = song.id
if (!isStarred) {
viewHolder?.star?.setImageDrawable(starDrawable)
song.starred = true
} else {
viewHolder?.star?.setImageDrawable(starHollowDrawable)
song.starred = false
}
Thread {
val musicService = getMusicService()
try {
if (!isStarred) {
musicService.star(id, null, null)
} else {
musicService.unstar(id, null, null)
}
} catch (e: Exception) {
Timber.e(e)
}
}.start()
}
}
}
update()
}
override fun updateBackground() {}
@Synchronized
public override fun update() {
updateBackground()
val song = entry ?: return
downloadFile = mediaPlayerController.getDownloadFileForSong(song)
updateDownloadStatus(downloadFile!!)
if (entry?.starred != true) {
if (viewHolder?.star?.drawable !== starHollowDrawable) {
viewHolder?.star?.setImageDrawable(starHollowDrawable)
}
} else {
if (viewHolder?.star?.drawable !== starDrawable) {
viewHolder?.star?.setImageDrawable(starDrawable)
}
}
val rating = entry?.userRating ?: 0
viewHolder?.fiveStar1?.setImageDrawable(
if (rating > 0) starDrawable else starHollowDrawable
)
viewHolder?.fiveStar2?.setImageDrawable(
if (rating > 1) starDrawable else starHollowDrawable
)
viewHolder?.fiveStar3?.setImageDrawable(
if (rating > 2) starDrawable else starHollowDrawable
)
viewHolder?.fiveStar4?.setImageDrawable(
if (rating > 3) starDrawable else starHollowDrawable
)
viewHolder?.fiveStar5?.setImageDrawable(
if (rating > 4) starDrawable else starHollowDrawable
)
val playing = mediaPlayerController.currentPlaying === downloadFile
if (playing) {
if (!this.playing) {
this.playing = true
viewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
playingImage, null, null, null
)
}
} else {
if (this.playing) {
this.playing = false
viewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
0, 0, 0, 0
)
}
}
}
private fun updateDownloadStatus(downloadFile: DownloadFile) {
if (downloadFile.isWorkDone) {
val newLeftImageType =
if (downloadFile.isSaved) ImageType.Pin else ImageType.Downloaded
if (leftImageType != newLeftImageType) {
leftImage = if (downloadFile.isSaved) pinImage else downloadedImage
leftImageType = newLeftImageType
}
} else {
leftImageType = ImageType.None
leftImage = null
}
val rightImageType: ImageType
val rightImage: Drawable?
if (downloadFile.isDownloading && !downloadFile.isDownloadCancelled) {
viewHolder?.status?.text = Util.formatPercentage(downloadFile.progress.value!!)
rightImageType = ImageType.Downloading
rightImage = downloadingImage
} else {
rightImageType = ImageType.None
rightImage = null
val statusText = viewHolder?.status?.text
if (!statusText.isNullOrEmpty()) viewHolder?.status?.text = null
}
if (previousLeftImageType != leftImageType || previousRightImageType != rightImageType) {
previousLeftImageType = leftImageType
previousRightImageType = rightImageType
if (viewHolder?.status != null) {
viewHolder?.status?.setCompoundDrawablesWithIntrinsicBounds(
leftImage, null, rightImage, null
)
if (rightImage === downloadingImage) {
val frameAnimation = rightImage as AnimationDrawable?
frameAnimation!!.setVisible(true, true)
frameAnimation.start()
}
}
}
}
override fun setChecked(b: Boolean) {
viewHolder?.check?.isChecked = b
}
override fun isChecked(): Boolean {
return viewHolder?.check?.isChecked ?: false
}
override fun toggle() {
viewHolder?.check?.toggle()
}
fun maximizeOrMinimize() {
isMaximized = !isMaximized
viewHolder?.title?.isSingleLine = !isMaximized
viewHolder?.artist?.isSingleLine = !isMaximized
}
enum class ImageType {
None, Pin, Downloaded, Downloading
}
companion object {
private var starHollowDrawable: Drawable? = null
private var starDrawable: Drawable? = null
var pinImage: Drawable? = null
var downloadedImage: Drawable? = null
var downloadingImage: Drawable? = null
private var playingImage: Drawable? = null
private var theme: String? = null
private var inflater: LayoutInflater? = null
}
init {
val theme = Settings.theme
val themesMatch = theme == Companion.theme
inflater = LayoutInflater.from(this.context)
if (!themesMatch) Companion.theme = theme
if (starHollowDrawable == null || !themesMatch) {
starHollowDrawable = Util.getDrawableFromAttribute(context, R.attr.star_hollow)
}
if (starDrawable == null || !themesMatch) {
starDrawable = Util.getDrawableFromAttribute(context, R.attr.star_full)
}
if (pinImage == null || !themesMatch) {
pinImage = Util.getDrawableFromAttribute(context, R.attr.pin)
}
if (downloadedImage == null || !themesMatch) {
downloadedImage = Util.getDrawableFromAttribute(context, R.attr.downloaded)
}
if (downloadingImage == null || !themesMatch) {
downloadingImage = Util.getDrawableFromAttribute(context, R.attr.downloading)
}
if (playingImage == null || !themesMatch) {
playingImage = Util.getDrawableFromAttribute(context, R.attr.media_play_small)
}
}
}

View File

@ -1,316 +0,0 @@
// 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
// //
// // 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
// }
//
//
// }