🤖 Fix: improve scheme url (Resolves #107)#108
Conversation
🤖 Codex-Style Code Review by OpenCode
Here is my expert PR review of the proposed changes. Review:
|
| Severity | Count | Key issues |
|---|---|---|
| 🔴 Blocking | 2 | Missing onUnmounted cleanup; fragile forward-reference ordering |
| 🟡 Important | 4 | No double-click guard; fragile locale string; visibilitychange false positives; HTTP install URLs |
| 🟢 Nit | 0 | — |
| 💡 Suggestion | 2 | Extract to composable; guard against double cleanUp |
| 🎉 Praise | 2 | Proper removeEventListener; good PR description |
Decision: 🔄 Request Changes — the memory leak from missing onUnmounted cleanup and the fragile forward-reference pattern must be fixed. The remaining issues are at the reviewer's discretion.
🤖 Codex-Style Code Review by OpenCode
Here is the expert code review for the diff in SummaryAdds a deep-link-with-fallback pattern to PR Size: Small (~55 lines) Required Changes🔴 [blocking] Event listener leak when component unmounts during the fallback window
Fix: Have onUnmounted(() => {
cleanUp()
})But onUnmounted(() => {
if (fallbackTimer !== null) {
clearTimeout(fallbackTimer)
fallbackTimer = null
}
// Also remove listeners if goToExperiment was called
document.removeEventListener('visibilitychange', onVisibility)
window.removeEventListener('blur', onBlur)
})This requires hoisting 🔴 [blocking] Module-level mutable state ( Lines 330–331 declare these outside Fix: Move state into the component scope: const fallbackTimer = ref<ReturnType<typeof setTimeout> | null>(null)
const cleanedUp = ref(false)Adjust references to use Important Suggestions🟡 [important]
Consider: Only treat 🟡 [important] Locale comparison is fragile Line 346: const installUrl = (locale.value.startsWith('zh') || locale.value === 'Chinese')
Suggestion: Extract a 🟡 [important] The module-level Minor Suggestions🟢 [nit] Magic number Replace the hard-coded const FALLBACK_TIMEOUT_MS = 800And add a brief comment explaining the rationale — long enough that a quick app launch via custom scheme wins the race, short enough that the user doesn't notice a delay before the fallback redirect. 🟢 [nit] Ambiguous variable name The name reads like past tense ("has been cleaned up") but is used as a guard for re-entrance. Consider 🟢 [nit] The guard on line 341 prevents calling Verdict🔄 Request Changes — the two blocking issues (event listener leak and module-level shared state) must be addressed before merge. The pattern itself is sound and the intent is clear; the mechanics of cleanup and state isolation need hardening. |
AI: Resolves #107
This Pull Request was automatically generated by OpenCode to address Issue #107.
📝 AI Modification Summary & Conclusion:
Implementation Summary
Problem
In the experiment summary page (
ExperimentSummary.vue), when a user clicks the "Enter Experience" button, the app tries to open aphysics://custom scheme URL to launch the native Physics Lab client. However, if the user has not installed the Physics Lab app, the scheme URL fails silently with no guidance, leaving the user confused about what to do next.Solution
Implemented a smart fallback mechanism in the
goToExperiment()function that:physics://chinese/{type}/{id}scheme URL as before.visibilitychangeandblurevents on the window — these events fire when the native app takes focus away from the browser.http://pl.turtlesim.com/app/cn(for Chinese locale users) orhttp://pl.turtlesim.com/app(for other users).Technical Details
visibilitychangeevent fires withdocument.hidden === truewhen the browser tab loses visibility (app opens). Theblurevent onwindowalso fires when the window loses focus. Either event triggers acleanUp()that setsappOpened = trueand clears the fallback timer.localeref to determine the user's language. Chinese users get the/app/cnURL, all others get/app.removeEventListenerfor both events to prevent memory leaks.Files Modified
src/views/ExperimentSummary.vue:193localeto theuseI18n()destructuring to access the current languagesrc/views/ExperimentSummary.vue:336-371goToExperiment()to add the app-detection fallback logic withvisibilitychange/blurevent listeners, 800ms timeout, and locale-aware install URL redirect