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 : 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 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> /** * The central function to pass a query to the model and return a LiveData object */ abstract fun getLiveData(args: Bundle? = null): LiveData> /** * 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 -> // 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(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> : // GenericListFragment() { // @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) // } // }