ultrasonic-app-subsonic-and.../ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MultiListFragment.kt

287 lines
9.8 KiB
Kotlin

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.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.moire.ultrasonic.R
import org.moire.ultrasonic.adapters.MultiTypeDiffAdapter
import org.moire.ultrasonic.data.ActiveServerProvider
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)
*/
abstract class MultiListFragment<T : Identifiable> : Fragment() {
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
*/
internal val viewAdapter: MultiTypeDiffAdapter<Identifiable> by lazy {
MultiTypeDiffAdapter()
}
/**
* 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
/**
* The id of the main layout
*/
open val mainLayout: Int = R.layout.generic_list
/**
* The id of the refresh view
*/
open val refreshListId: Int = R.id.generic_list_refresh
/**
* The id of the RecyclerView
*/
open val recyclerViewId = R.id.generic_list_recycler
/**
* 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
liveDataItems.observe(
viewLifecycleOwner,
{
newItems ->
viewAdapter.submitList(newItems)
}
)
// 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)
// }
// }