enhance(android): add logs for the navigation stack

This commit is contained in:
charlie
2026-05-18 12:56:27 +08:00
parent d44466b287
commit b91c12d3a2
4 changed files with 79 additions and 4 deletions

View File

@@ -39,6 +39,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
private const val ROOT_ROUTE = "web/{encodedPath}"
private const val DEBUG_NAV_STACK_PREFIX = "[DEBUG-navstack]"
data class NavigationEvent(
val navigationType: String,
@@ -55,6 +56,7 @@ object ComposeHost {
fun applyNavigation(navigationType: String?, path: String?) {
val type = (navigationType ?: "push").lowercase()
val safePath = path?.takeIf { it.isNotBlank() } ?: "/"
Log.d("NavStack", "$DEBUG_NAV_STACK_PREFIX compose.applyNavigation type=$type path=$safePath")
if (!navEvents.tryEmit(NavigationEvent(type, safePath))) {
Log.w("ComposeHost", "Dropped navigation event: type=$type path=$safePath")
}
@@ -99,8 +101,9 @@ private fun encodePath(path: String): String =
private fun routeFor(path: String): String =
"web/${encodePath(path)}"
@Suppress("UNUSED_PARAMETER")
private fun shouldAnimateNavigation(navigationType: String): Boolean =
navigationType == "push" || navigationType == "pop"
false
@OptIn(ExperimentalAnimationApi::class)
@Composable
@@ -273,13 +276,20 @@ private fun HandleNavigationEvents(
snapshotVersion += 1
val currentSnapshotVersion = snapshotVersion
val animateNavigation = shouldAnimateNavigation(event.navigationType)
val route = routeFor(event.path)
Log.d(
"NavStack",
"$DEBUG_NAV_STACK_PREFIX compose.event.before type=${event.navigationType} path=${event.path} targetRoute=$route " +
"currentRoute=${navController.currentBackStackEntry?.destination?.route} " +
"currentArgs=${navController.currentBackStackEntry?.arguments} " +
"previousRoute=${navController.previousBackStackEntry?.destination?.route}"
)
if (animateNavigation) {
WebViewSnapshotManager.showSnapshot("navigation", webView)
} else {
WebViewSnapshotManager.clearSnapshot("navigation")
}
onNavType(event.navigationType)
val route = routeFor(event.path)
when (event.navigationType) {
"push" -> navController.navigate(route)
@@ -291,7 +301,14 @@ private fun HandleNavigationEvents(
}
"pop" -> {
navController.popBackStack()
if (!navController.popBackStack(route, inclusive = false)) {
navController.navigate(route) {
popUpTo(ROOT_ROUTE) {
inclusive = true
}
launchSingleTop = true
}
}
}
"reset" -> {
@@ -306,6 +323,13 @@ private fun HandleNavigationEvents(
else -> navController.navigate(route)
}
Log.d(
"NavStack",
"$DEBUG_NAV_STACK_PREFIX compose.event.after type=${event.navigationType} path=${event.path} targetRoute=$route " +
"currentRoute=${navController.currentBackStackEntry?.destination?.route} " +
"currentArgs=${navController.currentBackStackEntry?.arguments} " +
"previousRoute=${navController.previousBackStackEntry?.destination?.route}"
)
if (animateNavigation) {
launch {

View File

@@ -19,6 +19,7 @@ import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends BridgeActivity {
private static final String NAV_STACK_DEBUG_PREFIX = "[DEBUG-navstack]";
private final NavigationCoordinator navigationCoordinator = new NavigationCoordinator();
private BroadcastReceiver routeChangeReceiver;
@@ -60,7 +61,19 @@ public class MainActivity extends BridgeActivity {
String stack = intent.getStringExtra("stack");
String navigationType = intent.getStringExtra("navigationType");
String path = intent.getStringExtra("path");
Log.d(
"NavStack",
NAV_STACK_DEBUG_PREFIX + " activity.routeChange.received stack=" + stack
+ " type=" + navigationType
+ " path=" + path
+ " before=" + navigationCoordinator.debugState()
);
navigationCoordinator.onRouteChange(stack, navigationType, path);
Log.d(
"NavStack",
NAV_STACK_DEBUG_PREFIX + " activity.routeChange.applied after="
+ navigationCoordinator.debugState()
);
}
};
IntentFilter filter = new IntentFilter(UILocal.ACTION_ROUTE_CHANGED);
@@ -133,6 +146,11 @@ public class MainActivity extends BridgeActivity {
private void handleNativeBack() {
Log.d("onBackPressed", "Debug");
Log.d(
"NavStack",
NAV_STACK_DEBUG_PREFIX + " activity.nativeBack source=system-or-edge before="
+ navigationCoordinator.debugState()
);
WebView webView = getBridge().getWebView();
if (webView != null) {
@@ -167,6 +185,7 @@ public class MainActivity extends BridgeActivity {
private void sendJsBack(WebView webView) {
if (webView == null) return;
Log.d("NavStack", NAV_STACK_DEBUG_PREFIX + " activity.sendJsBack dispatching onNativePop");
webView.post(() -> webView.evaluateJavascript(
"window.LogseqNative && window.LogseqNative.onNativePop && window.LogseqNative.onNativePop();",
null

View File

@@ -1,6 +1,13 @@
package com.logseq.app
import android.util.Log
class NavigationCoordinator {
companion object {
private const val TAG = "NavStack"
private const val DEBUG_PREFIX = "[DEBUG-navstack]"
}
private val primaryStack = "home"
private val stackPaths: MutableMap<String, MutableList<String>> = mutableMapOf(
primaryStack to mutableListOf("/")
@@ -14,11 +21,22 @@ class NavigationCoordinator {
private fun normalizedPath(raw: String?): String =
raw?.takeIf { it.isNotBlank() } ?: "/"
fun debugState(): String =
"active=$activeStackId stacks=" + stackPaths.entries.joinToString(
prefix = "{",
postfix = "}"
) { (stack, paths) -> "$stack=${paths.joinToString(prefix = "[", postfix = "]")}" }
fun onRouteChange(stack: String?, navigationType: String?, path: String?) {
val stackId = stack?.takeIf { it.isNotBlank() } ?: primaryStack
val navType = navigationType?.lowercase() ?: "push"
val resolvedPath = normalizedPath(path)
Log.d(
TAG,
"$DEBUG_PREFIX coordinator.onRouteChange.before stack=$stackId type=$navType path=$resolvedPath ${debugState()}"
)
val paths = stackPaths.getOrPut(stackId) { mutableListOf(defaultPath(stackId)) }
when (navType) {
@@ -58,6 +76,11 @@ class NavigationCoordinator {
activeStackId = stackId
stackPaths[stackId] = paths
Log.d(
TAG,
"$DEBUG_PREFIX coordinator.onRouteChange.after stack=$stackId type=$navType path=$resolvedPath ${debugState()} canPop=${canPop()}"
)
}
fun canPop(): Boolean {
@@ -69,6 +92,8 @@ class NavigationCoordinator {
val paths = stackPaths[activeStackId] ?: return null
if (paths.size <= 1) return null
paths.removeAt(paths.lastIndex)
return paths.lastOrNull()
return paths.lastOrNull().also { target ->
Log.d(TAG, "$DEBUG_PREFIX coordinator.pop target=$target ${debugState()} canPop=${canPop()}")
}
}
}

View File

@@ -2,6 +2,7 @@ package com.logseq.app
import android.app.DatePickerDialog
import android.content.Intent
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.DatePicker
@@ -21,6 +22,7 @@ class UILocal : Plugin() {
private var toast: Toast? = null
companion object {
const val ACTION_ROUTE_CHANGED = "com.logseq.app.ROUTE_DID_CHANGE"
private const val DEBUG_PREFIX = "[DEBUG-navstack]"
}
@PluginMethod
@@ -119,6 +121,11 @@ class UILocal : Plugin() {
val path = call.getString("path") ?: "/"
val stack = call.getString("stack") ?: "home"
Log.d(
"NavStack",
"$DEBUG_PREFIX uiLocal.routeDidChange stack=$stack type=$navigationType push=$push path=$path"
)
// Drive Compose Nav for native animations/back handling.
ComposeHost.applyNavigation(navigationType, path)