Fixed search, put compareTo method into Interface

This commit is contained in:
tzugen 2021-11-30 20:53:10 +01:00
parent bdac092eff
commit f1e789ea9b
No known key found for this signature in database
GPG Key ID: 61E9C34BC10EC930
23 changed files with 117 additions and 233 deletions

View File

@ -11,21 +11,4 @@ data class Artist(
override var coverArt: String? = null, override var coverArt: String? = null,
override var albumCount: Long? = null, override var albumCount: Long? = null,
override var closeness: Int = 0 override var closeness: Int = 0
) : ArtistOrIndex(id) { ) : ArtistOrIndex(id)
fun compareTo(other: Artist): Int {
when {
this.closeness == other.closeness -> {
return 0
}
this.closeness > other.closeness -> {
return -1
}
else -> {
return 1
}
}
}
override fun compareTo(other: Identifiable) = compareTo(other as Artist)
}

View File

@ -15,4 +15,21 @@ abstract class ArtistOrIndex(
open var albumCount: Long? = null, open var albumCount: Long? = null,
@Ignore @Ignore
open var closeness: Int = 0 open var closeness: Int = 0
) : GenericEntry() ) : GenericEntry() {
fun compareTo(other: ArtistOrIndex): Int {
when {
this.closeness == other.closeness -> {
return 0
}
this.closeness > other.closeness -> {
return -1
}
else -> {
return 1
}
}
}
override fun compareTo(other: Identifiable) = compareTo(other as ArtistOrIndex)
}

View File

@ -3,19 +3,17 @@ package org.moire.ultrasonic.domain
import androidx.room.Ignore import androidx.room.Ignore
abstract class GenericEntry : Identifiable { abstract class GenericEntry : Identifiable {
abstract override val id: String
@Ignore @Ignore
open val name: String? = null open val name: String? = null
override fun compareTo(other: Identifiable): Int {
return this.id.toInt().compareTo(other.id.toInt())
}
@delegate:Ignore
override val longId: Long by lazy {
id.hashCode().toLong()
}
} }
interface Identifiable : Comparable<Identifiable> { interface Identifiable : Comparable<Identifiable> {
val id: String val id: String
val longId: Long val longId: Long
get() = id.hashCode().toLong()
override fun compareTo(other: Identifiable): Int {
return longId.compareTo(other.longId)
}
} }

View File

