-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Add download list in the App #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,72 @@ | ||||||||||||||||||||||||||
| package com.tpstreams.player | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import android.view.LayoutInflater | ||||||||||||||||||||||||||
| import android.view.View | ||||||||||||||||||||||||||
| import android.view.ViewGroup | ||||||||||||||||||||||||||
| import android.widget.ProgressBar | ||||||||||||||||||||||||||
| import android.widget.TextView | ||||||||||||||||||||||||||
| import androidx.media3.exoplayer.offline.Download | ||||||||||||||||||||||||||
| import androidx.recyclerview.widget.DiffUtil | ||||||||||||||||||||||||||
| import androidx.recyclerview.widget.ListAdapter | ||||||||||||||||||||||||||
| import androidx.recyclerview.widget.RecyclerView | ||||||||||||||||||||||||||
| import com.tpstreams.player.download.DownloadItem | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| class DownloadAdapter : ListAdapter<DownloadItem, DownloadAdapter.DownloadViewHolder>(DownloadDiffCallback()) { | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadViewHolder { | ||||||||||||||||||||||||||
| val view = LayoutInflater.from(parent.context).inflate(R.layout.item_download, parent, false) | ||||||||||||||||||||||||||
| return DownloadViewHolder(view) | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| override fun onBindViewHolder(holder: DownloadViewHolder, position: Int) { | ||||||||||||||||||||||||||
| holder.bind(getItem(position)) | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| class DownloadViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { | ||||||||||||||||||||||||||
| private val titleText: TextView = itemView.findViewById(R.id.title_text) | ||||||||||||||||||||||||||
| private val assetIdText: TextView = itemView.findViewById(R.id.asset_id_text) | ||||||||||||||||||||||||||
| private val progressBar: ProgressBar = itemView.findViewById(R.id.download_progress) | ||||||||||||||||||||||||||
| private val progressText: TextView = itemView.findViewById(R.id.progress_text) | ||||||||||||||||||||||||||
| private val stateText: TextView = itemView.findViewById(R.id.state_text) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| fun bind(downloadItem: DownloadItem) { | ||||||||||||||||||||||||||
| titleText.text = downloadItem.title | ||||||||||||||||||||||||||
| assetIdText.text = "Asset ID: ${downloadItem.assetId}" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Set progress | ||||||||||||||||||||||||||
| val progress = downloadItem.progressPercentage.toInt() | ||||||||||||||||||||||||||
| progressBar.progress = progress | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Show only percentage | ||||||||||||||||||||||||||
| progressText.text = "$progress%" | ||||||||||||||||||||||||||
|
Comment on lines
+37
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Clamp / guard progress to avoid illegal values
• Display a “-1%” label -val progress = downloadItem.progressPercentage.toInt()
-progressBar.progress = progress
-progressText.text = "$progress%"
+val raw = downloadItem.progressPercentage
+val clamped = raw.coerceIn(0f, 100f).toInt()
+progressBar.isIndeterminate = raw < 0
+progressBar.progress = clamped
+progressText.text = if (raw < 0) "—" else "$clamped%"📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Set state text | ||||||||||||||||||||||||||
| stateText.text = getStateString(downloadItem.state) | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private fun getStateString(state: Int): String { | ||||||||||||||||||||||||||
| return when (state) { | ||||||||||||||||||||||||||
| Download.STATE_COMPLETED -> "COMPLETED" | ||||||||||||||||||||||||||
| Download.STATE_DOWNLOADING -> "DOWNLOADING" | ||||||||||||||||||||||||||
| Download.STATE_FAILED -> "FAILED" | ||||||||||||||||||||||||||
| Download.STATE_QUEUED -> "QUEUED" | ||||||||||||||||||||||||||
| Download.STATE_REMOVING -> "REMOVING" | ||||||||||||||||||||||||||
| Download.STATE_RESTARTING -> "RESTARTING" | ||||||||||||||||||||||||||
| Download.STATE_STOPPED -> "PAUSED" | ||||||||||||||||||||||||||
| else -> "UNKNOWN" | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| class DownloadDiffCallback : DiffUtil.ItemCallback<DownloadItem>() { | ||||||||||||||||||||||||||
| override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { | ||||||||||||||||||||||||||
| return oldItem.assetId == newItem.assetId | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { | ||||||||||||||||||||||||||
| return oldItem == newItem | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,55 @@ | ||||||||||||||||||||||||||||||||||||||
| package com.tpstreams.player | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import android.app.Application | ||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.AndroidViewModel | ||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.LiveData | ||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.MutableLiveData | ||||||||||||||||||||||||||||||||||||||
| import androidx.media3.common.util.UnstableApi | ||||||||||||||||||||||||||||||||||||||
| import com.tpstreams.player.download.DownloadItem | ||||||||||||||||||||||||||||||||||||||
| import com.tpstreams.player.download.DownloadTracker | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @UnstableApi | ||||||||||||||||||||||||||||||||||||||
| class DownloadViewModel(application: Application) : AndroidViewModel(application) { | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| private val _downloads = MutableLiveData<List<DownloadItem>>() | ||||||||||||||||||||||||||||||||||||||
| val downloads: LiveData<List<DownloadItem>> = _downloads | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| private val _isLoading = MutableLiveData<Boolean>() | ||||||||||||||||||||||||||||||||||||||
| val isLoading: LiveData<Boolean> = _isLoading | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+17
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Initialize
-private val _isLoading = MutableLiveData<Boolean>()
+private val _isLoading = MutableLiveData(false)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| private val downloadTracker = DownloadTracker.getInstance(application) | ||||||||||||||||||||||||||||||||||||||
| private val downloadListener = object : DownloadTracker.Listener { | ||||||||||||||||||||||||||||||||||||||
| override fun onDownloadsChanged() { | ||||||||||||||||||||||||||||||||||||||
| loadDownloads() | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| init { | ||||||||||||||||||||||||||||||||||||||
| downloadTracker.addListener(downloadListener) | ||||||||||||||||||||||||||||||||||||||
| loadDownloads() | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| fun loadDownloads() { | ||||||||||||||||||||||||||||||||||||||
| _isLoading.value = true | ||||||||||||||||||||||||||||||||||||||
| val downloadItems = downloadTracker.getAllDownloadItems() | ||||||||||||||||||||||||||||||||||||||
| _downloads.value = downloadItems | ||||||||||||||||||||||||||||||||||||||
| _isLoading.value = false | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+32
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Off-load
-fun loadDownloads() {
- _isLoading.value = true
- val downloadItems = downloadTracker.getAllDownloadItems()
- _downloads.value = downloadItems
- _isLoading.value = false
-}
+fun loadDownloads() = viewModelScope.launch {
+ _isLoading.postValue(true)
+ val downloadItems = withContext(Dispatchers.IO) {
+ downloadTracker.getAllDownloadItems()
+ }
+ _downloads.postValue(downloadItems)
+ _isLoading.postValue(false)
+}(remember to add 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| fun pauseDownload(assetId: String) { | ||||||||||||||||||||||||||||||||||||||
| downloadTracker.pauseDownload(assetId) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| fun resumeDownload(assetId: String) { | ||||||||||||||||||||||||||||||||||||||
| downloadTracker.resumeDownload(assetId) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| fun removeDownload(assetId: String) { | ||||||||||||||||||||||||||||||||||||||
| downloadTracker.removeDownload(assetId) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| override fun onCleared() { | ||||||||||||||||||||||||||||||||||||||
| super.onCleared() | ||||||||||||||||||||||||||||||||||||||
| downloadTracker.removeListener(downloadListener) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,130 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.tpstreams.player | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import android.os.Bundle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import android.view.MenuItem | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import android.view.View | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import android.widget.PopupMenu | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.activity.viewModels | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.annotation.OptIn | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.appcompat.app.AppCompatActivity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.media3.common.util.UnstableApi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.media3.exoplayer.offline.Download | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.tpstreams.player.databinding.ActivityDownloadsBinding | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.tpstreams.player.download.DownloadItem | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @OptIn(UnstableApi::class) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class DownloadsActivity : AppCompatActivity() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private lateinit var binding: ActivityDownloadsBinding | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private val viewModel: DownloadViewModel by viewModels() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private lateinit var adapter: DownloadAdapter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onCreate(savedInstanceState: Bundle?) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super.onCreate(savedInstanceState) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding = ActivityDownloadsBinding.inflate(layoutInflater) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setContentView(binding.root) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Setup toolbar | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSupportActionBar(binding.toolbar) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| supportActionBar?.setDisplayHomeAsUpEnabled(true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Setup RecyclerView | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adapter = DownloadAdapter() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding.downloadsRecyclerView.adapter = adapter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding.downloadsRecyclerView.layoutManager = LinearLayoutManager(this) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Setup item click listener | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adapter.registerAdapterDataObserver(object : androidx.recyclerview.widget.RecyclerView.AdapterDataObserver() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onChanged() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkEmptyState() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+38
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Unregister the
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Observe downloads | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewModel.downloads.observe(this) { downloads -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adapter.submitList(downloads) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkEmptyState() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Observe loading state | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewModel.isLoading.observe(this) { isLoading -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding.progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Setup item click listener with popup menu | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setupItemClickListener() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private fun setupItemClickListener() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding.downloadsRecyclerView.addOnItemTouchListener( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RecyclerItemClickListener(this, binding.downloadsRecyclerView, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| object : RecyclerItemClickListener.OnItemClickListener { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onItemClick(view: View, position: Int) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val downloadItem = adapter.currentList[position] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| showPopupMenu(view, downloadItem) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onLongItemClick(view: View, position: Int) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Not needed for now | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private fun showPopupMenu(view: View, downloadItem: DownloadItem) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val popupMenu = PopupMenu(this, view) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| when (downloadItem.state) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Download.STATE_COMPLETED -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| popupMenu.menu.add(getString(R.string.delete_download_title)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Download.STATE_DOWNLOADING -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| popupMenu.menu.add(getString(R.string.pause_download)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| popupMenu.menu.add(getString(R.string.cancel_download)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Download.STATE_STOPPED -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| popupMenu.menu.add(getString(R.string.resume_download)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| popupMenu.menu.add(getString(R.string.cancel_download)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| popupMenu.menu.add(getString(R.string.cancel_download)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| popupMenu.setOnMenuItemClickListener { menuItem -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| when (menuItem.title) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getString(R.string.delete_download_title), getString(R.string.cancel_download) -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewModel.removeDownload(downloadItem.assetId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getString(R.string.pause_download) -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewModel.pauseDownload(downloadItem.assetId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getString(R.string.resume_download) -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewModel.resumeDownload(downloadItem.assetId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| popupMenu.show() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+75
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use stable menu item IDs instead of comparing titles Comparing - when (downloadItem.state) {
+ when (downloadItem.state) {
Download.STATE_COMPLETED -> {
- popupMenu.menu.add(getString(R.string.delete_download_title))
+ popupMenu.menu.add(0, R.id.menu_delete, 0, R.string.delete_download_title)
}
...
}
- popupMenu.setOnMenuItemClickListener { menuItem ->
- when (menuItem.title) {
- getString(R.string.delete_download_title), getString(R.string.cancel_download) -> {
+ popupMenu.setOnMenuItemClickListener { menuItem ->
+ when (menuItem.itemId) {
+ R.id.menu_delete, R.id.menu_cancel -> {
viewModel.removeDownload(downloadItem.assetId)
}
- getString(R.string.pause_download) -> {
+ R.id.menu_pause -> {
viewModel.pauseDownload(downloadItem.assetId)
}
- getString(R.string.resume_download) -> {
+ R.id.menu_resume -> {
viewModel.resumeDownload(downloadItem.assetId)
}
}
true
}Remember to declare these IDs in 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private fun checkEmptyState() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (adapter.itemCount == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding.emptyView.visibility = View.VISIBLE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding.downloadsRecyclerView.visibility = View.GONE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding.emptyView.visibility = View.GONE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| binding.downloadsRecyclerView.visibility = View.VISIBLE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (item.itemId == android.R.id.home) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| finish() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return super.onOptionsItemSelected(item) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,8 +12,8 @@ class PlayerUIViewModel(application: Application) : AndroidViewModel(application | |
| val player: TPStreamsPlayer by lazy { | ||
| TPStreamsPlayer.create( | ||
| context = application.applicationContext, | ||
| assetId = "8rEx9apZHFF", | ||
| accessToken = "19aa0055-d965-4654-8fce-b804e70a46b0", | ||
| assetId = "BEArYFdaFbt", | ||
| accessToken = "e6a1b485-daad-42eb-8cf2-6b6e51631092", | ||
|
Comment on lines
+15
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid committing credentials / tokens to VCS
At minimum, move them to -assetId = "BEArYFdaFbt",
-accessToken = "e6a1b485-daad-42eb-8cf2-6b6e51631092",
+assetId = BuildConfig.TP_ASSET_ID,
+accessToken = BuildConfig.TP_ACCESS_TOKEN,
🤖 Prompt for AI Agents |
||
| shouldAutoPlay = false | ||
| ) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package com.tpstreams.player | ||
|
|
||
| import android.content.Context | ||
| import android.view.GestureDetector | ||
| import android.view.MotionEvent | ||
| import android.view.View | ||
| import androidx.recyclerview.widget.RecyclerView | ||
|
|
||
| class RecyclerItemClickListener( | ||
| context: Context, | ||
| recyclerView: RecyclerView, | ||
| private val listener: OnItemClickListener? | ||
| ) : RecyclerView.OnItemTouchListener { | ||
|
|
||
| interface OnItemClickListener { | ||
| fun onItemClick(view: View, position: Int) | ||
| fun onLongItemClick(view: View, position: Int) | ||
| } | ||
|
|
||
| private val gestureDetector: GestureDetector | ||
|
|
||
| init { | ||
| gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() { | ||
| override fun onSingleTapUp(e: MotionEvent): Boolean { | ||
| return true | ||
| } | ||
|
|
||
| override fun onLongPress(e: MotionEvent) { | ||
| val childView = recyclerView.findChildViewUnder(e.x, e.y) | ||
| if (childView != null && listener != null) { | ||
| listener.onLongItemClick(childView, recyclerView.getChildAdapterPosition(childView)) | ||
| } | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean { | ||
| val childView = view.findChildViewUnder(e.x, e.y) | ||
| if (childView != null && listener != null && gestureDetector.onTouchEvent(e)) { | ||
| listener.onItemClick(childView, view.getChildAdapterPosition(childView)) | ||
| return true | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent) {} | ||
|
|
||
| override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {} | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace brittle
findViewByIdwith View BindingManual view look-ups are verbose, error-prone, and prevent the compiler from catching missing IDs.
Switching to View Binding (or Kotlin synthetic properties if you’re still on KTX) will:
• Remove the repeated casts
• Guarantee non-null references at compile time
• Reduce boilerplate in
onCreateViewHolder/ViewHolderExample refactor (View Binding):
And in
onCreateViewHolder:🤖 Prompt for AI Agents