refactor(auth): scope phone verification loading state to the composition that owns it - #2454

Merged
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership
Aug 28, 2026
Merged

refactor(auth): scope phone verification loading state to the composition that owns it#2454
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership

Conversation

@demolaf

@demolafdemolaf commented Aug 25, 2026

Copy link
Copy Markdown
Member

FirebaseAuthUI carried a revision counter plus clearLoadingState and currentAuthStateRevision purely so verifyPhoneNumber could retract its own AuthState.Loading on cancellation without clobbering whatever superseded it.

verifyPhoneNumber now writes no state on cancellation and just rethrows, and PhoneAuthScreen retracts its own Loading instead — in onChangeNumberClick, and from a DisposableEffect when the composition goes away mid-verification. Cancelling an attempt was already the screen's own bookkeeping, so the state it leaves behind belongs to the screen too.

Dropped three tests covering the removed API and the old callee-retracts contract, and added one to PhoneAuthScreenVerificationLifecycleTest for the change-number case — verified it fails without the change.

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies state management in FirebaseAuthUI by removing the AtomicLong revision tracking and instead handling the retraction of the Loading state directly within the UI layer using Compose's lifecycle. Specifically, a DisposableEffect is introduced in PhoneAuthScreen to reset the authentication state to Idle upon disposal if it was left in a Loading state. The review feedback points out a potential bug where rememberUpdatedState(authState) combined with DisposableEffect(authUI) can cause a mismatched state capture when authUI changes, as well as a race condition with cancellation. A code suggestion is provided to track the state per authUI instance using remember(authUI) { mutableStateOf(authState) }.

Comment threadauth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt Outdated
@demolaf
demolaf marked this pull request as ready for review August 25, 2026 09:09
@demolaf
demolaf marked this pull request as draft August 25, 2026 14:10
@demolaf
demolaf changed the base branch from version-10.0.0-beta04 to version-10.0.0-beta05August 26, 2026 14:32
@demolaf
demolaf marked this pull request as ready for review August 26, 2026 14:33
@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 485c2d9 to 3edb410CompareAugust 26, 2026 16:30

@russellwheatleyrussellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The core simplification is sound, traced through all the cancellation call sites and the DisposableEffect(authUI) cleanup correctly fixes the per-instance state capture bug flagged in review.

One thing worth a follow-up look: submitVerificationCode and signInWithPhoneAuthCredential still write AuthState.Error on CancellationException, so the same stale-state-after-disposal issue this PR fixes for verifyPhoneNumber might still apply if the screen disposes mid-flight on those. Pre-existing and out of scope here, not blocking.

