diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AlbumListFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AlbumListFragment.kt index 342e6a87..93c7d1c7 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AlbumListFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AlbumListFragment.kt @@ -34,6 +34,11 @@ class AlbumListFragment : EntryListFragment() { */ override val mainLayout: Int = R.layout.list_layout_generic + /** + * Whether to refresh the data onViewCreated + */ + override val refreshOnCreation: Boolean = false + /** * The central function to pass a query to the model and return a LiveData object */ diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EntryListFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EntryListFragment.kt index 22942703..395d2d6c 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EntryListFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EntryListFragment.kt @@ -71,7 +71,7 @@ abstract class EntryListFragment : MultiListFragment() { * What to do when the list has changed */ override val defaultObserver: (List) -> Unit = { - emptyView.isVisible = it.isEmpty() + emptyView.isVisible = it.isEmpty() && !(refreshListView?.isRefreshing?:false) if (showFolderHeader()) { val list = mutableListOf(folderHeader) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MultiListFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MultiListFragment.kt index 0c819730..fef74587 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MultiListFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MultiListFragment.kt @@ -89,6 +89,11 @@ abstract class MultiListFragment : Fragment() { open val emptyViewId = R.id.empty_list_view open val emptyTextId = R.id.empty_list_text + /** + * Whether to refresh the data onViewCreated + */ + open val refreshOnCreation: Boolean = true + open fun setTitle(title: String?) { if (title == null) { FragmentTitle.setTitle( @@ -106,7 +111,7 @@ abstract class MultiListFragment : Fragment() { * What to do when the list has changed */ internal open val defaultObserver: ((List) -> Unit) = { - emptyView.isVisible = it.isEmpty() + emptyView.isVisible = it.isEmpty() && !(refreshListView?.isRefreshing?:false) viewAdapter.submitList(it) } @@ -123,7 +128,7 @@ abstract class MultiListFragment : Fragment() { } // Populate the LiveData. This starts an API request in most cases - liveDataItems = getLiveData(arguments, true) + liveDataItems = getLiveData(arguments, refreshOnCreation) // Link view to display text if the list is empty emptyView = view.findViewById(emptyViewId) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt index 8e4dc778..ca9b099e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt @@ -18,7 +18,6 @@ import android.widget.ImageView import androidx.core.view.isVisible import androidx.fragment.app.viewModels import androidx.lifecycle.LiveData -import androidx.lifecycle.Observer import androidx.lifecycle.viewModelScope import androidx.navigation.Navigation import androidx.recyclerview.widget.LinearLayoutManager @@ -54,6 +53,8 @@ import org.moire.ultrasonic.util.Util * 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, * or using Offline mode, both in which Indexes instead of Artists are being used. + * + * TODO: Remove more button and introduce endless scrolling */ @Suppress("TooManyFunctions") open class TrackCollectionFragment : MultiListFragment() { @@ -97,9 +98,6 @@ open class TrackCollectionFragment : MultiListFragment() { getLiveData(arguments, true) } - // TODO: remove special casing for songsForGenre - listModel.songsForGenre.observe(viewLifecycleOwner, songsForGenreObserver) - setupButtons(view) registerForContextMenu(listView!!) @@ -424,34 +422,6 @@ open class TrackCollectionFragment : MultiListFragment() { mediaPlayerController.unpin(songs) } - private val songsForGenreObserver = Observer { musicDirectory -> - - // Hide more button when results are less than album list size - if (musicDirectory.size < requireArguments().getInt( - Constants.INTENT_ALBUM_LIST_SIZE, 0 - ) - ) { - moreButton!!.visibility = View.GONE - } else { - moreButton!!.visibility = View.VISIBLE - } - - moreButton!!.setOnClickListener { - val theGenre = requireArguments().getString(Constants.INTENT_GENRE_NAME) - val size = requireArguments().getInt(Constants.INTENT_ALBUM_LIST_SIZE, 0) - val theOffset = requireArguments().getInt( - Constants.INTENT_ALBUM_LIST_OFFSET, 0 - ) + size - val bundle = Bundle() - bundle.putString(Constants.INTENT_GENRE_NAME, theGenre) - bundle.putInt(Constants.INTENT_ALBUM_LIST_SIZE, size) - bundle.putInt(Constants.INTENT_ALBUM_LIST_OFFSET, theOffset) - - Navigation.findNavController(requireView()) - .navigate(R.id.trackCollectionFragment, bundle) - } - } - override val defaultObserver: (List) -> Unit = { val entryList: MutableList = it.toMutableList() @@ -483,18 +453,9 @@ open class TrackCollectionFragment : MultiListFragment() { } else { moreButton!!.visibility = View.VISIBLE if (arguments?.getInt(Constants.INTENT_RANDOM, 0) ?: 0 > 0) { - moreButton!!.setOnClickListener { - val offset = requireArguments().getInt( - Constants.INTENT_ALBUM_LIST_OFFSET, 0 - ) + listSize - val bundle = Bundle() - bundle.putInt(Constants.INTENT_RANDOM, 1) - bundle.putInt(Constants.INTENT_ALBUM_LIST_SIZE, listSize) - bundle.putInt(Constants.INTENT_ALBUM_LIST_OFFSET, offset) - Navigation.findNavController(requireView()).navigate( - R.id.trackCollectionFragment, bundle - ) - } + moreRandomTracks() + } else if (arguments?.getString(Constants.INTENT_GENRE_NAME, "") ?: "" != "") { + moreSongsForGenre() } } } @@ -536,6 +497,40 @@ open class TrackCollectionFragment : MultiListFragment() { listModel.currentListIsSortable = true } + private fun moreSongsForGenre(args: Bundle = requireArguments()) { + moreButton!!.setOnClickListener { + val theGenre = args.getString(Constants.INTENT_GENRE_NAME) + val size = args.getInt(Constants.INTENT_ALBUM_LIST_SIZE, 0) + val theOffset = args.getInt( + Constants.INTENT_ALBUM_LIST_OFFSET, 0 + ) + size + val bundle = Bundle() + bundle.putString(Constants.INTENT_GENRE_NAME, theGenre) + bundle.putInt(Constants.INTENT_ALBUM_LIST_SIZE, size) + bundle.putInt(Constants.INTENT_ALBUM_LIST_OFFSET, theOffset) + + Navigation.findNavController(requireView()) + .navigate(R.id.trackCollectionFragment, bundle) + } + } + + private fun moreRandomTracks() { + val listSize = arguments?.getInt(Constants.INTENT_ALBUM_LIST_SIZE, 0) ?: 0 + + moreButton!!.setOnClickListener { it: View? -> + val offset = requireArguments().getInt( + Constants.INTENT_ALBUM_LIST_OFFSET, 0 + ) + listSize + val bundle = Bundle() + bundle.putInt(Constants.INTENT_RANDOM, 1) + bundle.putInt(Constants.INTENT_ALBUM_LIST_SIZE, listSize) + bundle.putInt(Constants.INTENT_ALBUM_LIST_OFFSET, offset) + Navigation.findNavController(requireView()).navigate( + R.id.trackCollectionFragment, bundle + ) + } + } + internal fun getSelectedSongs(): List { // Walk through selected set and get the Entries based on the saved ids. return viewAdapter.getCurrentList().mapNotNull { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt index 816696c7..5fd2e86d 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt @@ -63,6 +63,12 @@ class AlbumListModel(application: Application) : GenericListModel(application) { null } + // If we are refreshing the random list, we want to avoid items moving across the screen, + // by clearing the list first + if (refresh && albumListType == "random") { + list.postValue(listOf()) + } + // Handle the logic for endless scrolling: // If appending the existing list, set the offset from where to load if (append) offset += (size + loadedUntil) @@ -95,7 +101,7 @@ class AlbumListModel(application: Application) : GenericListModel(application) { val newList = ArrayList() newList.addAll(list.value!!) newList.addAll(musicDirectory) - this.list.postValue(newList) + list.postValue(newList) } else { list.postValue(musicDirectory) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/TrackCollectionModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/TrackCollectionModel.kt index 3b658ae6..8fdd1202 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/TrackCollectionModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/TrackCollectionModel.kt @@ -22,7 +22,6 @@ import org.moire.ultrasonic.util.Util class TrackCollectionModel(application: Application) : GenericListModel(application) { val currentList: MutableLiveData> = MutableLiveData() - val songsForGenre: MutableLiveData = MutableLiveData() /* * Especially when dealing with indexes, this method can return Albums, Entries or a mix of both! @@ -56,7 +55,7 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() val musicDirectory = service.getSongsByGenre(genre, count, offset) - songsForGenre.postValue(musicDirectory) + updateList(musicDirectory) } }