Various fixes
* Work on folder selector, * Make current play queue drag&droppable * Fix album view in offline mode
This commit is contained in:
parent
82d90a6aee
commit
2f0ff384d0
|
@ -24,6 +24,7 @@ import org.moire.ultrasonic.util.BoundedTreeSet
|
|||
*
|
||||
* It should be kept generic enough that it can be used a Base for all lists in the app.
|
||||
*/
|
||||
@Suppress("unused", "UNUSED_PARAMETER")
|
||||
class BaseAdapter<T : Identifiable> : MultiTypeAdapter() {
|
||||
|
||||
// Update the BoundedTreeSet if selection type is changed
|
||||
|
@ -195,19 +196,6 @@ class BaseAdapter<T : Identifiable> : MultiTypeAdapter() {
|
|||
return selectedSet.contains(longId)
|
||||
}
|
||||
|
||||
fun moveItem(from: Int, to: Int): List<T> {
|
||||
val list = getCurrentList().toMutableList()
|
||||
val fromLocation = list[from]
|
||||
list.removeAt(from)
|
||||
if (to < from) {
|
||||
list.add(to + 1, fromLocation)
|
||||
} else {
|
||||
list.add(to - 1, fromLocation)
|
||||
}
|
||||
submitList(list)
|
||||
return list
|
||||
}
|
||||
|
||||
fun hasSingleSelection(): Boolean {
|
||||
return selectionType == SelectionType.SINGLE
|
||||
}
|
||||
|
|
|
@ -36,15 +36,22 @@ class FolderSelectorBinder(context: Context) :
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, item: FolderHeader) {
|
||||
holder.setData(item.selected, item.folders)
|
||||
holder.setData(item)
|
||||
}
|
||||
|
||||
class ViewHolder(
|
||||
view: View,
|
||||
private val weakContext: WeakReference<Context>
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
private var musicFolders: List<MusicFolder> = mutableListOf()
|
||||
private var selectedFolderId: String? = null
|
||||
|
||||
private var data: FolderHeader? = null
|
||||
|
||||
private val selectedFolderId: String?
|
||||
get() = data?.selected
|
||||
|
||||
private val musicFolders: List<MusicFolder>
|
||||
get() = data?.folders ?: mutableListOf()
|
||||
|
||||
private val folderName: TextView = itemView.findViewById(R.id.select_folder_name)
|
||||
private val layout: LinearLayout = itemView.findViewById(R.id.select_folder_header)
|
||||
|
||||
|
@ -53,9 +60,8 @@ class FolderSelectorBinder(context: Context) :
|
|||
layout.setOnClickListener { onFolderClick() }
|
||||
}
|
||||
|
||||
fun setData(selectedId: String?, folders: List<MusicFolder>) {
|
||||
selectedFolderId = selectedId
|
||||
musicFolders = folders
|
||||
fun setData(item: FolderHeader) {
|
||||
data = item
|
||||
if (selectedFolderId != null) {
|
||||
for ((id, name) in musicFolders) {
|
||||
if (id == selectedFolderId) {
|
||||
|
@ -74,9 +80,11 @@ class FolderSelectorBinder(context: Context) :
|
|||
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)
|
||||
|
@ -95,7 +103,8 @@ class FolderSelectorBinder(context: Context) :
|
|||
val selectedFolder = if (menuItem.itemId == -1) null else musicFolders[menuItem.itemId]
|
||||
val musicFolderName = selectedFolder?.name
|
||||
?: weakContext.get()!!.getString(R.string.select_artist_all_folders)
|
||||
selectedFolderId = selectedFolder?.id
|
||||
|
||||
data?.selected = selectedFolder?.id
|
||||
|
||||
menuItem.isChecked = true
|
||||
folderName.text = musicFolderName
|
||||
|
@ -111,8 +120,8 @@ class FolderSelectorBinder(context: Context) :
|
|||
}
|
||||
|
||||
data class FolderHeader(
|
||||
val folders: List<MusicFolder>,
|
||||
val selected: String?
|
||||
var folders: List<MusicFolder>,
|
||||
var selected: String?
|
||||
) : Identifiable {
|
||||
override val id: String
|
||||
get() = "FOLDERSELECTOR"
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
package org.moire.ultrasonic.adapters
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class TrackViewBinder(
|
|||
val popup = Utils.createPopupMenu(holder.itemView, contextMenuLayout)
|
||||
|
||||
popup.setOnMenuItemClickListener { menuItem ->
|
||||
onContextMenuClick?.invoke(menuItem, downloadFile)
|
||||
onContextMenuClick?.invoke(menuItem, downloadFile)
|
||||
}
|
||||
} else {
|
||||
// Minimize or maximize the Text view (if song title is very long)
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.widget.Checkable
|
|||
import android.widget.CheckedTextView
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
|
|
@ -9,12 +9,15 @@ package org.moire.ultrasonic.fragment
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.moire.ultrasonic.R
|
||||
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.model.AlbumListModel
|
||||
import org.moire.ultrasonic.util.Constants
|
||||
|
@ -84,4 +87,39 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Album>() {
|
|||
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.parent)
|
||||
findNavController().navigate(R.id.trackCollectionFragment, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* What to do when the list has changed
|
||||
*/
|
||||
override val defaultObserver: (List<MusicDirectory.Album>) -> Unit = {
|
||||
emptyView.isVisible = it.isEmpty()
|
||||
|
||||
if (showFolderHeader()) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val list = it as MutableList<Identifiable>
|
||||
list.add(0, folderHeader)
|
||||
} else {
|
||||
viewAdapter.submitList(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a folder header and update it on changes
|
||||
*/
|
||||
private val folderHeader: FolderSelectorBinder.FolderHeader by lazy {
|
||||
val header = FolderSelectorBinder.FolderHeader(
|
||||
listModel.musicFolders.value!!,
|
||||
listModel.activeServer.musicFolderId
|
||||
)
|
||||
|
||||
listModel.musicFolders.observe(
|
||||
viewLifecycleOwner,
|
||||
{
|
||||
header.folders = it
|
||||
viewAdapter.notifyItemChanged(0)
|
||||
}
|
||||
)
|
||||
|
||||
header
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.moire.ultrasonic.R
|
|||
import org.moire.ultrasonic.adapters.ArtistRowBinder
|
||||
import org.moire.ultrasonic.domain.Artist
|
||||
import org.moire.ultrasonic.domain.ArtistOrIndex
|
||||
import org.moire.ultrasonic.domain.Index
|
||||
import org.moire.ultrasonic.model.ArtistListModel
|
||||
import org.moire.ultrasonic.util.Constants
|
||||
|
||||
|
@ -47,16 +48,29 @@ class ArtistListFragment : EntryListFragment<ArtistOrIndex>() {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* There are different targets depending on what list we show.
|
||||
* If we are showing indexes, we need to go to TrackCollection
|
||||
* If we are showing artists, we need to go to AlbumList
|
||||
*/
|
||||
override fun onItemClick(item: ArtistOrIndex) {
|
||||
val bundle = Bundle()
|
||||
|
||||
// Common arguments
|
||||
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))
|
||||
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.selectArtistToSelectAlbum, bundle)
|
||||
|
||||
// Check type
|
||||
if (item is Index) {
|
||||
findNavController().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)
|
||||
findNavController().navigate(R.id.artistsListToAlbumsList, bundle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import androidx.lifecycle.LiveData
|
|||
import org.koin.core.component.inject
|
||||
import org.moire.ultrasonic.R
|
||||
import org.moire.ultrasonic.adapters.TrackViewBinder
|
||||
import org.moire.ultrasonic.domain.Identifiable
|
||||
import org.moire.ultrasonic.model.GenericListModel
|
||||
import org.moire.ultrasonic.service.DownloadFile
|
||||
import org.moire.ultrasonic.service.Downloader
|
||||
|
@ -56,7 +55,7 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
|
|||
viewAdapter.register(
|
||||
TrackViewBinder(
|
||||
{ },
|
||||
{ _,_ -> true },
|
||||
{ _, _ -> true },
|
||||
checkable = false,
|
||||
draggable = false,
|
||||
context = requireContext(),
|
||||
|
@ -78,7 +77,7 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
|
|||
}
|
||||
|
||||
override fun onItemClick(item: DownloadFile) {
|
||||
// TODO: Add code to enable manipulation of the download list
|
||||
// TODO: Add code to enable manipulation of the download list
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.view.View
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.moire.ultrasonic.R
|
||||
import org.moire.ultrasonic.adapters.FolderSelectorBinder
|
||||
import org.moire.ultrasonic.domain.Artist
|
||||
import org.moire.ultrasonic.domain.GenericEntry
|
||||
import org.moire.ultrasonic.domain.Identifiable
|
||||
|
@ -24,7 +25,6 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
|
|||
/**
|
||||
* Whether to show the folder selector
|
||||
*/
|
||||
// FIXME
|
||||
fun showFolderHeader(): Boolean {
|
||||
return listModel.showSelectFolderHeader(arguments) &&
|
||||
!listModel.isOffline() && !Settings.shouldUseId3Tags
|
||||
|
@ -55,9 +55,14 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
|
|||
currentSetting.musicFolderId = it
|
||||
serverSettingsModel.updateItem(currentSetting)
|
||||
}
|
||||
// FIXME: Needed?
|
||||
viewAdapter.notifyDataSetChanged()
|
||||
listModel.refresh(refreshListView!!, arguments)
|
||||
}
|
||||
|
||||
viewAdapter.register(
|
||||
FolderSelectorBinder(view.context)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -102,6 +102,14 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* What to do when the list has changed
|
||||
*/
|
||||
internal open val defaultObserver: ((List<T>) -> Unit) = {
|
||||
emptyView.isVisible = it.isEmpty()
|
||||
viewAdapter.submitList(it)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
@ -122,13 +130,7 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
|
|||
emptyTextView = view.findViewById(emptyTextId)
|
||||
|
||||
// Register an observer to update our UI when the data changes
|
||||
liveDataItems.observe(
|
||||
viewLifecycleOwner,
|
||||
{ newItems ->
|
||||
emptyView.isVisible = newItems.isEmpty()
|
||||
viewAdapter.submitList(newItems)
|
||||
}
|
||||
)
|
||||
liveDataItems.observe(viewLifecycleOwner, defaultObserver)
|
||||
|
||||
// Create a View Manager
|
||||
viewManager = LinearLayoutManager(this.context)
|
||||
|
@ -139,9 +141,6 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
|
|||
layoutManager = viewManager
|
||||
adapter = viewAdapter
|
||||
}
|
||||
|
||||
// Configure whether to show the folder header
|
||||
// viewAdapter.folderHeaderEnabled = showFolderHeader()
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -859,7 +859,7 @@ class PlayerFragment :
|
|||
viewAdapter.register(
|
||||
TrackViewBinder(
|
||||
onItemClick = listener,
|
||||
onContextMenuClick = {_,_ -> true},
|
||||
onContextMenuClick = { _, _ -> true },
|
||||
checkable = false,
|
||||
draggable = true,
|
||||
context = requireContext(),
|
||||
|
@ -880,10 +880,9 @@ class PlayerFragment :
|
|||
val from = viewHolder.bindingAdapterPosition
|
||||
val to = target.bindingAdapterPosition
|
||||
|
||||
// FIXME:
|
||||
// Needs to be changed in the playlist as well...
|
||||
// Move it in the data set
|
||||
(recyclerView.adapter as BaseAdapter<*>).moveItem(from, to)
|
||||
// Move it in the data set
|
||||
mediaPlayerController.moveItemInPlaylist(from, to)
|
||||
viewAdapter.submitList(mediaPlayerController.playList)
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -370,7 +370,14 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
|
|||
@Suppress("LongMethod")
|
||||
override fun onContextMenuItemSelected(menuItem: MenuItem, item: Identifiable): Boolean {
|
||||
val isArtist = (item is Artist)
|
||||
val found = EntryListFragment.handleContextMenu(menuItem, item, isArtist, downloadHandler, this)
|
||||
|
||||
val found = EntryListFragment.handleContextMenu(
|
||||
menuItem,
|
||||
item,
|
||||
isArtist,
|
||||
downloadHandler,
|
||||
this
|
||||
)
|
||||
|
||||
if (found || item !is DownloadFile) return true
|
||||
|
||||
|
|
|
@ -46,24 +46,24 @@ import org.moire.ultrasonic.util.Constants
|
|||
import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator
|
||||
import org.moire.ultrasonic.util.Settings
|
||||
import org.moire.ultrasonic.util.Util
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Displays a group of tracks, eg. the songs of an album, of a playlist etc.
|
||||
* FIXME: Offset when navigating to?
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
|
||||
|
||||
private var albumButtons: View? = null
|
||||
internal var selectButton: ImageView? = null
|
||||
internal var playNowButton: ImageView? = null
|
||||
internal var playNextButton: ImageView? = null
|
||||
internal var playLastButton: ImageView? = null
|
||||
private var playNextButton: ImageView? = null
|
||||
private var playLastButton: ImageView? = null
|
||||
internal var pinButton: ImageView? = null
|
||||
internal var unpinButton: ImageView? = null
|
||||
internal var downloadButton: ImageView? = null
|
||||
internal var deleteButton: ImageView? = null
|
||||
internal var moreButton: ImageView? = null
|
||||
private var unpinButton: ImageView? = null
|
||||
private var downloadButton: ImageView? = null
|
||||
private var deleteButton: ImageView? = null
|
||||
private var moreButton: ImageView? = null
|
||||
private var playAllButtonVisible = false
|
||||
private var shareButtonVisible = false
|
||||
private var playAllButton: MenuItem? = null
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.os.Bundle
|
|||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -16,14 +17,15 @@ 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
|
||||
import org.moire.ultrasonic.util.Settings
|
||||
|
||||
/**
|
||||
* An abstract Model, which can be extended to retrieve a list of items from the API
|
||||
*/
|
||||
* An abstract Model, which can be extended to retrieve a list of items from the API
|
||||
*/
|
||||
open class GenericListModel(application: Application) :
|
||||
AndroidViewModel(application), KoinComponent {
|
||||
|
||||
|
@ -38,6 +40,8 @@ open class GenericListModel(application: Application) :
|
|||
var currentListIsSortable = true
|
||||
var showHeader = true
|
||||
|
||||
val musicFolders: MutableLiveData<List<MusicFolder>> = MutableLiveData(listOf())
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
open fun showSelectFolderHeader(args: Bundle?): Boolean {
|
||||
return true
|
||||
|
@ -105,8 +109,11 @@ open class GenericListModel(application: Application) :
|
|||
args: Bundle
|
||||
) {
|
||||
// Update the list of available folders if enabled
|
||||
// FIXME && refresh ?
|
||||
if (showSelectFolderHeader(args) && !isOffline && !useId3Tags) {
|
||||
// FIXME
|
||||
musicFolders.postValue(
|
||||
musicService.getMusicFolders(refresh)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -369,6 +369,20 @@ class Downloader(
|
|||
checkDownloads()
|
||||
}
|
||||
|
||||
fun moveItemInPlaylist(oldPos: Int, newPos: Int) {
|
||||
val item = playlist[oldPos]
|
||||
playlist.remove(item)
|
||||
|
||||
if (newPos < oldPos) {
|
||||
playlist.add(newPos + 1, item)
|
||||
} else {
|
||||
playlist.add(newPos - 1, item)
|
||||
}
|
||||
|
||||
playlistUpdateRevision++
|
||||
checkDownloads()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun clearIncomplete() {
|
||||
val iterator = playlist.iterator()
|
||||
|
|
|
@ -250,6 +250,11 @@ class MediaPlayerController(
|
|||
mediaPlayerService?.setNextPlaying()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun moveItemInPlaylist(oldPos: Int, newPos: Int) {
|
||||
downloader.moveItemInPlaylist(oldPos, newPos)
|
||||
}
|
||||
|
||||
@set:Synchronized
|
||||
var repeatMode: RepeatMode
|
||||
get() = Settings.repeatMode
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package org.moire.ultrasonic.util
|
||||
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.DOWN
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.UP
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.moire.ultrasonic.adapters.BaseAdapter
|
||||
|
||||
class DragSortCallback : ItemTouchHelper.SimpleCallback(UP or DOWN, 0) {
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
|
||||
val from = viewHolder.bindingAdapterPosition
|
||||
val to = target.bindingAdapterPosition
|
||||
|
||||
// FIXME: Move it in the data set
|
||||
(recyclerView.adapter as BaseAdapter<*>).moveItem(from, to)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
}
|
||||
}
|
|
@ -25,15 +25,21 @@
|
|||
android:name="org.moire.ultrasonic.fragment.ArtistListFragment"
|
||||
android:label="@string/music_library.label" >
|
||||
<action
|
||||
android:id="@+id/selectArtistToSelectAlbum"
|
||||
android:id="@+id/artistsListToAlbumsList"
|
||||
app:destination="@id/albumListFragment" />
|
||||
<action
|
||||
android:id="@+id/artistsListToTrackCollection"
|
||||
app:destination="@id/trackCollectionFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/artistListFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.ArtistListFragment" >
|
||||
<action
|
||||
android:id="@+id/selectArtistToSelectAlbum"
|
||||
android:id="@+id/artistsListToAlbumsList"
|
||||
app:destination="@id/albumListFragment" />
|
||||
<action
|
||||
android:id="@+id/artistsListToTrackCollection"
|
||||
app:destination="@id/trackCollectionFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/trackCollectionFragment"
|
||||
|
|
Loading…
Reference in New Issue