@ -32,7 +32,7 @@ class MusicDirectory : ArrayList<MusicDirectory.Child>() {
} }
} }
abstract class Child : Identifiable, GenericEntry() { abstract class Child : GenericEntry() {
abstract override var id: String abstract override var id: String
abstract var parent: String? abstract var parent: String?
abstract var isDirectory: Boolean abstract var isDirectory: Boolean

View File

@ -7,7 +7,7 @@ import org.moire.ultrasonic.domain.MusicDirectory.Entry
* The result of a search. Contains matching artists, albums and songs. * The result of a search. Contains matching artists, albums and songs.
*/ */
data class SearchResult( data class SearchResult(
val artists: List<Artist> = listOf(), val artists: List<ArtistOrIndex> = listOf(),
val albums: List<Album> = listOf(), val albums: List<Album> = listOf(),
val songs: List<Entry> = listOf() val songs: List<Entry> = listOf()
) )

View File

@ -7,8 +7,8 @@ data class Album(
val id: String = "", val id: String = "",
val parent: String = "", val parent: String = "",
val album: String = "", val album: String = "",
val title: String = "", val title: String? = null,
val name: String = "", val name: String? = null,
val discNumber: Int = 0, val discNumber: Int = 0,
val coverArt: String = "", val coverArt: String = "",
val songCount: Int = 0, val songCount: Int = 0,

View File

@ -2,7 +2,8 @@ org.gradle.parallel=true
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.configureondemand=true org.gradle.configureondemand=true
org.gradle.caching=true org.gradle.caching=true
org.gradle.jvmargs=-Xmx2g org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC
kotlin.incremental=true kotlin.incremental=true
kotlin.caching.enabled=true kotlin.caching.enabled=true

View File

@ -1,117 +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.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.SectionIndexer;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.Artist;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
/**
* @author Sindre Mehus
*/
public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexer
{
private final LayoutInflater layoutInflater;
// Both arrays are indexed by section ID.
private final Object[] sections;
private final Integer[] positions;
public ArtistAdapter(Context context, List<Artist> artists)
{
super(context, R.layout.list_item_generic, artists);
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Collection<String> sectionSet = new LinkedHashSet<String>(30);
List<Integer> positionList = new ArrayList<Integer>(30);
for (int i = 0; i < artists.size(); i++)
{
Artist artist = artists.get(i);
String index = artist.getIndex();
if (!sectionSet.contains(index))
{
sectionSet.add(index);
positionList.add(i);
}
}
sections = sectionSet.toArray(new Object[0]);
positions = positionList.toArray(new Integer[0]);
}
@NonNull
@Override
public View getView(
int position,
@Nullable View convertView,
@NonNull ViewGroup parent
) {
View rowView = convertView;
if (rowView == null) {
rowView = layoutInflater.inflate(R.layout.list_item_generic, parent, false);
}
((TextView) rowView).setText(getItem(position).getName());
return rowView;
}
@Override
public Object[] getSections()
{
return sections;
}
@Override
public int getPositionForSection(int section)
{
return positions.length > section ? positions[section] : 0;
}
@Override
public int getSectionForPosition(int pos)
{
for (int i = 0; i < sections.length - 1; i++)
{
if (pos < positions[i + 1])
{
return i;
}
}
return sections.length - 1;
}
}

View File

@ -88,8 +88,4 @@ class AlbumHeader(
override val longId: Long override val longId: Long
get() = -1L get() = -1L
override fun compareTo(other: Identifiable): Int {
return this.longId.compareTo(other.longId)
}
} }

View File

@ -52,8 +52,6 @@ class BaseAdapter<T : Identifiable> : MultiTypeAdapter() {
return mDiffer.currentList[position] return mDiffer.currentList[position]
} }
// override getIt
override var items: List<Any> override var items: List<Any>
get() = getCurrentList() get() = getCurrentList()
set(value) { set(value) {

View File

@ -41,9 +41,5 @@ class DividerBinder : ItemViewBinder<DividerBinder.Divider, DividerBinder.ViewHo
data class Divider(val stringId: Int) : Identifiable { data class Divider(val stringId: Int) : Identifiable {
override val id: String override val id: String
get() = stringId.toString() get() = stringId.toString()
override val longId: Long
get() = stringId.toLong()
override fun compareTo(other: Identifiable): Int = longId.compareTo(other.longId)
} }
} }

View File

@ -128,9 +128,5 @@ class FolderSelectorBinder(context: Context) :
override val longId: Long override val longId: Long
get() = -1L get() = -1L
override fun compareTo(other: Identifiable): Int {
return longId.compareTo(other.longId)
}
} }
} }

View File

@ -3,7 +3,6 @@ package org.moire.ultrasonic.adapters
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.drakeet.multitype.ItemViewBinder import com.drakeet.multitype.ItemViewBinder
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
@ -37,14 +36,9 @@ class MoreButtonBinder : ItemViewBinder<MoreButtonBinder.MoreButton, RecyclerVie
data class MoreButton( data class MoreButton(
val stringId: Int, val stringId: Int,
val onClick: (() -> Unit) val onClick: (() -> Unit)
): Identifiable { ) : Identifiable {
override val id: String override val id: String
get() = stringId.toString() get() = stringId.toString()
override val longId: Long
get() = stringId.toLong()
override fun compareTo(other: Identifiable): Int = longId.compareTo(other.longId)
} }
} }

View File

