Compare commits

...

2 commits

Author SHA1 Message Date
firelight
baf6294e96
Feat: Added progress to ProfilePhoto and AppLogin 2026-07-07 18:11:09 +00:00
firelight
c70bf620c9
Feat: Loading apply button 2026-07-07 17:03:57 +00:00
5 changed files with 162 additions and 94 deletions

View file

@ -37,8 +37,10 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDefaultAccount import com.lagradost.cloudstream3.utils.DataStoreHelper.getDefaultAccount
import com.lagradost.cloudstream3.utils.ImageLoader.loadImage import com.lagradost.cloudstream3.utils.ImageLoader.loadImage
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideProgress
import com.lagradost.cloudstream3.utils.UIHelper.navigate import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.showInputMethod import com.lagradost.cloudstream3.utils.UIHelper.showInputMethod
import com.lagradost.cloudstream3.utils.UIHelper.showProgress
object AccountHelper { object AccountHelper {
fun showAccountEditDialog( fun showAccountEditDialog(
@ -164,7 +166,7 @@ object AccountHelper {
canSetPin = true canSetPin = true
binding.editProfilePhotoButton.setOnClickListener({ binding.editProfilePhotoButton.setOnClickListener {
val bottomSheetDialog = BottomSheetDialog(context) val bottomSheetDialog = BottomSheetDialog(context)
val sheetBinding = BottomInputDialogBinding.inflate(LayoutInflater.from(context)) val sheetBinding = BottomInputDialogBinding.inflate(LayoutInflater.from(context))
bottomSheetDialog.setContentView(sheetBinding.root) bottomSheetDialog.setContentView(sheetBinding.root)
@ -174,9 +176,13 @@ object AccountHelper {
text1.text = context.getString(R.string.edit_profile_image_title) text1.text = context.getString(R.string.edit_profile_image_title)
nginxTextInput.hint = context.getString(R.string.edit_profile_image_hint) nginxTextInput.hint = context.getString(R.string.edit_profile_image_hint)
applyBtt.setOnClickListener({ applyBtt.setOnClickListener {
val url = sheetBinding.nginxTextInput.text.toString() val url = sheetBinding.nginxTextInput.text.toString()
if (url.isNotEmpty()) { if (url.isEmpty()) {
showToast(R.string.edit_profile_image_error_empty, Toast.LENGTH_SHORT)
return@setOnClickListener
}
applyBtt.showProgress()
val imageLoader = ImageLoader(context) val imageLoader = ImageLoader(context)
val request = ImageRequest.Builder(context) val request = ImageRequest.Builder(context)
.data(url) .data(url)
@ -189,27 +195,27 @@ object AccountHelper {
R.string.edit_profile_image_success, R.string.edit_profile_image_success,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
) )
bottomSheetDialog.dismiss() bottomSheetDialog.dismissSafe()
}, },
onError = { _, _ -> onError = { _, _ ->
showToast( showToast(
R.string.edit_profile_image_error_invalid, R.string.edit_profile_image_error_invalid,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
) )
applyBtt.hideProgress()
},
onCancel = {
applyBtt.hideProgress()
} }
) )
.build() .build()
imageLoader.enqueue(request) imageLoader.enqueue(request)
} else {
showToast(R.string.edit_profile_image_error_empty, Toast.LENGTH_SHORT)
} }
sheetBinding.cancelBtt.setOnClickListener {
bottomSheetDialog.dismissSafe() bottomSheetDialog.dismissSafe()
})
sheetBinding.cancelBtt.setOnClickListener({
bottomSheetDialog.dismissSafe()
})
} }
}) }
}
} }
fun showPinInputDialog( fun showPinInputDialog(

View file

@ -117,8 +117,10 @@ import com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding import com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding
import com.lagradost.cloudstream3.utils.UIHelper.hideProgress
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
import com.lagradost.cloudstream3.utils.UIHelper.showProgress
import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.cloudstream3.utils.UIHelper.toPx
import com.lagradost.cloudstream3.utils.downloader.DownloadUtils.getImageBitmapFromUrl import com.lagradost.cloudstream3.utils.downloader.DownloadUtils.getImageBitmapFromUrl
import com.lagradost.cloudstream3.utils.setText import com.lagradost.cloudstream3.utils.setText
@ -790,11 +792,24 @@ class GeneratorPlayer : FullScreenPlayer() {
} }
binding.applyBtt.setOnClickListener { binding.applyBtt.setOnClickListener {
currentSubtitle?.let { currentSubtitle -> val currentSubtitle = currentSubtitle
providers.firstOrNull { it.idPrefix == currentSubtitle.idPrefix }?.let { api -> if (currentSubtitle == null) {
dialog.dismissSafe()
return@setOnClickListener
}
val api = providers.firstOrNull { it.idPrefix == currentSubtitle.idPrefix }
if (api == null) {
dialog.dismissSafe()
return@setOnClickListener
}
binding.applyBtt.showProgress()
ioSafe { ioSafe {
when (val apiResource = val apiResource =
Resource.fromResult(api.resource(currentSubtitle))) { Resource.fromResult(api.resource(currentSubtitle))
binding.applyBtt.hideProgress()
when (apiResource) {
is Resource.Success -> { is Resource.Success -> {
val subtitles = apiResource.value.getSubtitles().map { resource -> val subtitles = apiResource.value.getSubtitles().map { resource ->
SubtitleData( SubtitleData(
@ -814,6 +829,7 @@ class GeneratorPlayer : FullScreenPlayer() {
showToast(R.string.no_subtitles) showToast(R.string.no_subtitles)
return@ioSafe return@ioSafe
} }
dialog.dismissSafe()
runOnMainThread { runOnMainThread {
addAndSelectSubtitles(*subtitles.toTypedArray()) addAndSelectSubtitles(*subtitles.toTypedArray())
} }
@ -829,9 +845,6 @@ class GeneratorPlayer : FullScreenPlayer() {
} }
} }
} }
}
dialog.dismissSafe()
}
dialog.setOnDismissListener { dialog.setOnDismissListener {
dismissCallback.invoke() dismissCallback.invoke()

View file

@ -65,6 +65,8 @@ import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogTe
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.hideProgress
import com.lagradost.cloudstream3.utils.UIHelper.showProgress
import com.lagradost.cloudstream3.utils.setText import com.lagradost.cloudstream3.utils.setText
import com.lagradost.cloudstream3.utils.txt import com.lagradost.cloudstream3.utils.txt
import qrcode.QRCode import qrcode.QRCode
@ -348,6 +350,7 @@ class SettingsAccount : BasePreferenceFragmentCompat(), BiometricCallback {
email = if (req.email) binding.loginEmailInput.text?.toString() else null, email = if (req.email) binding.loginEmailInput.text?.toString() else null,
server = if (req.server) binding.loginServerInput.text?.toString() else null, server = if (req.server) binding.loginServerInput.text?.toString() else null,
) )
binding.applyBtt.showProgress()
ioSafe { ioSafe {
try { try {
if (api.login(loginData)) { if (api.login(loginData)) {
@ -377,6 +380,8 @@ class SettingsAccount : BasePreferenceFragmentCompat(), BiometricCallback {
api.name api.name
) )
) )
} finally {
binding.applyBtt.hideProgress()
} }
} }
} }

View file

@ -39,6 +39,8 @@ import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideProgress
import com.lagradost.cloudstream3.utils.UIHelper.showProgress
import com.lagradost.cloudstream3.utils.setText import com.lagradost.cloudstream3.utils.setText
class ExtensionsFragment : BaseFragment<FragmentExtensionsBinding>( class ExtensionsFragment : BaseFragment<FragmentExtensionsBinding>(
@ -282,7 +284,9 @@ class ExtensionsFragment : BaseFragment<FragmentExtensionsBinding>(
showToast(R.string.error_invalid_url, Toast.LENGTH_SHORT) showToast(R.string.error_invalid_url, Toast.LENGTH_SHORT)
return@secondListener return@secondListener
} }
binding.applyBtt.showProgress()
ioSafe { ioSafe {
try {
val url = RepositoryManager.parseRepoUrl(urlInput) val url = RepositoryManager.parseRepoUrl(urlInput)
if (url.isNullOrBlank()) { if (url.isNullOrBlank()) {
showToast(R.string.error_invalid_data, Toast.LENGTH_SHORT) showToast(R.string.error_invalid_data, Toast.LENGTH_SHORT)
@ -314,6 +318,9 @@ class ExtensionsFragment : BaseFragment<FragmentExtensionsBinding>(
this@ExtensionsFragment.activity?.addRepositoryDialog( this@ExtensionsFragment.activity?.addRepositoryDialog(
newRepo newRepo
) )
} finally {
binding.applyBtt.hideProgress()
}
} }
} }
binding.cancelBtt.setOnClickListener { binding.cancelBtt.setOnClickListener {
@ -321,6 +328,7 @@ class ExtensionsFragment : BaseFragment<FragmentExtensionsBinding>(
} }
} }
val isTv = isLayout(TV) val isTv = isLayout(TV)
binding.apply { binding.apply {
addRepoButton.isGone = isTv addRepoButton.isGone = isTv

View file

@ -65,9 +65,12 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.palette.graphics.Palette import androidx.palette.graphics.Palette
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.button.MaterialButton
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipDrawable import com.google.android.material.chip.ChipDrawable
import com.google.android.material.chip.ChipGroup import com.google.android.material.chip.ChipGroup
import com.google.android.material.progressindicator.CircularProgressIndicatorSpec
import com.google.android.material.progressindicator.IndeterminateDrawable
import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.CloudStreamApp.Companion.context
import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
@ -583,6 +586,39 @@ object UIHelper {
} }
} }
/**
* Source: https://stackoverflow.com/questions/70954321/circular-progress-indicator-inside-buttons-android-material-design
*
* Shows indeterminate progress bar on this button in place of where icon would be.
* By default the tint of progress bar is the same as iconTint.
*
* @param tintColor (@ColorInt Int) Sets custom progress bar tint color.
*/
fun MaterialButton.showProgress(@ColorInt tintColor: Int = this.iconTint.defaultColor) =
// Use runOnMainThreadNative to allow process on io threads, to make the code a bit cleaner
runOnMainThreadNative {
val spec = CircularProgressIndicatorSpec(
context, null, 0,
com.google.android.material.R.style.Widget_Material3_CircularProgressIndicator_ExtraSmall
)
spec.indicatorColors = intArrayOf(tintColor)
val progressIndicatorDrawable =
IndeterminateDrawable.createCircularDrawable(context, spec)
this.icon = progressIndicatorDrawable
if (this.getTag(R.id.text1) == null)
this.setTag(R.id.text1, this.text)
this.text = ""
}
fun MaterialButton.hideProgress() =
runOnMainThreadNative {
this.text = this.getTag(R.id.text1) as? String
this.icon = null
}
/**id, stringRes */ /**id, stringRes */
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
fun View.popupMenuNoIcons( fun View.popupMenuNoIcons(