2021-10-16 11:30:51 +02:00
|
|
|
package org.moire.ultrasonic.fragment
|
|
|
|
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.view.MenuItem
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewGroup
|
|
|
|
import androidx.fragment.app.Fragment
|
|
|
|
import androidx.fragment.app.viewModels
|
|
|
|
import androidx.lifecycle.LiveData
|
|
|
|
import androidx.navigation.fragment.findNavController
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager
|
|
|
|
import androidx.recyclerview.widget.RecyclerView
|
|
|
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|
|
|
import com.drakeet.multitype.MultiTypeAdapter
|
|
|
|
import org.koin.android.ext.android.inject
|
|
|
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
|
|
|
import org.moire.ultrasonic.R
|
2021-11-14 21:20:23 +01:00
|
|
|
import org.moire.ultrasonic.adapters.MultiTypeDiffAdapter
|
2021-10-16 11:30:51 +02:00
|
|
|
import org.moire.ultrasonic.data.ActiveServerProvider
|
|
|
|
import org.moire.ultrasonic.domain.Artist
|
|
|
|
import org.moire.ultrasonic.domain.GenericEntry
|
|
|
|
import org.moire.ultrasonic.domain.Identifiable
|
|
|
|
import org.moire.ultrasonic.domain.MusicFolder
|
|
|
|
import org.moire.ultrasonic.subsonic.DownloadHandler
|
|
|
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
|
|
|
import org.moire.ultrasonic.util.Constants
|
|
|
|
import org.moire.ultrasonic.util.Settings
|
|
|
|
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
|
|
|
|
* @param T: The type of data which will be used (must extend GenericEntry)
|
|
|
|
* @param TA: The Adapter to use (must extend GenericRowAdapter)
|
|
|
|
*/
|
2021-11-14 21:20:23 +01:00
|
|
|
abstract class MultiListFragment<T : Identifiable> : Fragment() {
|
2021-10-16 11:30:51 +02:00
|
|
|
internal val activeServerProvider: ActiveServerProvider by inject()
|
|
|
|
internal val serverSettingsModel: ServerSettingsModel by viewModel()
|
|
|
|
internal val imageLoaderProvider: ImageLoaderProvider by inject()
|
|
|
|
protected val downloadHandler: DownloadHandler by inject()
|
|
|
|
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
|
|
|
|
* Recommendation: Implement this as a lazy delegate
|
|
|
|
*/
|
2021-11-14 21:20:23 +01:00
|
|
|
internal val viewAdapter: MultiTypeDiffAdapter<Identifiable> by lazy {
|
|
|
|
MultiTypeDiffAdapter()
|
|
|
|
}
|
2021-10-16 11:30:51 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The ViewModel to use to get the data
|
|
|
|
*/
|
|
|
|
open val listModel: GenericListModel by viewModels()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The LiveData containing the list provided by the model
|
|
|
|
* Implement this as a getter
|
|
|
|
*/
|
|
|
|
internal lateinit var liveDataItems: LiveData<List<T>>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The central function to pass a query to the model and return a LiveData object
|
|
|
|
*/
|
|
|
|
abstract fun getLiveData(args: Bundle? = null): LiveData<List<T>>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The id of the target in the navigation graph where we should go,
|
|
|
|
* after the user has clicked on an item
|
|
|
|
*/
|
|
|
|
protected abstract val itemClickTarget: Int
|
|
|
|
|
|
|
|
/**
|
2021-10-18 12:57:21 +02:00
|
|
|
* The id of the main layout
|
2021-10-16 11:30:51 +02:00
|
|
|
*/
|
2021-10-18 12:57:21 +02:00
|
|
|
open val mainLayout: Int = R.layout.generic_list
|
2021-10-16 11:30:51 +02:00
|
|
|
|
|
|
|
/**
|
2021-10-18 12:57:21 +02:00
|
|
|
* The id of the refresh view
|
2021-10-16 11:30:51 +02:00
|
|
|
*/
|
2021-10-18 12:57:21 +02:00
|
|
|
open val refreshListId: Int = R.id.generic_list_refresh
|
2021-10-16 11:30:51 +02:00
|
|
|
|
|
|
|
/**
|
2021-10-18 12:57:21 +02:00
|
|
|
* The id of the RecyclerView
|
2021-10-16 11:30:51 +02:00
|
|
|
*/
|
2021-10-18 12:57:21 +02:00
|
|
|
open val recyclerViewId = R.id.generic_list_recycler
|
2021-10-16 11:30:51 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The observer to be called if the available music folders have changed
|
|
|
|
*/
|
|
|
|
@Suppress("CommentOverPrivateProperty")
|
|
|
|
private val musicFolderObserver = { folders: List<MusicFolder> ->
|
|
|
|
//viewAdapter.setFolderList(folders, listModel.activeServer.musicFolderId)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* What to do when the user has modified the folder filter
|
|
|
|
*/
|
|
|
|
val onMusicFolderUpdate = { selectedFolderId: String? ->
|
|
|
|
if (!listModel.isOffline()) {
|
|
|
|
val currentSetting = listModel.activeServer
|
|
|
|
currentSetting.musicFolderId = selectedFolderId
|
|
|
|
serverSettingsModel.updateItem(currentSetting)
|
|
|
|
}
|
|
|
|
viewAdapter.notifyDataSetChanged()
|
|
|
|
listModel.refresh(refreshListView!!, arguments)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether to show the folder selector
|
|
|
|
*/
|
|
|
|
fun showFolderHeader(): Boolean {
|
|
|
|
return listModel.showSelectFolderHeader(arguments) &&
|
|
|
|
!listModel.isOffline() && !Settings.shouldUseId3Tags
|
|
|
|
}
|
|
|
|
|
|
|
|
open fun setTitle(title: String?) {
|
|
|
|
if (title == null) {
|
|
|
|
FragmentTitle.setTitle(
|
|
|
|
this,
|
|
|
|
if (listModel.isOffline())
|
|
|
|
R.string.music_library_label_offline
|
|
|
|
else R.string.music_library_label
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
FragmentTitle.setTitle(this, title)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
|
|
super.onViewCreated(view, savedInstanceState)
|
|
|
|
|
|
|
|
// Set the title if available
|
|
|
|
setTitle(arguments?.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE))
|
|
|
|
|
|
|
|
// Setup refresh handler
|
|
|
|
refreshListView = view.findViewById(refreshListId)
|
|
|
|
refreshListView?.setOnRefreshListener {
|
|
|
|
listModel.refresh(refreshListView!!, arguments)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate the LiveData. This starts an API request in most cases
|
|
|
|
liveDataItems = getLiveData(arguments)
|
|
|
|
|
|
|
|
// Register an observer to update our UI when the data changes
|
2021-11-14 21:20:23 +01:00
|
|
|
liveDataItems.observe(viewLifecycleOwner, {
|
|
|
|
newItems -> viewAdapter.submitList(newItems)
|
|
|
|
})
|
2021-10-16 11:30:51 +02:00
|
|
|
|
|
|
|
// Setup the Music folder handling
|
|
|
|
listModel.getMusicFolders().observe(viewLifecycleOwner, musicFolderObserver)
|
|
|
|
|
|
|
|
// Create a View Manager
|
|
|
|
viewManager = LinearLayoutManager(this.context)
|
|
|
|
|
|
|
|
// Hook up the view with the manager and the adapter
|
|
|
|
listView = view.findViewById<RecyclerView>(recyclerViewId).apply {
|
|
|
|
setHasFixedSize(true)
|
|
|
|
layoutManager = viewManager
|
|
|
|
adapter = viewAdapter
|
|
|
|
}
|
|
|
|
|
|
|
|
// Configure whether to show the folder header
|
|
|
|
//viewAdapter.folderHeaderEnabled = showFolderHeader()
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
Util.applyTheme(this.context)
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onCreateView(
|
|
|
|
inflater: LayoutInflater,
|
|
|
|
container: ViewGroup?,
|
|
|
|
savedInstanceState: Bundle?
|
|
|
|
): View? {
|
|
|
|
return inflater.inflate(mainLayout, container, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract fun onContextMenuItemSelected(menuItem: MenuItem, item: T): Boolean
|
|
|
|
|
|
|
|
abstract fun onItemClick(item: T)
|
|
|
|
}
|
|
|
|
|
|
|
|
//abstract class EntryListFragment<T : GenericEntry, TA : GenericRowAdapter<T>> :
|
|
|
|
// GenericListFragment<T, TA>() {
|
|
|
|
// @Suppress("LongMethod")
|
|
|
|
// override fun onContextMenuItemSelected(menuItem: MenuItem, item: T): Boolean {
|
|
|
|
// val isArtist = (item is Artist)
|
|
|
|
//
|
|
|
|
// when (menuItem.itemId) {
|
|
|
|
// R.id.menu_play_now ->
|
|
|
|
// downloadHandler.downloadRecursively(
|
|
|
|
// this,
|
|
|
|
// item.id,
|
|
|
|
// save = false,
|
|
|
|
// append = false,
|
|
|
|
// autoPlay = true,
|
|
|
|
// shuffle = false,
|
|
|
|
// background = false,
|
|
|
|
// playNext = false,
|
|
|
|
// unpin = false,
|
|
|
|
// isArtist = isArtist
|
|
|
|
// )
|
|
|
|
// R.id.menu_play_next ->
|
|
|
|
// downloadHandler.downloadRecursively(
|
|
|
|
// this,
|
|
|
|
// item.id,
|
|
|
|
// save = false,
|
|
|
|
// append = false,
|
|
|
|
// autoPlay = true,
|
|
|
|
// shuffle = true,
|
|
|
|
// background = false,
|
|
|
|
// playNext = true,
|
|
|
|
// unpin = false,
|
|
|
|
// isArtist = isArtist
|
|
|
|
// )
|
|
|
|
// R.id.menu_play_last ->
|
|
|
|
// downloadHandler.downloadRecursively(
|
|
|
|
// this,
|
|
|
|
// item.id,
|
|
|
|
// save = false,
|
|
|
|
// append = true,
|
|
|
|
// autoPlay = false,
|
|
|
|
// shuffle = false,
|
|
|
|
// background = false,
|
|
|
|
// playNext = false,
|
|
|
|
// unpin = false,
|
|
|
|
// isArtist = isArtist
|
|
|
|
// )
|
|
|
|
// R.id.menu_pin ->
|
|
|
|
// downloadHandler.downloadRecursively(
|
|
|
|
// this,
|
|
|
|
// item.id,
|
|
|
|
// save = true,
|
|
|
|
// append = true,
|
|
|
|
// autoPlay = false,
|
|
|
|
// shuffle = false,
|
|
|
|
// background = false,
|
|
|
|
// playNext = false,
|
|
|
|
// unpin = false,
|
|
|
|
// isArtist = isArtist
|
|
|
|
// )
|
|
|
|
// R.id.menu_unpin ->
|
|
|
|
// downloadHandler.downloadRecursively(
|
|
|
|
// this,
|
|
|
|
// item.id,
|
|
|
|
// save = false,
|
|
|
|
// append = false,
|
|
|
|
// autoPlay = false,
|
|
|
|
// shuffle = false,
|
|
|
|
// background = false,
|
|
|
|
// playNext = false,
|
|
|
|
// unpin = true,
|
|
|
|
// isArtist = isArtist
|
|
|
|
// )
|
|
|
|
// R.id.menu_download ->
|
|
|
|
// downloadHandler.downloadRecursively(
|
|
|
|
// this,
|
|
|
|
// item.id,
|
|
|
|
// save = false,
|
|
|
|
// append = false,
|
|
|
|
// autoPlay = false,
|
|
|
|
// shuffle = false,
|
|
|
|
// background = true,
|
|
|
|
// playNext = false,
|
|
|
|
// unpin = false,
|
|
|
|
// isArtist = isArtist
|
|
|
|
// )
|
|
|
|
// }
|
|
|
|
// return true
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// override fun onItemClick(item: T) {
|
|
|
|
// val bundle = 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))
|
|
|
|
// findNavController().navigate(itemClickTarget, bundle)
|
|
|
|
// }
|
|
|
|
//}
|