@ -7,7 +7,7 @@ import org.moire.ultrasonic.api.subsonic.models.Album
fun Album.toDomainEntity(): MusicDirectory.Album = MusicDirectory.Album( fun Album.toDomainEntity(): MusicDirectory.Album = MusicDirectory.Album(
id = this@toDomainEntity.id, id = this@toDomainEntity.id,
title = this@toDomainEntity.title, title = this@toDomainEntity.name ?: this@toDomainEntity.title,
album = this@toDomainEntity.album, album = this@toDomainEntity.album,
coverArt = this@toDomainEntity.coverArt, coverArt = this@toDomainEntity.coverArt,
artist = this@toDomainEntity.artist, artist = this@toDomainEntity.artist,

View File

@ -9,15 +9,12 @@ package org.moire.ultrasonic.fragment
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.adapters.AlbumRowBinder import org.moire.ultrasonic.adapters.AlbumRowBinder
import org.moire.ultrasonic.adapters.FolderSelectorBinder
import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.model.AlbumListModel import org.moire.ultrasonic.model.AlbumListModel
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
@ -40,7 +37,10 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Album>() {
/** /**
* The central function to pass a query to the model and return a LiveData object * The central function to pass a query to the model and return a LiveData object
*/ */
override fun getLiveData(args: Bundle?, refresh: Boolean): LiveData<List<MusicDirectory.Album>> { override fun getLiveData(
args: Bundle?,
refresh: Boolean
): LiveData<List<MusicDirectory.Album>> {
if (args == null) throw IllegalArgumentException("Required arguments are missing") if (args == null) throw IllegalArgumentException("Required arguments are missing")
val refresh = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH) || refresh val refresh = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH) || refresh

View File

@ -2,25 +2,20 @@ package org.moire.ultrasonic.fragment
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.adapters.ArtistRowBinder import org.moire.ultrasonic.adapters.ArtistRowBinder
import org.moire.ultrasonic.adapters.FolderSelectorBinder
import org.moire.ultrasonic.domain.Artist import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.ArtistOrIndex import org.moire.ultrasonic.domain.ArtistOrIndex
import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.domain.Index import org.moire.ultrasonic.domain.Index
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.model.ArtistListModel import org.moire.ultrasonic.model.ArtistListModel
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
/** /**
* Displays the list of Artists from the media library * Displays the list of Artists or Indexes (folders) from the media library
*
* FIXME: FOLDER HEADER NOT POPULATED ON FIST LOAD
*/ */
class ArtistListFragment : EntryListFragment<ArtistOrIndex>() { class ArtistListFragment : EntryListFragment<ArtistOrIndex>() {
@ -60,23 +55,32 @@ class ArtistListFragment : EntryListFragment<ArtistOrIndex>() {
* If we are showing artists, we need to go to AlbumList * If we are showing artists, we need to go to AlbumList
*/ */
override fun onItemClick(item: ArtistOrIndex) { override fun onItemClick(item: ArtistOrIndex) {
val bundle = Bundle() Companion.onItemClick(item, findNavController())
}
// Common arguments companion object {
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, item.id) fun onItemClick(item: ArtistOrIndex, navController: NavController) {
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, item.name) val bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.id)
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, (item is Artist))
// Check type // Common arguments
if (item is Index) { bundle.putString(Constants.INTENT_EXTRA_NAME_ID, item.id)
findNavController().navigate(R.id.artistsListToTrackCollection, bundle) bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, item.name)
} else { bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.id)
bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, Constants.ALBUMS_OF_ARTIST) bundle.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, (item is Artist))
bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, item.name)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 1000) // Check type
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0) if (item is Index) {
findNavController().navigate(R.id.artistsListToAlbumsList, bundle) navController.navigate(R.id.artistsListToTrackCollection, bundle)
} else {
bundle.putString(
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE,
Constants.ALBUMS_OF_ARTIST
)
bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, item.name)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 1000)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0)
navController.navigate(R.id.artistsListToAlbumsList, bundle)
}
} }
} }
} }

View File

