mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Introduce and use SnackbarHelper, and UX fixes
This commit is contained in:
parent
4bc62f133c
commit
e495b3a028
7 changed files with 133 additions and 80 deletions
|
@ -149,6 +149,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
|
||||||
import com.lagradost.cloudstream3.utils.Event
|
import com.lagradost.cloudstream3.utils.Event
|
||||||
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
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.changeStatusBarState
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
|
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
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)
|
this.setKey(getString(R.string.jsdelivr_proxy_key), false)
|
||||||
} else {
|
} else {
|
||||||
this.setKey(getString(R.string.jsdelivr_proxy_key), true)
|
this.setKey(getString(R.string.jsdelivr_proxy_key), true)
|
||||||
val parentView: View = findViewById(android.R.id.content)
|
showSnackbar(
|
||||||
Snackbar.make(parentView, R.string.jsdelivr_enabled, Snackbar.LENGTH_LONG)
|
this@MainActivity,
|
||||||
.let { snackbar ->
|
R.string.jsdelivr_enabled,
|
||||||
snackbar.setAction(R.string.revert) {
|
Snackbar.LENGTH_LONG,
|
||||||
setKey(getString(R.string.jsdelivr_proxy_key), false)
|
getString(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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,20 @@ class DownloadAdapter(
|
||||||
|
|
||||||
val data = card.data
|
val data = card.data
|
||||||
binding.apply {
|
binding.apply {
|
||||||
|
episodeHolder.apply {
|
||||||
|
if (isMultiDeleteState) {
|
||||||
|
setOnClickListener {
|
||||||
|
toggleIsChecked(deleteCheckbox, card)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnLongClickListener {
|
||||||
|
multiDeleteStateCallback.invoke(card)
|
||||||
|
toggleIsChecked(deleteCheckbox, card)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
downloadHeaderPoster.apply {
|
downloadHeaderPoster.apply {
|
||||||
setImage(data.poster)
|
setImage(data.poster)
|
||||||
if (isMultiDeleteState) {
|
if (isMultiDeleteState) {
|
||||||
|
@ -108,6 +122,7 @@ class DownloadAdapter(
|
||||||
|
|
||||||
setOnLongClickListener {
|
setOnLongClickListener {
|
||||||
multiDeleteStateCallback.invoke(card)
|
multiDeleteStateCallback.invoke(card)
|
||||||
|
toggleIsChecked(deleteCheckbox, card)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,25 +177,9 @@ class DownloadAdapter(
|
||||||
downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, mediaClickCallback)
|
downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, mediaClickCallback)
|
||||||
downloadButton.isVisible = !isMultiDeleteState
|
downloadButton.isVisible = !isMultiDeleteState
|
||||||
|
|
||||||
downloadButton.setOnLongClickListener {
|
if (!isMultiDeleteState) {
|
||||||
multiDeleteStateCallback.invoke(card)
|
episodeHolder.setOnClickListener {
|
||||||
true
|
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, card.child))
|
||||||
}
|
|
||||||
|
|
||||||
episodeHolder.apply {
|
|
||||||
if (isMultiDeleteState) {
|
|
||||||
setOnClickListener {
|
|
||||||
toggleIsChecked(deleteCheckbox, card)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setOnClickListener {
|
|
||||||
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, card.child))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setOnLongClickListener {
|
|
||||||
multiDeleteStateCallback.invoke(card)
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,20 +203,9 @@ class DownloadAdapter(
|
||||||
logError(e)
|
logError(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
episodeHolder.apply {
|
if (!isMultiDeleteState) {
|
||||||
if (isMultiDeleteState) {
|
episodeHolder.setOnClickListener {
|
||||||
setOnClickListener {
|
headerClickCallback.invoke(DownloadHeaderClickEvent(DOWNLOAD_ACTION_GO_TO_CHILD, card.data))
|
||||||
toggleIsChecked(deleteCheckbox, card)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setOnClickListener {
|
|
||||||
headerClickCallback.invoke(DownloadHeaderClickEvent(DOWNLOAD_ACTION_GO_TO_CHILD, card.data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setOnLongClickListener {
|
|
||||||
multiDeleteStateCallback.invoke(card)
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,11 +248,6 @@ class DownloadAdapter(
|
||||||
downloadButton.setDefaultClickListener(data, downloadChildEpisodeTextExtra, mediaClickCallback)
|
downloadButton.setDefaultClickListener(data, downloadChildEpisodeTextExtra, mediaClickCallback)
|
||||||
downloadButton.isVisible = !isMultiDeleteState
|
downloadButton.isVisible = !isMultiDeleteState
|
||||||
|
|
||||||
downloadButton.setOnLongClickListener {
|
|
||||||
multiDeleteStateCallback.invoke(card)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadChildEpisodeText.apply {
|
downloadChildEpisodeText.apply {
|
||||||
text = context.getNameFull(data.name, data.episode, data.season)
|
text = context.getNameFull(data.name, data.episode, data.season)
|
||||||
isSelected = true // Needed for text repeating
|
isSelected = true // Needed for text repeating
|
||||||
|
@ -275,18 +258,22 @@ class DownloadAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadChildEpisodeHolder.apply {
|
downloadChildEpisodeHolder.apply {
|
||||||
if (isMultiDeleteState) {
|
when {
|
||||||
setOnClickListener {
|
isMultiDeleteState -> {
|
||||||
toggleIsChecked(deleteCheckbox, card)
|
setOnClickListener {
|
||||||
|
toggleIsChecked(deleteCheckbox, card)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
else -> {
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, data))
|
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, data))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setOnLongClickListener {
|
setOnLongClickListener {
|
||||||
multiDeleteStateCallback.invoke(card)
|
multiDeleteStateCallback.invoke(card)
|
||||||
|
toggleIsChecked(deleteCheckbox, card)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,16 +325,6 @@ class DownloadAdapter(
|
||||||
} else notifyItemRangeChanged(0, itemCount)
|
} 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() {
|
fun selectAllItems() {
|
||||||
currentList.forEachIndexed { index, item ->
|
currentList.forEachIndexed { index, item ->
|
||||||
val id = item.data.id
|
val id = item.data.id
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.download
|
||||||
|
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.activity
|
import com.lagradost.cloudstream3.CommonActivity.activity
|
||||||
import com.lagradost.cloudstream3.R
|
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.getNameFull
|
||||||
import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus
|
import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
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.UIHelper.navigate
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
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 -> {
|
DOWNLOAD_ACTION_PLAY_FILE -> {
|
||||||
activity?.let { act ->
|
activity?.let { act ->
|
||||||
val info =
|
val info =
|
||||||
|
|
|
@ -42,6 +42,7 @@ class DownloadChildFragment : Fragment() {
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
||||||
downloadDeleteEventListener = null
|
downloadDeleteEventListener = null
|
||||||
|
detachBackPressedCallback()
|
||||||
binding = null
|
binding = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
@ -131,13 +132,7 @@ class DownloadChildFragment : Fragment() {
|
||||||
downloadsViewModel.addSelected(card)
|
downloadsViewModel.addSelected(card)
|
||||||
} else downloadsViewModel.removeSelected(card)
|
} else downloadsViewModel.removeSelected(card)
|
||||||
},
|
},
|
||||||
{ card ->
|
{ card -> downloadsViewModel.addSelected(card) }
|
||||||
downloadsViewModel.addSelected(card)
|
|
||||||
(binding?.downloadChildList?.adapter as? DownloadAdapter)?.updateSelectedItem(
|
|
||||||
card.data.id,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
binding?.downloadChildList?.apply {
|
binding?.downloadChildList?.apply {
|
||||||
|
|
|
@ -68,6 +68,7 @@ class DownloadFragment : Fragment() {
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
||||||
downloadDeleteEventListener = null
|
downloadDeleteEventListener = null
|
||||||
|
detachBackPressedCallback()
|
||||||
binding = null
|
binding = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
@ -130,13 +131,7 @@ class DownloadFragment : Fragment() {
|
||||||
downloadsViewModel.addSelected(card)
|
downloadsViewModel.addSelected(card)
|
||||||
} else downloadsViewModel.removeSelected(card)
|
} else downloadsViewModel.removeSelected(card)
|
||||||
},
|
},
|
||||||
{ card ->
|
{ card -> downloadsViewModel.addSelected(card) }
|
||||||
downloadsViewModel.addSelected(card)
|
|
||||||
(binding?.downloadList?.adapter as? DownloadAdapter)?.updateSelectedItem(
|
|
||||||
card.data.id,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
binding?.downloadList?.apply {
|
binding?.downloadList?.apply {
|
||||||
|
|
|
@ -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<View>(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -150,6 +150,7 @@
|
||||||
<string name="download_done">Download Done</string>
|
<string name="download_done">Download Done</string>
|
||||||
<string name="download_format" translatable="false">%s - %s</string>
|
<string name="download_format" translatable="false">%s - %s</string>
|
||||||
<string name="downloads_empty">There are currently no downloads.</string>
|
<string name="downloads_empty">There are currently no downloads.</string>
|
||||||
|
<string name="offline_file">Available for watching offline</string>
|
||||||
<string name="select_all">Select All</string>
|
<string name="select_all">Select All</string>
|
||||||
<string name="update_started">Update Started</string>
|
<string name="update_started">Update Started</string>
|
||||||
<string name="stream">Network stream</string>
|
<string name="stream">Network stream</string>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue