From d3dadf71e8d7d029fdb87b44217e001f95f21c1a Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Sat, 18 Feb 2023 22:08:37 +0700 Subject: [PATCH] MainActivity: Avoid navigator-related crash when handling onNewIntent (#9104) --- .../kanade/tachiyomi/ui/main/MainActivity.kt | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index a361d7aee5..6b8497fc03 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -3,12 +3,14 @@ package eu.kanade.tachiyomi.ui.main import android.animation.ValueAnimator import android.app.SearchManager import android.app.assist.AssistContent +import android.content.Context import android.content.Intent import android.graphics.Color import android.os.Build import android.os.Bundle import android.view.View import android.widget.Toast +import androidx.activity.ComponentActivity import androidx.activity.compose.BackHandler import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box @@ -41,6 +43,7 @@ import androidx.core.animation.doOnEnd import androidx.core.net.toUri import androidx.core.splashscreen.SplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.core.util.Consumer import androidx.core.view.WindowCompat import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.LinearOutSlowInInterpolator @@ -86,7 +89,10 @@ import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.setComposeContent import kotlinx.coroutines.cancel +import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn @@ -120,8 +126,7 @@ class MainActivity : BaseActivity() { */ private var settingsSheet: LibrarySettingsSheet? = null - private var isHandlingShortcut: Boolean = false - private lateinit var navigator: Navigator + private var navigator: Navigator? = null override fun onCreate(savedInstanceState: Bundle?) { // Prevent splash screen showing up on configuration changes @@ -211,7 +216,7 @@ class MainActivity : BaseActivity() { if (savedInstanceState == null) { // Set start screen - handleIntentAction(intent) + handleIntentAction(intent, navigator) // Reset Incognito Mode on relaunch preferences.incognitoMode().set(false) @@ -257,6 +262,8 @@ class MainActivity : BaseActivity() { .launchIn(this) } + HandleOnNewIntent(context = context, navigator = navigator) + CheckForUpdates() } @@ -289,7 +296,7 @@ class MainActivity : BaseActivity() { override fun onProvideAssistContent(outContent: AssistContent) { super.onProvideAssistContent(outContent) - when (val screen = navigator.lastItem) { + when (val screen = navigator?.lastItem) { is AssistContentScreen -> { screen.onProvideAssistUrl()?.let { outContent.webUri = it.toUri() } } @@ -320,6 +327,18 @@ class MainActivity : BaseActivity() { } } + @Composable + fun HandleOnNewIntent(context: Context, navigator: Navigator) { + LaunchedEffect(Unit) { + callbackFlow { + val componentActivity = context as ComponentActivity + val consumer = Consumer { trySend(it) } + componentActivity.addOnNewIntentListener(consumer) + awaitClose { componentActivity.removeOnNewIntentListener(consumer) } + }.collectLatest { handleIntentAction(it, navigator) } + } + } + @Composable private fun CheckForUpdates() { val context = LocalContext.current @@ -398,37 +417,26 @@ class MainActivity : BaseActivity() { } } - override fun onNewIntent(intent: Intent) { - lifecycleScope.launch { - val handle = handleIntentAction(intent) - if (!handle) { - super.onNewIntent(intent) - } - } - } - - private suspend fun handleIntentAction(intent: Intent): Boolean { + private fun handleIntentAction(intent: Intent, navigator: Navigator): Boolean { val notificationId = intent.getIntExtra("notificationId", -1) if (notificationId > -1) { NotificationReceiver.dismissNotification(applicationContext, notificationId, intent.getIntExtra("groupId", 0)) } - isHandlingShortcut = true - - when (intent.action) { - Constants.SHORTCUT_LIBRARY -> HomeScreen.openTab(HomeScreen.Tab.Library()) + val tabToOpen = when (intent.action) { + Constants.SHORTCUT_LIBRARY -> HomeScreen.Tab.Library() Constants.SHORTCUT_MANGA -> { val idToOpen = intent.extras?.getLong(Constants.MANGA_EXTRA) ?: return false navigator.popUntilRoot() - HomeScreen.openTab(HomeScreen.Tab.Library(idToOpen)) + HomeScreen.Tab.Library(idToOpen) } - Constants.SHORTCUT_UPDATES -> HomeScreen.openTab(HomeScreen.Tab.Updates) - Constants.SHORTCUT_HISTORY -> HomeScreen.openTab(HomeScreen.Tab.History) - Constants.SHORTCUT_SOURCES -> HomeScreen.openTab(HomeScreen.Tab.Browse(false)) - Constants.SHORTCUT_EXTENSIONS -> HomeScreen.openTab(HomeScreen.Tab.Browse(true)) + Constants.SHORTCUT_UPDATES -> HomeScreen.Tab.Updates + Constants.SHORTCUT_HISTORY -> HomeScreen.Tab.History + Constants.SHORTCUT_SOURCES -> HomeScreen.Tab.Browse(false) + Constants.SHORTCUT_EXTENSIONS -> HomeScreen.Tab.Browse(true) Constants.SHORTCUT_DOWNLOADS -> { navigator.popUntilRoot() - HomeScreen.openTab(HomeScreen.Tab.More(toDownloads = true)) + HomeScreen.Tab.More(toDownloads = true) } Intent.ACTION_SEARCH, Intent.ACTION_SEND, "com.google.android.gms.actions.SEARCH_ACTION" -> { // If the intent match the "standard" Android search intent @@ -440,6 +448,7 @@ class MainActivity : BaseActivity() { navigator.popUntilRoot() navigator.push(GlobalSearchScreen(query)) } + null } INTENT_SEARCH -> { val query = intent.getStringExtra(INTENT_SEARCH_QUERY) @@ -448,15 +457,16 @@ class MainActivity : BaseActivity() { navigator.popUntilRoot() navigator.push(GlobalSearchScreen(query, filter)) } + null } - else -> { - isHandlingShortcut = false - return false - } + else -> return false + } + + if (tabToOpen != null) { + lifecycleScope.launch { HomeScreen.openTab(tabToOpen) } } ready = true - isHandlingShortcut = false return true } @@ -467,7 +477,7 @@ class MainActivity : BaseActivity() { } override fun onBackPressed() { - if (navigator.size == 1 && + if (navigator?.size == 1 && !onBackPressedDispatcher.hasEnabledCallbacks() && libraryPreferences.autoClearChapterCache().get() ) {