@ -9,7 +9,6 @@ import androidx.navigation.fragment.findNavController
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.adapters.FolderSelectorBinder import org.moire.ultrasonic.adapters.FolderSelectorBinder
import org.moire.ultrasonic.domain.Artist import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.ArtistOrIndex
import org.moire.ultrasonic.domain.GenericEntry import org.moire.ultrasonic.domain.GenericEntry
import org.moire.ultrasonic.domain.Identifiable import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.service.RxBus import org.moire.ultrasonic.service.RxBus
@ -50,6 +49,10 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// Call a cheap function on ServerSettingsModel to make sure it is initialized by Koin,
// because it can't be initialized from inside the callback
serverSettingsModel.toString()
RxBus.musicFolderChangedEventObservable.subscribe { RxBus.musicFolderChangedEventObservable.subscribe {
if (!listModel.isOffline()) { if (!listModel.isOffline()) {
val currentSetting = listModel.activeServer val currentSetting = listModel.activeServer

View File

@ -3,17 +3,16 @@ package org.moire.ultrasonic.fragment
import android.app.SearchManager import android.app.SearchManager
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.ListAdapter
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.navigation.Navigation import androidx.navigation.Navigation
import androidx.navigation.fragment.findNavController
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
@ -26,7 +25,9 @@ import org.moire.ultrasonic.adapters.MoreButtonBinder
import org.moire.ultrasonic.adapters.MoreButtonBinder.MoreButton import org.moire.ultrasonic.adapters.MoreButtonBinder.MoreButton
import org.moire.ultrasonic.adapters.TrackViewBinder import org.moire.ultrasonic.adapters.TrackViewBinder
import org.moire.ultrasonic.domain.Artist import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.ArtistOrIndex
import org.moire.ultrasonic.domain.Identifiable import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.domain.Index
import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.SearchResult import org.moire.ultrasonic.domain.SearchResult
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
@ -41,12 +42,10 @@ import org.moire.ultrasonic.util.CommunicationError
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util.toast import org.moire.ultrasonic.util.Util.toast
import org.moire.ultrasonic.view.ArtistAdapter
import timber.log.Timber import timber.log.Timber
/** /**
* Initiates a search on the media library and displays the results * Initiates a search on the media library and displays the results
* FIXME: Artist click, display
*/ */
class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent { class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
private var searchResult: SearchResult? = null private var searchResult: SearchResult? = null
@ -265,11 +264,28 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
populateList(listModel.trimResultLength(searchResult!!, maxSongs = Int.MAX_VALUE)) populateList(listModel.trimResultLength(searchResult!!, maxSongs = Int.MAX_VALUE))
} }
private fun onArtistSelected(artist: Artist) { private fun onArtistSelected(item: ArtistOrIndex) {
val bundle = Bundle() val bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id)
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.id) // Common arguments
Navigation.findNavController(requireView()).navigate(R.id.searchToSelectAlbum, bundle) bundle.putString(Constants.INTENT_EXTRA_NAME_ID, item.id)
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, item.name)
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.id)
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, (item is Artist))
// Check type
if (item is Index) {
findNavController().navigate(R.id.searchToTrackCollection, bundle)
} else {
bundle.putString(
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE,
Constants.ALBUMS_OF_ARTIST
)
bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, item.name)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 1000)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0)
findNavController().navigate(R.id.searchToAlbumsList, bundle)
}
} }
private fun onAlbumSelected(album: MusicDirectory.Album, autoplay: Boolean) { private fun onAlbumSelected(album: MusicDirectory.Album, autoplay: Boolean) {
@ -278,14 +294,21 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, album.title) bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, album.title)
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, album.isDirectory) bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, album.isDirectory)
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoplay) bundle.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoplay)
Navigation.findNavController(requireView()).navigate(R.id.searchToSelectAlbum, bundle) Navigation.findNavController(requireView()).navigate(R.id.searchToTrackCollection, bundle)
} }
private fun onSongSelected(song: MusicDirectory.Entry, append: Boolean) { private fun onSongSelected(song: MusicDirectory.Entry, append: Boolean) {
if (!append) { if (!append) {
mediaPlayerController.clear() mediaPlayerController.clear()
} }
mediaPlayerController.addToPlaylist(listOf(song), false, false, false, false, false) mediaPlayerController.addToPlaylist(
listOf(song),
save = false,
autoPlay = false,
playNext = false,
shuffle = false,
newPlaylist = false
)
mediaPlayerController.play(mediaPlayerController.playlistSize - 1) mediaPlayerController.play(mediaPlayerController.playlistSize - 1)
toast(context, resources.getQuantityString(R.plurals.select_album_n_songs_added, 1, 1)) toast(context, resources.getQuantityString(R.plurals.select_album_n_songs_added, 1, 1))
} }
@ -304,7 +327,7 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
override fun onItemClick(item: Identifiable) { override fun onItemClick(item: Identifiable) {
when (item) { when (item) {
is Artist -> { is ArtistOrIndex -> {
onArtistSelected(item) onArtistSelected(item)
} }
is MusicDirectory.Entry -> { is MusicDirectory.Entry -> {

View File

@ -49,13 +49,11 @@ import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.util.Util
/** /**
*
* 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.
* *
* In most cases the data should be just a list of Entries, but there are some cases * In most cases the data should be just a list of Entries, but there are some cases
* where the list can contain Albums as well. This happens especially when having ID3 tags disabled, * where the list can contain Albums as well. This happens especially when having ID3 tags disabled,
* or using Offline mode, both in which Indexes instead of Artists are being used. * or using Offline mode, both in which Indexes instead of Artists are being used.
*
*/ */
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() { open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
@ -96,7 +94,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
// Setup refresh handler // Setup refresh handler
refreshListView = view.findViewById(refreshListId) refreshListView = view.findViewById(refreshListId)
refreshListView?.setOnRefreshListener { refreshListView?.setOnRefreshListener {
refreshData(true) getLiveData(arguments, true)
} }
// TODO: remove special casing for songsForGenre // TODO: remove special casing for songsForGenre
@ -209,12 +207,6 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
refreshListView?.isRefreshing = false refreshListView?.isRefreshing = false
} }
private fun refreshData(refresh: Boolean = false) {
val args = getArgumentsClone()
args.putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, refresh)
getLiveData(args)
}
override fun onPrepareOptionsMenu(menu: Menu) { override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu) super.onPrepareOptionsMenu(menu)
playAllButton = menu.findItem(R.id.select_album_play_all) playAllButton = menu.findItem(R.id.select_album_play_all)
@ -293,8 +285,6 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
} }
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) val id = arguments?.getString(Constants.INTENT_EXTRA_NAME_ID)
if (hasSubFolders && id != null) { if (hasSubFolders && id != null) {
@ -565,7 +555,10 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
} }
@Suppress("LongMethod") @Suppress("LongMethod")
override fun getLiveData(args: Bundle?, refresh: Boolean): LiveData<List<MusicDirectory.Child>> { override fun getLiveData(
args: Bundle?,
refresh: Boolean
): LiveData<List<MusicDirectory.Child>> {
if (args == null) return listModel.currentList if (args == null) return listModel.currentList
val id = args.getString(Constants.INTENT_EXTRA_NAME_ID) val id = args.getString(Constants.INTENT_EXTRA_NAME_ID)
val isAlbum = args.getBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, false) val isAlbum = args.getBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, false)
@ -588,7 +581,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
val albumListOffset = args.getInt( val albumListOffset = args.getInt(
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
) )
val refresh = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true) || refresh val refresh2 = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true) || refresh
listModel.viewModelScope.launch(handler) { listModel.viewModelScope.launch(handler) {
refreshListView?.isRefreshing = true refreshListView?.isRefreshing = true
@ -610,7 +603,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
listModel.getStarred() listModel.getStarred()
} else if (getVideos != 0) { } else if (getVideos != 0) {
setTitle(R.string.main_videos) setTitle(R.string.main_videos)
listModel.getVideos(refresh) listModel.getVideos(refresh2)
} else if (getRandomTracks != 0) { } else if (getRandomTracks != 0) {
setTitle(R.string.main_songs_random) setTitle(R.string.main_songs_random)
listModel.getRandom(albumListSize) listModel.getRandom(albumListSize)
@ -618,12 +611,12 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
setTitle(name) setTitle(name)
if (!isOffline() && Settings.shouldUseId3Tags) { if (!isOffline() && Settings.shouldUseId3Tags) {
if (isAlbum) { if (isAlbum) {
listModel.getAlbum(refresh, id!!, name) listModel.getAlbum(refresh2, id!!, name)
} else { } else {
throw IllegalAccessException("Use AlbumFragment instead!") throw IllegalAccessException("Use AlbumFragment instead!")
} }
} else { } else {
listModel.getMusicDirectory(refresh, id!!, name) listModel.getMusicDirectory(refresh2, id!!, name)
} }
} }

