package org.moire.ultrasonic.fragment import android.app.Application import android.content.Context import android.graphics.drawable.Drawable import android.os.Bundle import android.view.MenuItem import android.view.View import android.widget.CheckedTextView import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import androidx.core.view.isVisible import androidx.fragment.app.viewModels import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.recyclerview.widget.RecyclerView import org.koin.core.component.inject import org.moire.ultrasonic.R import org.moire.ultrasonic.service.DownloadFile import org.moire.ultrasonic.service.DownloadStatus import org.moire.ultrasonic.service.Downloader import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.view.SongView class DownloadsFragment : GenericListFragment() { /** * The ViewModel to use to get the data */ override val listModel: DownloadListModel by viewModels() /** * The id of the main layout */ override val mainLayout: Int = R.layout.generic_list /** * The id of the refresh view */ override val refreshListId: Int = R.id.generic_list_refresh /** * The id of the RecyclerView */ override val recyclerViewId = R.id.generic_list_recycler /** * The id of the target in the navigation graph where we should go, * after the user has clicked on an item */ // FIXME override val itemClickTarget: Int = R.id.trackCollectionFragment /** * The central function to pass a query to the model and return a LiveData object */ override fun getLiveData(args: Bundle?): LiveData> { return listModel.getList() } /** * Provide the Adapter for the RecyclerView with a lazy delegate */ override val viewAdapter: DownloadRowAdapter by lazy { DownloadRowAdapter( liveDataItems.value ?: listOf(), { entry -> onItemClick(entry) }, { menuItem, entry -> onContextMenuItemSelected(menuItem, entry) }, onMusicFolderUpdate, requireContext(), viewLifecycleOwner ) } override fun onContextMenuItemSelected(menuItem: MenuItem, item: DownloadFile): Boolean { // Do nothing return true } override fun onItemClick(item: DownloadFile) { // Do nothing } override fun setTitle(title: String?) { FragmentTitle.setTitle(this, Util.appContext().getString(R.string.menu_downloads)) } } class DownloadRowAdapter( itemList: List, onItemClick: (DownloadFile) -> Unit, onContextMenuClick: (MenuItem, DownloadFile) -> Boolean, onMusicFolderUpdate: (String?) -> Unit, context: Context, val lifecycleOwner: LifecycleOwner ) : GenericRowAdapter( onItemClick, onContextMenuClick, onMusicFolderUpdate ) { init { super.submitList(itemList) } private val starDrawable: Drawable = Util.getDrawableFromAttribute(context, R.attr.star_full) private val starHollowDrawable: Drawable = Util.getDrawableFromAttribute(context, R.attr.star_hollow) // Set our layout files override val layout = R.layout.song_list_item override val contextMenuLayout = R.menu.artist_context_menu override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { if (holder is ViewHolder) { val downloadFile = currentList[position] val entry = downloadFile.song holder.title.text = entry.title holder.artist.text = entry.artist holder.star.setImageDrawable(if (entry.starred) starDrawable else starHollowDrawable) // Observe download status downloadFile.status.observe( lifecycleOwner, { updateDownloadStatus(downloadFile, holder) } ) downloadFile.progress.observe( lifecycleOwner, { updateDownloadStatus(downloadFile, holder) } ) } } private fun updateDownloadStatus( downloadFile: DownloadFile, holder: ViewHolder ) { var image: Drawable? = null when (downloadFile.status.value) { DownloadStatus.DONE -> { image = if (downloadFile.isSaved) SongView.pinImage else SongView.downloadedImage holder.status.text = null } DownloadStatus.DOWNLOADING -> { holder.status.text = Util.formatPercentage(downloadFile.progress.value!!) image = SongView.downloadingImage } else -> { holder.status.text = null } } // TODO: Migrate the image animation stuff from SongView into this class // // if (image != null) { // holder.status.setCompoundDrawablesWithIntrinsicBounds( // image, null, image, null // ) // } // // if (image === SongView.downloadingImage) { // val frameAnimation = image as AnimationDrawable // // frameAnimation.setVisible(true, true) // frameAnimation.start() // } } /** * Holds the view properties of an Item row */ class ViewHolder( view: View ) : RecyclerView.ViewHolder(view) { var check: CheckedTextView = view.findViewById(R.id.song_check) var rating: LinearLayout = view.findViewById(R.id.song_rating) var fiveStar1: ImageView = view.findViewById(R.id.song_five_star_1) var fiveStar2: ImageView = view.findViewById(R.id.song_five_star_2) var fiveStar3: ImageView = view.findViewById(R.id.song_five_star_3) var fiveStar4: ImageView = view.findViewById(R.id.song_five_star_4) var fiveStar5: ImageView = view.findViewById(R.id.song_five_star_5) var star: ImageView = view.findViewById(R.id.song_star) var drag: ImageView = view.findViewById(R.id.song_drag) var track: TextView = view.findViewById(R.id.song_track) var title: TextView = view.findViewById(R.id.song_title) var artist: TextView = view.findViewById(R.id.song_artist) var duration: TextView = view.findViewById(R.id.song_duration) var status: TextView = view.findViewById(R.id.song_status) init { drag.isVisible = false star.isVisible = false fiveStar1.isVisible = false fiveStar2.isVisible = false fiveStar3.isVisible = false fiveStar4.isVisible = false fiveStar5.isVisible = false check.isVisible = false } } /** * Creates an instance of our ViewHolder class */ override fun newViewHolder(view: View): RecyclerView.ViewHolder { return ViewHolder(view) } } class DownloadListModel(application: Application) : GenericListModel(application) { private val downloader by inject() fun getList(): LiveData> { return downloader.observableList } }