@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 3edb410 to 98d196cCompareAugust 28, 2026 14:29
@demolaf
demolaf merged commit 65149e2 into version-10.0.0-beta05Aug 28, 2026
9 checks passed
@demolaf
demolaf deleted the fix/phone-auth-loading-state-ownership branch August 28, 2026 14:36
@demolafdemolaf mentioned this pull request Aug 28, 2026
demolaf added a commit that referenced this pull request Sep 1, 2026
…tion that owns it (#2454)
* refactor(auth): let the phone screen own its verification loading state
* fix(auth): read auth state per authUI instance when clearing loading on dispose
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@demolaf@russellwheatley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

refactor(auth): scope phone verification loading state to the composition that owns it - #2454

Merged
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership
Aug 28, 2026
Merged

refactor(auth): scope phone verification loading state to the composition that owns it#2454
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership

Conversation

@demolaf

@demolafdemolaf commented Aug 25, 2026

Copy link
Copy Markdown
Member

FirebaseAuthUI carried a revision counter plus clearLoadingState and currentAuthStateRevision purely so verifyPhoneNumber could retract its own AuthState.Loading on cancellation without clobbering whatever superseded it.

verifyPhoneNumber now writes no state on cancellation and just rethrows, and PhoneAuthScreen retracts its own Loading instead — in onChangeNumberClick, and from a DisposableEffect when the composition goes away mid-verification. Cancelling an attempt was already the screen's own bookkeeping, so the state it leaves behind belongs to the screen too.

Dropped three tests covering the removed API and the old callee-retracts contract, and added one to PhoneAuthScreenVerificationLifecycleTest for the change-number case — verified it fails without the change.

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies state management in FirebaseAuthUI by removing the AtomicLong revision tracking and instead handling the retraction of the Loading state directly within the UI layer using Compose's lifecycle. Specifically, a DisposableEffect is introduced in PhoneAuthScreen to reset the authentication state to Idle upon disposal if it was left in a Loading state. The review feedback points out a potential bug where rememberUpdatedState(authState) combined with DisposableEffect(authUI) can cause a mismatched state capture when authUI changes, as well as a race condition with cancellation. A code suggestion is provided to track the state per authUI instance using remember(authUI) { mutableStateOf(authState) }.

Comment threadauth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt Outdated
@demolaf
demolaf marked this pull request as ready for review August 25, 2026 09:09
@demolaf
demolaf marked this pull request as draft August 25, 2026 14:10
@demolaf
demolaf changed the base branch from version-10.0.0-beta04 to version-10.0.0-beta05August 26, 2026 14:32
@demolaf
demolaf marked this pull request as ready for review August 26, 2026 14:33
@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 485c2d9 to 3edb410CompareAugust 26, 2026 16:30

@russellwheatleyrussellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The core simplification is sound, traced through all the cancellation call sites and the DisposableEffect(authUI) cleanup correctly fixes the per-instance state capture bug flagged in review.

One thing worth a follow-up look: submitVerificationCode and signInWithPhoneAuthCredential still write AuthState.Error on CancellationException, so the same stale-state-after-disposal issue this PR fixes for verifyPhoneNumber might still apply if the screen disposes mid-flight on those. Pre-existing and out of scope here, not blocking.

@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 3edb410 to 98d196cCompareAugust 28, 2026 14:29
@demolaf
demolaf merged commit 65149e2 into version-10.0.0-beta05Aug 28, 2026
9 checks passed
@demolaf
demolaf deleted the fix/phone-auth-loading-state-ownership branch August 28, 2026 14:36
@demolafdemolaf mentioned this pull request Aug 28, 2026
demolaf added a commit that referenced this pull request Sep 1, 2026
…tion that owns it (#2454)
* refactor(auth): let the phone screen own its verification loading state
* fix(auth): read auth state per authUI instance when clearing loading on dispose
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@demolaf@russellwheatley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(auth): scope phone verification loading state to the composition that owns it - #2454

Merged
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership
Aug 28, 2026
Merged

refactor(auth): scope phone verification loading state to the composition that owns it#2454
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership

Conversation

@demolaf

@demolafdemolaf commented Aug 25, 2026

Copy link
Copy Markdown
Member

FirebaseAuthUI carried a revision counter plus clearLoadingState and currentAuthStateRevision purely so verifyPhoneNumber could retract its own AuthState.Loading on cancellation without clobbering whatever superseded it.

verifyPhoneNumber now writes no state on cancellation and just rethrows, and PhoneAuthScreen retracts its own Loading instead — in onChangeNumberClick, and from a DisposableEffect when the composition goes away mid-verification. Cancelling an attempt was already the screen's own bookkeeping, so the state it leaves behind belongs to the screen too.

Dropped three tests covering the removed API and the old callee-retracts contract, and added one to PhoneAuthScreenVerificationLifecycleTest for the change-number case — verified it fails without the change.

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies state management in FirebaseAuthUI by removing the AtomicLong revision tracking and instead handling the retraction of the Loading state directly within the UI layer using Compose's lifecycle. Specifically, a DisposableEffect is introduced in PhoneAuthScreen to reset the authentication state to Idle upon disposal if it was left in a Loading state. The review feedback points out a potential bug where rememberUpdatedState(authState) combined with DisposableEffect(authUI) can cause a mismatched state capture when authUI changes, as well as a race condition with cancellation. A code suggestion is provided to track the state per authUI instance using remember(authUI) { mutableStateOf(authState) }.

Comment threadauth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt Outdated
@demolaf
demolaf marked this pull request as ready for review August 25, 2026 09:09
@demolaf
demolaf marked this pull request as draft August 25, 2026 14:10
@demolaf
demolaf changed the base branch from version-10.0.0-beta04 to version-10.0.0-beta05August 26, 2026 14:32
@demolaf
demolaf marked this pull request as ready for review August 26, 2026 14:33
@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 485c2d9 to 3edb410CompareAugust 26, 2026 16:30

@russellwheatleyrussellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The core simplification is sound, traced through all the cancellation call sites and the DisposableEffect(authUI) cleanup correctly fixes the per-instance state capture bug flagged in review.

One thing worth a follow-up look: submitVerificationCode and signInWithPhoneAuthCredential still write AuthState.Error on CancellationException, so the same stale-state-after-disposal issue this PR fixes for verifyPhoneNumber might still apply if the screen disposes mid-flight on those. Pre-existing and out of scope here, not blocking.

@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 3edb410 to 98d196cCompareAugust 28, 2026 14:29
@demolaf
demolaf merged commit 65149e2 into version-10.0.0-beta05Aug 28, 2026
9 checks passed
@demolaf
demolaf deleted the fix/phone-auth-loading-state-ownership branch August 28, 2026 14:36
@demolafdemolaf mentioned this pull request Aug 28, 2026
demolaf added a commit that referenced this pull request Sep 1, 2026
…tion that owns it (#2454)
* refactor(auth): let the phone screen own its verification loading state
* fix(auth): read auth state per authUI instance when clearing loading on dispose
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@demolaf@russellwheatley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(auth): scope phone verification loading state to the composition that owns it - #2454

Merged
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership
Aug 28, 2026
Merged

refactor(auth): scope phone verification loading state to the composition that owns it#2454
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership

Conversation

@demolaf

@demolafdemolaf commented Aug 25, 2026

Copy link
Copy Markdown
Member

FirebaseAuthUI carried a revision counter plus clearLoadingState and currentAuthStateRevision purely so verifyPhoneNumber could retract its own AuthState.Loading on cancellation without clobbering whatever superseded it.

verifyPhoneNumber now writes no state on cancellation and just rethrows, and PhoneAuthScreen retracts its own Loading instead — in onChangeNumberClick, and from a DisposableEffect when the composition goes away mid-verification. Cancelling an attempt was already the screen's own bookkeeping, so the state it leaves behind belongs to the screen too.

Dropped three tests covering the removed API and the old callee-retracts contract, and added one to PhoneAuthScreenVerificationLifecycleTest for the change-number case — verified it fails without the change.

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies state management in FirebaseAuthUI by removing the AtomicLong revision tracking and instead handling the retraction of the Loading state directly within the UI layer using Compose's lifecycle. Specifically, a DisposableEffect is introduced in PhoneAuthScreen to reset the authentication state to Idle upon disposal if it was left in a Loading state. The review feedback points out a potential bug where rememberUpdatedState(authState) combined with DisposableEffect(authUI) can cause a mismatched state capture when authUI changes, as well as a race condition with cancellation. A code suggestion is provided to track the state per authUI instance using remember(authUI) { mutableStateOf(authState) }.

Comment threadauth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt Outdated
@demolaf
demolaf marked this pull request as ready for review August 25, 2026 09:09
@demolaf
demolaf marked this pull request as draft August 25, 2026 14:10
@demolaf
demolaf changed the base branch from version-10.0.0-beta04 to version-10.0.0-beta05August 26, 2026 14:32
@demolaf
demolaf marked this pull request as ready for review August 26, 2026 14:33
@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 485c2d9 to 3edb410CompareAugust 26, 2026 16:30

@russellwheatleyrussellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The core simplification is sound, traced through all the cancellation call sites and the DisposableEffect(authUI) cleanup correctly fixes the per-instance state capture bug flagged in review.

One thing worth a follow-up look: submitVerificationCode and signInWithPhoneAuthCredential still write AuthState.Error on CancellationException, so the same stale-state-after-disposal issue this PR fixes for verifyPhoneNumber might still apply if the screen disposes mid-flight on those. Pre-existing and out of scope here, not blocking.

@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 3edb410 to 98d196cCompareAugust 28, 2026 14:29
@demolaf
demolaf merged commit 65149e2 into version-10.0.0-beta05Aug 28, 2026
9 checks passed
@demolaf
demolaf deleted the fix/phone-auth-loading-state-ownership branch August 28, 2026 14:36
@demolafdemolaf mentioned this pull request Aug 28, 2026
demolaf added a commit that referenced this pull request Sep 1, 2026
…tion that owns it (#2454)
* refactor(auth): let the phone screen own its verification loading state
* fix(auth): read auth state per authUI instance when clearing loading on dispose
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@demolaf@russellwheatley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

refactor(auth): scope phone verification loading state to the composition that owns it - #2454

Merged
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership
Aug 28, 2026
Merged

refactor(auth): scope phone verification loading state to the composition that owns it#2454
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership

Conversation

@demolaf

@demolafdemolaf commented Aug 25, 2026

Copy link
Copy Markdown
Member

FirebaseAuthUI carried a revision counter plus clearLoadingState and currentAuthStateRevision purely so verifyPhoneNumber could retract its own AuthState.Loading on cancellation without clobbering whatever superseded it.

verifyPhoneNumber now writes no state on cancellation and just rethrows, and PhoneAuthScreen retracts its own Loading instead — in onChangeNumberClick, and from a DisposableEffect when the composition goes away mid-verification. Cancelling an attempt was already the screen's own bookkeeping, so the state it leaves behind belongs to the screen too.

Dropped three tests covering the removed API and the old callee-retracts contract, and added one to PhoneAuthScreenVerificationLifecycleTest for the change-number case — verified it fails without the change.

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies state management in FirebaseAuthUI by removing the AtomicLong revision tracking and instead handling the retraction of the Loading state directly within the UI layer using Compose's lifecycle. Specifically, a DisposableEffect is introduced in PhoneAuthScreen to reset the authentication state to Idle upon disposal if it was left in a Loading state. The review feedback points out a potential bug where rememberUpdatedState(authState) combined with DisposableEffect(authUI) can cause a mismatched state capture when authUI changes, as well as a race condition with cancellation. A code suggestion is provided to track the state per authUI instance using remember(authUI) { mutableStateOf(authState) }.

Comment threadauth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt Outdated
@demolaf
demolaf marked this pull request as ready for review August 25, 2026 09:09
@demolaf
demolaf marked this pull request as draft August 25, 2026 14:10
@demolaf
demolaf changed the base branch from version-10.0.0-beta04 to version-10.0.0-beta05August 26, 2026 14:32
@demolaf
demolaf marked this pull request as ready for review August 26, 2026 14:33
@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 485c2d9 to 3edb410CompareAugust 26, 2026 16:30

@russellwheatleyrussellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The core simplification is sound, traced through all the cancellation call sites and the DisposableEffect(authUI) cleanup correctly fixes the per-instance state capture bug flagged in review.

One thing worth a follow-up look: submitVerificationCode and signInWithPhoneAuthCredential still write AuthState.Error on CancellationException, so the same stale-state-after-disposal issue this PR fixes for verifyPhoneNumber might still apply if the screen disposes mid-flight on those. Pre-existing and out of scope here, not blocking.

@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 3edb410 to 98d196cCompareAugust 28, 2026 14:29
@demolaf
demolaf merged commit 65149e2 into version-10.0.0-beta05Aug 28, 2026
9 checks passed
@demolaf
demolaf deleted the fix/phone-auth-loading-state-ownership branch August 28, 2026 14:36
@demolafdemolaf mentioned this pull request Aug 28, 2026
demolaf added a commit that referenced this pull request Sep 1, 2026
…tion that owns it (#2454)
* refactor(auth): let the phone screen own its verification loading state
* fix(auth): read auth state per authUI instance when clearing loading on dispose
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@demolaf@russellwheatley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(auth): scope phone verification loading state to the composition that owns it - #2454

Merged
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership
Aug 28, 2026
Merged

refactor(auth): scope phone verification loading state to the composition that owns it#2454
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership

Conversation

@demolaf

@demolafdemolaf commented Aug 25, 2026

Copy link
Copy Markdown
Member

FirebaseAuthUI carried a revision counter plus clearLoadingState and currentAuthStateRevision purely so verifyPhoneNumber could retract its own AuthState.Loading on cancellation without clobbering whatever superseded it.

verifyPhoneNumber now writes no state on cancellation and just rethrows, and PhoneAuthScreen retracts its own Loading instead — in onChangeNumberClick, and from a DisposableEffect when the composition goes away mid-verification. Cancelling an attempt was already the screen's own bookkeeping, so the state it leaves behind belongs to the screen too.

Dropped three tests covering the removed API and the old callee-retracts contract, and added one to PhoneAuthScreenVerificationLifecycleTest for the change-number case — verified it fails without the change.

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies state management in FirebaseAuthUI by removing the AtomicLong revision tracking and instead handling the retraction of the Loading state directly within the UI layer using Compose's lifecycle. Specifically, a DisposableEffect is introduced in PhoneAuthScreen to reset the authentication state to Idle upon disposal if it was left in a Loading state. The review feedback points out a potential bug where rememberUpdatedState(authState) combined with DisposableEffect(authUI) can cause a mismatched state capture when authUI changes, as well as a race condition with cancellation. A code suggestion is provided to track the state per authUI instance using remember(authUI) { mutableStateOf(authState) }.

Comment threadauth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt Outdated
@demolaf
demolaf marked this pull request as ready for review August 25, 2026 09:09
@demolaf
demolaf marked this pull request as draft August 25, 2026 14:10
@demolaf
demolaf changed the base branch from version-10.0.0-beta04 to version-10.0.0-beta05August 26, 2026 14:32
@demolaf
demolaf marked this pull request as ready for review August 26, 2026 14:33
@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 485c2d9 to 3edb410CompareAugust 26, 2026 16:30

@russellwheatleyrussellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The core simplification is sound, traced through all the cancellation call sites and the DisposableEffect(authUI) cleanup correctly fixes the per-instance state capture bug flagged in review.

One thing worth a follow-up look: submitVerificationCode and signInWithPhoneAuthCredential still write AuthState.Error on CancellationException, so the same stale-state-after-disposal issue this PR fixes for verifyPhoneNumber might still apply if the screen disposes mid-flight on those. Pre-existing and out of scope here, not blocking.

@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 3edb410 to 98d196cCompareAugust 28, 2026 14:29
@demolaf
demolaf merged commit 65149e2 into version-10.0.0-beta05Aug 28, 2026
9 checks passed
@demolaf
demolaf deleted the fix/phone-auth-loading-state-ownership branch August 28, 2026 14:36
@demolafdemolaf mentioned this pull request Aug 28, 2026
demolaf added a commit that referenced this pull request Sep 1, 2026
…tion that owns it (#2454)
* refactor(auth): let the phone screen own its verification loading state
* fix(auth): read auth state per authUI instance when clearing loading on dispose
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@demolaf@russellwheatley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(auth): scope phone verification loading state to the composition that owns it - #2454

Merged
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership
Aug 28, 2026
Merged

refactor(auth): scope phone verification loading state to the composition that owns it#2454
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership

Conversation

@demolaf

@demolafdemolaf commented Aug 25, 2026

Copy link
Copy Markdown
Member

FirebaseAuthUI carried a revision counter plus clearLoadingState and currentAuthStateRevision purely so verifyPhoneNumber could retract its own AuthState.Loading on cancellation without clobbering whatever superseded it.

verifyPhoneNumber now writes no state on cancellation and just rethrows, and PhoneAuthScreen retracts its own Loading instead — in onChangeNumberClick, and from a DisposableEffect when the composition goes away mid-verification. Cancelling an attempt was already the screen's own bookkeeping, so the state it leaves behind belongs to the screen too.

Dropped three tests covering the removed API and the old callee-retracts contract, and added one to PhoneAuthScreenVerificationLifecycleTest for the change-number case — verified it fails without the change.

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies state management in FirebaseAuthUI by removing the AtomicLong revision tracking and instead handling the retraction of the Loading state directly within the UI layer using Compose's lifecycle. Specifically, a DisposableEffect is introduced in PhoneAuthScreen to reset the authentication state to Idle upon disposal if it was left in a Loading state. The review feedback points out a potential bug where rememberUpdatedState(authState) combined with DisposableEffect(authUI) can cause a mismatched state capture when authUI changes, as well as a race condition with cancellation. A code suggestion is provided to track the state per authUI instance using remember(authUI) { mutableStateOf(authState) }.

Comment threadauth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt Outdated
@demolaf
demolaf marked this pull request as ready for review August 25, 2026 09:09
@demolaf
demolaf marked this pull request as draft August 25, 2026 14:10
@demolaf
demolaf changed the base branch from version-10.0.0-beta04 to version-10.0.0-beta05August 26, 2026 14:32
@demolaf
demolaf marked this pull request as ready for review August 26, 2026 14:33
@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 485c2d9 to 3edb410CompareAugust 26, 2026 16:30

@russellwheatleyrussellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The core simplification is sound, traced through all the cancellation call sites and the DisposableEffect(authUI) cleanup correctly fixes the per-instance state capture bug flagged in review.

One thing worth a follow-up look: submitVerificationCode and signInWithPhoneAuthCredential still write AuthState.Error on CancellationException, so the same stale-state-after-disposal issue this PR fixes for verifyPhoneNumber might still apply if the screen disposes mid-flight on those. Pre-existing and out of scope here, not blocking.

@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 3edb410 to 98d196cCompareAugust 28, 2026 14:29
@demolaf
demolaf merged commit 65149e2 into version-10.0.0-beta05Aug 28, 2026
9 checks passed
@demolaf
demolaf deleted the fix/phone-auth-loading-state-ownership branch August 28, 2026 14:36
@demolafdemolaf mentioned this pull request Aug 28, 2026
demolaf added a commit that referenced this pull request Sep 1, 2026
…tion that owns it (#2454)
* refactor(auth): let the phone screen own its verification loading state
* fix(auth): read auth state per authUI instance when clearing loading on dispose
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@demolaf@russellwheatley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

refactor(auth): scope phone verification loading state to the composition that owns it - #2454

Merged
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership
Aug 28, 2026
Merged

refactor(auth): scope phone verification loading state to the composition that owns it#2454
demolaf merged 2 commits into
version-10.0.0-beta05from
fix/phone-auth-loading-state-ownership

Conversation

@demolaf

@demolafdemolaf commented Aug 25, 2026

Copy link
Copy Markdown
Member

FirebaseAuthUI carried a revision counter plus clearLoadingState and currentAuthStateRevision purely so verifyPhoneNumber could retract its own AuthState.Loading on cancellation without clobbering whatever superseded it.

verifyPhoneNumber now writes no state on cancellation and just rethrows, and PhoneAuthScreen retracts its own Loading instead — in onChangeNumberClick, and from a DisposableEffect when the composition goes away mid-verification. Cancelling an attempt was already the screen's own bookkeeping, so the state it leaves behind belongs to the screen too.

Dropped three tests covering the removed API and the old callee-retracts contract, and added one to PhoneAuthScreenVerificationLifecycleTest for the change-number case — verified it fails without the change.

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies state management in FirebaseAuthUI by removing the AtomicLong revision tracking and instead handling the retraction of the Loading state directly within the UI layer using Compose's lifecycle. Specifically, a DisposableEffect is introduced in PhoneAuthScreen to reset the authentication state to Idle upon disposal if it was left in a Loading state. The review feedback points out a potential bug where rememberUpdatedState(authState) combined with DisposableEffect(authUI) can cause a mismatched state capture when authUI changes, as well as a race condition with cancellation. A code suggestion is provided to track the state per authUI instance using remember(authUI) { mutableStateOf(authState) }.

Comment threadauth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt Outdated
@demolaf
demolaf marked this pull request as ready for review August 25, 2026 09:09
@demolaf
demolaf marked this pull request as draft August 25, 2026 14:10
@demolaf
demolaf changed the base branch from version-10.0.0-beta04 to version-10.0.0-beta05August 26, 2026 14:32
@demolaf
demolaf marked this pull request as ready for review August 26, 2026 14:33
@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 485c2d9 to 3edb410CompareAugust 26, 2026 16:30

@russellwheatleyrussellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The core simplification is sound, traced through all the cancellation call sites and the DisposableEffect(authUI) cleanup correctly fixes the per-instance state capture bug flagged in review.

One thing worth a follow-up look: submitVerificationCode and signInWithPhoneAuthCredential still write AuthState.Error on CancellationException, so the same stale-state-after-disposal issue this PR fixes for verifyPhoneNumber might still apply if the screen disposes mid-flight on those. Pre-existing and out of scope here, not blocking.

@demolaf
demolafforce-pushed the fix/phone-auth-loading-state-ownership branch from 3edb410 to 98d196cCompareAugust 28, 2026 14:29
@demolaf
demolaf merged commit 65149e2 into version-10.0.0-beta05Aug 28, 2026
9 checks passed
@demolaf
demolaf deleted the fix/phone-auth-loading-state-ownership branch August 28, 2026 14:36
@demolafdemolaf mentioned this pull request Aug 28, 2026
demolaf added a commit that referenced this pull request Sep 1, 2026
…tion that owns it (#2454)
* refactor(auth): let the phone screen own its verification loading state
* fix(auth): read auth state per authUI instance when clearing loading on dispose
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@demolaf@russellwheatley