MainActivity: Avoid navigator-related crash when handling onNewIntent (#9104)

This commit is contained in:
Ivan Iskandar 2023-02-18 22:08:37 +07:00 committed by GitHub
parent ffa8c8fd07
commit d3dadf71e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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<Intent> {
val componentActivity = context as ComponentActivity
val consumer = Consumer<Intent> { 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()
) {