From e495b3a02833d645872a4eb51e65b24e7828b990 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Mon, 8 Jul 2024 20:27:18 -0600 Subject: [PATCH] Introduce and use SnackbarHelper, and UX fixes --- .../lagradost/cloudstream3/MainActivity.kt | 21 ++--- .../ui/download/DownloadAdapter.kt | 85 +++++++------------ .../ui/download/DownloadButtonSetup.kt | 19 +++++ .../ui/download/DownloadChildFragment.kt | 9 +- .../ui/download/DownloadFragment.kt | 9 +- .../cloudstream3/utils/SnackbarHelper.kt | 69 +++++++++++++++ app/src/main/res/values/strings.xml | 1 + 7 files changed, 133 insertions(+), 80 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/utils/SnackbarHelper.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index a47e7685..02fac43a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -149,6 +149,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching import com.lagradost.cloudstream3.utils.Event import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog +import com.lagradost.cloudstream3.utils.SnackbarHelper.showSnackbar import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState import com.lagradost.cloudstream3.utils.UIHelper.checkWrite import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute @@ -1240,17 +1241,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa this.setKey(getString(R.string.jsdelivr_proxy_key), false) } else { this.setKey(getString(R.string.jsdelivr_proxy_key), true) - val parentView: View = findViewById(android.R.id.content) - Snackbar.make(parentView, R.string.jsdelivr_enabled, Snackbar.LENGTH_LONG) - .let { snackbar -> - snackbar.setAction(R.string.revert) { - setKey(getString(R.string.jsdelivr_proxy_key), false) - } - snackbar.setBackgroundTint(colorFromAttribute(R.attr.primaryGrayBackground)) - snackbar.setTextColor(colorFromAttribute(R.attr.textColor)) - snackbar.setActionTextColor(colorFromAttribute(R.attr.colorPrimary)) - snackbar.show() - } + showSnackbar( + this@MainActivity, + R.string.jsdelivr_enabled, + Snackbar.LENGTH_LONG, + getString(R.string.revert)) { + setKey(getString(R.string.jsdelivr_proxy_key), false) + } } } } @@ -1846,4 +1843,4 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa false } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt index cfb6c66f..c13f8cd9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt @@ -94,6 +94,20 @@ class DownloadAdapter( val data = card.data binding.apply { + episodeHolder.apply { + if (isMultiDeleteState) { + setOnClickListener { + toggleIsChecked(deleteCheckbox, card) + } + } + + setOnLongClickListener { + multiDeleteStateCallback.invoke(card) + toggleIsChecked(deleteCheckbox, card) + true + } + } + downloadHeaderPoster.apply { setImage(data.poster) if (isMultiDeleteState) { @@ -108,6 +122,7 @@ class DownloadAdapter( setOnLongClickListener { multiDeleteStateCallback.invoke(card) + toggleIsChecked(deleteCheckbox, card) true } } @@ -162,25 +177,9 @@ class DownloadAdapter( downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, mediaClickCallback) downloadButton.isVisible = !isMultiDeleteState - downloadButton.setOnLongClickListener { - multiDeleteStateCallback.invoke(card) - true - } - - episodeHolder.apply { - if (isMultiDeleteState) { - setOnClickListener { - toggleIsChecked(deleteCheckbox, card) - } - } else { - setOnClickListener { - mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, card.child)) - } - } - - setOnLongClickListener { - multiDeleteStateCallback.invoke(card) - true + if (!isMultiDeleteState) { + episodeHolder.setOnClickListener { + mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, card.child)) } } } @@ -204,20 +203,9 @@ class DownloadAdapter( logError(e) } - episodeHolder.apply { - if (isMultiDeleteState) { - setOnClickListener { - toggleIsChecked(deleteCheckbox, card) - } - } else { - setOnClickListener { - headerClickCallback.invoke(DownloadHeaderClickEvent(DOWNLOAD_ACTION_GO_TO_CHILD, card.data)) - } - } - - setOnLongClickListener { - multiDeleteStateCallback.invoke(card) - true + if (!isMultiDeleteState) { + episodeHolder.setOnClickListener { + headerClickCallback.invoke(DownloadHeaderClickEvent(DOWNLOAD_ACTION_GO_TO_CHILD, card.data)) } } } @@ -260,11 +248,6 @@ class DownloadAdapter( downloadButton.setDefaultClickListener(data, downloadChildEpisodeTextExtra, mediaClickCallback) downloadButton.isVisible = !isMultiDeleteState - downloadButton.setOnLongClickListener { - multiDeleteStateCallback.invoke(card) - true - } - downloadChildEpisodeText.apply { text = context.getNameFull(data.name, data.episode, data.season) isSelected = true // Needed for text repeating @@ -275,18 +258,22 @@ class DownloadAdapter( } downloadChildEpisodeHolder.apply { - if (isMultiDeleteState) { - setOnClickListener { - toggleIsChecked(deleteCheckbox, card) + when { + isMultiDeleteState -> { + setOnClickListener { + toggleIsChecked(deleteCheckbox, card) + } } - } else { - setOnClickListener { - mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, data)) + else -> { + setOnClickListener { + mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, data)) + } } } setOnLongClickListener { multiDeleteStateCallback.invoke(card) + toggleIsChecked(deleteCheckbox, card) true } } @@ -338,16 +325,6 @@ class DownloadAdapter( } else notifyItemRangeChanged(0, itemCount) } - fun updateSelectedItem(id: Int, isSelected: Boolean) { - if (isSelected) { - selectedIds[id] = true - } else selectedIds.remove(id) - val position = currentList.indexOfFirst { it.data.id == id } - if (position != -1) { - notifyItemChanged(position) - } - } - fun selectAllItems() { currentList.forEachIndexed { index, item -> val id = item.data.id diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt index 82bb7558..43907db9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.download import android.content.DialogInterface import androidx.appcompat.app.AlertDialog +import com.google.android.material.snackbar.Snackbar import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.R @@ -12,6 +13,7 @@ import com.lagradost.cloudstream3.ui.player.GeneratorPlayer import com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE +import com.lagradost.cloudstream3.utils.SnackbarHelper.showSnackbar import com.lagradost.cloudstream3.utils.UIHelper.navigate import com.lagradost.cloudstream3.utils.VideoDownloadHelper import com.lagradost.cloudstream3.utils.VideoDownloadManager @@ -78,6 +80,23 @@ object DownloadButtonSetup { } } } + DOWNLOAD_ACTION_LONG_CLICK -> { + activity?.let { act -> + val length = + VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( + act, + click.data.id + )?.fileLength + ?: 0 + if (length > 0) { + showSnackbar( + act, + R.string.offline_file, + Snackbar.LENGTH_LONG + ) + } + } + } DOWNLOAD_ACTION_PLAY_FILE -> { activity?.let { act -> val info = diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt index c9855d2a..5aefbcc2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt @@ -42,6 +42,7 @@ class DownloadChildFragment : Fragment() { override fun onDestroyView() { downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it } downloadDeleteEventListener = null + detachBackPressedCallback() binding = null super.onDestroyView() } @@ -131,13 +132,7 @@ class DownloadChildFragment : Fragment() { downloadsViewModel.addSelected(card) } else downloadsViewModel.removeSelected(card) }, - { card -> - downloadsViewModel.addSelected(card) - (binding?.downloadChildList?.adapter as? DownloadAdapter)?.updateSelectedItem( - card.data.id, - true - ) - } + { card -> downloadsViewModel.addSelected(card) } ) binding?.downloadChildList?.apply { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt index b8187e79..618c4657 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt @@ -68,6 +68,7 @@ class DownloadFragment : Fragment() { override fun onDestroyView() { downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it } downloadDeleteEventListener = null + detachBackPressedCallback() binding = null super.onDestroyView() } @@ -130,13 +131,7 @@ class DownloadFragment : Fragment() { downloadsViewModel.addSelected(card) } else downloadsViewModel.removeSelected(card) }, - { card -> - downloadsViewModel.addSelected(card) - (binding?.downloadList?.adapter as? DownloadAdapter)?.updateSelectedItem( - card.data.id, - true - ) - } + { card -> downloadsViewModel.addSelected(card) } ) binding?.downloadList?.apply { diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/SnackbarHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/SnackbarHelper.kt new file mode 100644 index 00000000..43981420 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/SnackbarHelper.kt @@ -0,0 +1,69 @@ +package com.lagradost.cloudstream3.utils + +import android.app.Activity +import android.view.View +import androidx.annotation.MainThread +import androidx.annotation.StringRes +import com.google.android.material.snackbar.Snackbar +import com.lagradost.api.Log +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute + +object SnackbarHelper { + + private const val TAG = "COMPACT" + private var currentSnackbar: Snackbar? = null + + @MainThread + fun showSnackbar( + act: Activity?, + @StringRes message: Int, + duration: Int = Snackbar.LENGTH_SHORT, + actionText: String? = null, + actionCallback: (() -> Unit)? = null + ) { + if (act == null) return + showSnackbar(act, act.getString(message), duration, actionText, actionCallback) + } + + @MainThread + fun showSnackbar( + act: Activity?, + message: String?, + duration: Int = Snackbar.LENGTH_SHORT, + actionText: String? = null, + actionCallback: (() -> Unit)? = null + ) { + if (act == null || message == null) { + Log.w(TAG, "Invalid showSnackbar: act = $act, message = $message") + return + } + Log.i(TAG, "showSnackbar: $message") + + try { + currentSnackbar?.dismiss() + } catch (e: Exception) { + logError(e) + } + + try { + val parentView = act.findViewById(android.R.id.content) + val snackbar = Snackbar.make(parentView, message, duration) + + actionCallback?.let { + snackbar.setAction(actionText) { actionCallback.invoke() } + } + + snackbar.show() + currentSnackbar = snackbar + + snackbar.setBackgroundTint(act.colorFromAttribute(R.attr.primaryBlackBackground)) + snackbar.setTextColor(act.colorFromAttribute(R.attr.textColor)) + snackbar.setActionTextColor(act.colorFromAttribute(R.attr.colorPrimary)) + + } catch (e: Exception) { + logError(e) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c94e963e..322c54cd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -150,6 +150,7 @@ Download Done %s - %s There are currently no downloads. + Available for watching offline Select All Update Started Network stream