From b0a6f0d30dd06f00e539c53dd58fe650541dad6e Mon Sep 17 00:00:00 2001 From: LagradOst <11805592+LagradOst@users.noreply.github.com> Date: Mon, 9 Nov 2026 19:39:59 +0100 Subject: [PATCH] Fixed launch --- .../lagradost/cloudstream3/CommonActivity.kt | 3 +- .../cloudstream3/actions/VideoClickAction.kt | 3 +- .../cloudstream3/ui/account/AccountScreen.kt | 3 +- .../ui/download/DownloadFragment.kt | 3 +- .../cloudstream3/ui/player/GeneratorPlayer.kt | 38 ++++++++-------- .../ui/settings/SettingsFragmentScreen.kt | 17 +++++++ .../ui/settings/SettingsGeneral.kt | 7 +-- .../ui/settings/SettingsGeneralScreen.kt | 3 +- .../ui/settings/SettingsUpdates.kt | 9 ++-- .../ui/settings/SettingsUpdatesScreen.kt | 3 +- .../ui/subtitles/SubtitlesScreen.kt | 3 +- .../cloudstream3/utils/BackupUtils.kt | 45 ++++++++++--------- 12 files changed, 79 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt index 8daf168c1c1..d541a52ab12 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt @@ -50,6 +50,7 @@ import com.lagradost.cloudstream3.ui.search.SearchAdapter import com.lagradost.cloudstream3.ui.settings.Globals.isLayout import com.lagradost.cloudstream3.ui.settings.Globals.TV import com.lagradost.cloudstream3.ui.settings.Globals.updateTv +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.ui.settings.extensions.PluginAdapter import com.lagradost.cloudstream3.utils.AppContextUtils.isRtl import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled @@ -280,7 +281,7 @@ object CommonActivity { ) { isGranted: Boolean -> Log.d(TAG, "Notification permission: $isGranted") } - requestPermissionLauncher.launch( + requestPermissionLauncher.launchSafe( Manifest.permission.POST_NOTIFICATIONS ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt index 0fdccb47660..fb5be07eb21 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt @@ -34,6 +34,7 @@ import com.lagradost.cloudstream3.actions.temp.fcast.FcastAction import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.ui.result.LinkLoadingResult import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.utils.Coroutines.atomicListOf import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.ExtractorLinkType @@ -143,7 +144,7 @@ abstract class VideoClickAction { } uiThread { - MainActivity.activityResultLauncher?.launch(intent,options) + MainActivity.activityResultLauncher?.launchSafe(intent, options) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountScreen.kt index 056d3224e2c..90c5c38c135 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountScreen.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountScreen.kt @@ -65,6 +65,7 @@ import coil3.compose.AsyncImage import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.utils.DataStoreHelper import com.lagradost.cloudstream3.utils.DataStoreHelper.Account import com.lagradost.cloudstream4.compose.ActionDialog @@ -430,7 +431,7 @@ object AccountScreen { DropdownMenuItem( text = { Text(text = stringResource(R.string.edit_profile_image_picker)) }, onClick = { - selectFileSelector.launch(arrayOf("image/*")) + selectFileSelector.launchSafe(arrayOf("image/*")) selectProfileImage = false } ) 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 abc432ef959..a0fb3a2fe0e 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 @@ -40,6 +40,7 @@ import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR import com.lagradost.cloudstream3.ui.settings.Globals.TV import com.lagradost.cloudstream3.ui.settings.Globals.isLandscape import com.lagradost.cloudstream3.ui.settings.Globals.isLayout +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.utils.AppContextUtils.loadResult import com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback import com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback @@ -306,7 +307,7 @@ class DownloadFragment : BaseFragment( .addCategory(Intent.CATEGORY_OPENABLE) .addFlags(FLAG_GRANT_READ_URI_PERMISSION) // Request temporary access safe { - videoResultLauncher.launch( + videoResultLauncher.launchSafe( Intent.createChooser( intent, getString(R.string.open_local_video) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index e4616c93bcf..49422f3f1e3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -98,6 +98,7 @@ import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR import com.lagradost.cloudstream3.ui.settings.Globals.PHONE import com.lagradost.cloudstream3.ui.settings.Globals.TV import com.lagradost.cloudstream3.ui.settings.Globals.isLayout +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.ui.subtitles.SUBTITLE_AUTO_SELECT_KEY import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.getAutoSelectLanguageTagIETF @@ -862,23 +863,19 @@ class GeneratorPlayer : FullScreenPlayer() { } private fun openSubPicker() { - try { - subsPathPicker.launch( - arrayOf( - "text/plain", - "text/str", - "application/octet-stream", - MimeTypes.TEXT_UNKNOWN, - MimeTypes.TEXT_VTT, - MimeTypes.TEXT_SSA, - MimeTypes.APPLICATION_TTML, - MimeTypes.APPLICATION_MP4VTT, - MimeTypes.APPLICATION_SUBRIP, - ) + subsPathPicker.launchSafe( + arrayOf( + "text/plain", + "text/str", + "application/octet-stream", + MimeTypes.TEXT_UNKNOWN, + MimeTypes.TEXT_VTT, + MimeTypes.TEXT_SSA, + MimeTypes.APPLICATION_TTML, + MimeTypes.APPLICATION_MP4VTT, + MimeTypes.APPLICATION_SUBRIP, ) - } catch (e: Exception) { - logError(e) - } + ) } @MainThread @@ -1125,7 +1122,8 @@ class GeneratorPlayer : FullScreenPlayer() { // Always display current linkFooter val sortedLinks = viewModel.state.sortLinks(qualityProfile) - filteredLinks = sortedLinks.filter { it.shouldUseLink || it.link == currentLinkUsed } + filteredLinks = + sortedLinks.filter { it.shouldUseLink || it.link == currentLinkUsed } if (sortedLinks.isEmpty()) { sourceDialog.findViewById(R.id.sort_sources_holder)?.isGone = @@ -1589,7 +1587,8 @@ class GeneratorPlayer : FullScreenPlayer() { private fun noLinksFound() { viewModel.forceClearCache = true - val hiddenLinks = viewModel.state.sortLinks(currentQualityProfile).count { !it.shouldUseLink } + val hiddenLinks = + viewModel.state.sortLinks(currentQualityProfile).count { !it.shouldUseLink } context?.let { ctx -> // Display that there are hidden links to the user. @@ -2275,7 +2274,8 @@ class GeneratorPlayer : FullScreenPlayer() { // Set up TV clock visibility if (isLayout(TV)) { - val showTvClock = settingsManager.getBoolean(ctx.getString(R.string.tv_layout_clock_key), false) + val showTvClock = + settingsManager.getBoolean(ctx.getString(R.string.tv_layout_clock_key), false) playerBinding?.playerVideoClock?.isVisible = showTvClock } else { playerBinding?.playerVideoClock?.isVisible = false diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragmentScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragmentScreen.kt index 305b8ec28b5..a39ec6c7ad5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragmentScreen.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragmentScreen.kt @@ -1,7 +1,9 @@ package com.lagradost.cloudstream3.ui.settings import android.annotation.SuppressLint +import android.content.ActivityNotFoundException import android.os.Bundle +import androidx.activity.result.ActivityResultLauncher import androidx.compose.animation.Crossfade import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.clickable @@ -64,10 +66,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp +import androidx.core.app.ActivityOptionsCompat import coil3.compose.AsyncImage import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CommonActivity.activity +import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.DataStoreHelper import com.lagradost.cloudstream3.utils.DataStoreHelper.profileImages import com.lagradost.cloudstream3.utils.GitInfo.currentCommitHash @@ -95,6 +100,18 @@ import java.util.Locale import java.util.TimeZone object SettingsFragmentScreen : Screen { + fun ActivityResultLauncher.launchSafe(input : I, options: ActivityOptionsCompat? = null) { + try { + this.launch(input = input, options = options) + } catch (_ : ActivityNotFoundException) { + showToast(R.string.app_not_found_error) + } catch (t : Throwable) { + /** This should not ever happen, but again Java is wack */ + showToast(t.toString()) + logError(t) + } + } + val screens = persistentListOf( SettingsNavigation( title = R.string.category_general, diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt index 32f60752ea0..5ded9a960e9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt @@ -37,6 +37,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.hideOn import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.ui.settings.utils.getChooseFolderLauncher import com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.isAppRestricted import com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.showBatteryOptimizationDialog @@ -402,11 +403,7 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { {}) { // Last = custom if (it == dirs.size) { - try { - pathPicker.launch(Uri.EMPTY) - } catch (e: Exception) { - logError(e) - } + pathPicker.launchSafe(Uri.EMPTY) } else { // Sets both visual and actual paths. // key = used path diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneralScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneralScreen.kt index 6aa94fa883c..a298dfd1d2b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneralScreen.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneralScreen.kt @@ -27,6 +27,7 @@ import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.insecureApp import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.network.initClient +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.ui.settings.SettingsProvidersScreen.toStringRes import com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.isAppRestricted import com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.showRequestIgnoreBatteryOptDialog @@ -166,7 +167,7 @@ object SettingsGeneralScreen : SearchableSettings { // This is not a ListPreference because the old selection system is // broken af. This needs to be refactored to QuickNovels download path // system. - selectFileSelector.launch(Uri.EMPTY) + selectFileSelector.launchSafe(Uri.EMPTY) }, ), Preference.PreferenceItem.SliderPreference( diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt index c04215594e1..a73e70242d0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt @@ -28,6 +28,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.hideOn import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.ui.settings.utils.getChooseFolderLauncher import com.lagradost.cloudstream3.utils.BackupUtils import com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt @@ -126,11 +127,7 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { ) { // Last = custom if (it == dirs.size) { - try { - pathPicker.launch(Uri.EMPTY) - } catch (e: Exception) { - logError(e) - } + pathPicker.launchSafe(Uri.EMPTY) } else { // Sets both visual and actual paths. // path = used uri @@ -245,7 +242,7 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { return@setOnPreferenceClickListener true } } - + getPref(R.string.install_prerelease_key)?.let { pref -> pref.isVisible = BuildConfig.FLAVOR == "stable" pref.setOnPreferenceClickListener { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdatesScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdatesScreen.kt index cc867ae251f..1a2881ef4fc 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdatesScreen.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdatesScreen.kt @@ -20,6 +20,7 @@ import com.lagradost.cloudstream3.MainActivityScreen import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.services.BackupWorkManager +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.utils.BackupUtils import com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt import com.lagradost.cloudstream3.utils.InAppUpdater.installPreReleaseIfNeeded @@ -162,7 +163,7 @@ object SettingsUpdatesScreen : SearchableSettings { // This is not a ListPreference because the old selection system is // broken af. This needs to be refactored to QuickNovels download path // system. - selectFileSelector.launch(Uri.EMPTY) + selectFileSelector.launchSafe(Uri.EMPTY) } ), Preference.PreferenceItem.TextPreference( diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesScreen.kt index cba651c7631..f97290578b4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesScreen.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesScreen.kt @@ -37,6 +37,7 @@ import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.ui.player.CustomDecoder +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.applyStyle import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.applyStyleEvent import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.defaultSubtitleStyle @@ -254,7 +255,7 @@ object SubtitlesScreen : SearchableSettings { entries = mapOf(null to stringResource(R.string.normal)) + SubtitleFont.entries.associateWith { it.label }, onValueChanged = { value -> if (value?.resource == 0) { - subtitleFileSelector.launch( + subtitleFileSelector.launchSafe( arrayOf( "font/*", ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt index d0c79c43c89..df1c1d42570 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt @@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_CACHED_LIST import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_CACHED_LIST import com.lagradost.cloudstream3.syncproviders.providers.KitsuApi.Companion.KITSU_CACHED_LIST +import com.lagradost.cloudstream3.ui.settings.SettingsFragmentScreen.launchSafe import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.Coroutines.ioSafe @@ -94,12 +95,12 @@ object BackupUtils { // and make it possible to restore download folders using that metadata. DOWNLOAD_EPISODE_CACHE_BACKUP, DOWNLOAD_EPISODE_CACHE, - + // Download headers are unintuitively used in the resume watching system. // We can therefore not prune download headers in backups. // DOWNLOAD_HEADER_CACHE_BACKUP, // DOWNLOAD_HEADER_CACHE, - + // This may overwrite valid local data with invalid data KEY_DOWNLOAD_INFO, @@ -193,7 +194,7 @@ object BackupUtils { } // Make sure the library is fresh - for(api in AccountManager.syncApis) { + for (api in AccountManager.syncApis) { api.requireLibraryRefresh = true } } @@ -210,7 +211,9 @@ object BackupUtils { return@ioSafe } - val date = SimpleDateFormat("yyyy_MM_dd_HH_mm", Locale.getDefault()).format(Date(currentTimeMillis())) + val date = SimpleDateFormat("yyyy_MM_dd_HH_mm", Locale.getDefault()).format( + Date(currentTimeMillis()) + ) val displayName = "CS3_Backup_${date}" val backupFile = getBackup(context) val stream = setupBackupStream(context, displayName) @@ -236,7 +239,11 @@ object BackupUtils { } @Throws(IOException::class) - private fun setupBackupStream(context: Context, name: String, ext: String = "txt"): DownloadObjects.StreamData { + private fun setupBackupStream( + context: Context, + name: String, + ext: String = "txt" + ): DownloadObjects.StreamData { return setupStream( baseFile = getCurrentBackupDir(context).first ?: getDefaultBackupDir(context) ?: throw IOException("Bad config"), @@ -285,22 +292,17 @@ object BackupUtils { fun Activity.restorePrompt() { runOnUiThread { - try { - restoreFileSelector?.launch( - arrayOf( - "text/plain", - "text/str", - "text/x-unknown", - "application/json", - "unknown/unknown", - "content/unknown", - "application/octet-stream", - ) + restoreFileSelector?.launchSafe( + arrayOf( + "text/plain", + "text/str", + "text/x-unknown", + "application/json", + "unknown/unknown", + "content/unknown", + "application/octet-stream", ) - } catch (e: Exception) { - showToast(e.message) - logError(e) - } + ) } } @@ -331,7 +333,8 @@ object BackupUtils { */ fun getCurrentBackupDir(context: Context): Pair { val settingsManager = PreferenceManager.getDefaultSharedPreferences(context) - val basePathSetting = settingsManager.getString(context.getString(R.string.backup_path_key), null) + val basePathSetting = + settingsManager.getString(context.getString(R.string.backup_path_key), null) return baseBackupPathToFile(context, basePathSetting) to basePathSetting }