View File

@ -436,10 +436,6 @@ class DownloadFile(
override val id: String override val id: String
get() = song.id get() = song.id
override val longId: Long by lazy {
id.hashCode().toLong()
}
companion object { companion object {
const val MAX_RETRIES = 5 const val MAX_RETRIES = 5
} }

View File

@ -24,6 +24,7 @@ import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.Artist import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.ArtistOrIndex
import org.moire.ultrasonic.domain.Bookmark import org.moire.ultrasonic.domain.Bookmark
import org.moire.ultrasonic.domain.ChatMessage import org.moire.ultrasonic.domain.ChatMessage
import org.moire.ultrasonic.domain.Genre import org.moire.ultrasonic.domain.Genre
@ -122,7 +123,7 @@ class OfflineMusicService : MusicService, KoinComponent {
} }
override fun search(criteria: SearchCriteria): SearchResult { override fun search(criteria: SearchCriteria): SearchResult {
val artists: MutableList<Artist> = ArrayList() val artists: MutableList<ArtistOrIndex> = ArrayList()
val albums: MutableList<MusicDirectory.Album> = ArrayList() val albums: MutableList<MusicDirectory.Album> = ArrayList()
val songs: MutableList<MusicDirectory.Entry> = ArrayList() val songs: MutableList<MusicDirectory.Entry> = ArrayList()
val root = FileUtil.musicDirectory val root = FileUtil.musicDirectory
@ -131,7 +132,7 @@ class OfflineMusicService : MusicService, KoinComponent {
val artistName = artistFile.name val artistName = artistFile.name
if (artistFile.isDirectory) { if (artistFile.isDirectory) {
if (matchCriteria(criteria, artistName).also { closeness = it } > 0) { if (matchCriteria(criteria, artistName).also { closeness = it } > 0) {
val artist = Artist(artistFile.path) val artist = Index(artistFile.path)
artist.index = artistFile.name.substring(0, 1) artist.index = artistFile.name.substring(0, 1)
artist.name = artistName artist.name = artistName
artist.closeness = closeness artist.closeness = closeness

View File

@ -361,7 +361,6 @@ open class RESTMusicService(
musicFolderId musicFolderId
).execute().throwOnFailure() ).execute().throwOnFailure()
return response.body()!!.albumList.toDomainEntityList() return response.body()!!.albumList.toDomainEntityList()
} }

View File

@ -60,8 +60,11 @@
android:id="@+id/searchFragment" android:id="@+id/searchFragment"
android:name="org.moire.ultrasonic.fragment.SearchFragment" > android:name="org.moire.ultrasonic.fragment.SearchFragment" >
<action <action
android:id="@+id/searchToSelectAlbum" android:id="@+id/searchToTrackCollection"
app:destination="@id/trackCollectionFragment" /> app:destination="@id/trackCollectionFragment" />
<action
android:id="@+id/searchToAlbumsList"
app:destination="@id/albumListFragment" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/playlistsFragment" android:id="@+id/playlistsFragment"