Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 64 additions & 16 deletions auth/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1585,13 +1585,16 @@ If left unset (`null`), the top app bar falls back to colors derived from `color

### Screen Transitions

Customize the animations when navigating between screens using the `AuthUITransitions` object:
Customize the animations when navigating between screens using the `AuthUITransitions` object.
Each spec is an `AnimatedContentTransitionScope<Scene<NavKey>>` receiver returning one
`ContentTransform`, so the enter and exit halves are paired with `togetherWith`:

**Slide animations:**

```kotlin
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
Expand All@@ -1600,10 +1603,14 @@ val configuration = authUIConfiguration {
provider(AuthProvider.Google())
}
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } }, // Slide in from right
exitTransition = { slideOutHorizontally { -it } }, // Slide out to left
popEnterTransition = { slideInHorizontally { -it } }, // Slide in from left
popExitTransition = { slideOutHorizontally { it } } // Slide out to right
// Slide in from right, slide out to left
transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
// Slide in from left, slide out to right
popTransitionSpec = { slideInHorizontally { -it } togetherWith slideOutHorizontally { it } },
// Predictive back falls back to the default cross-fade if left unset, so mirror the pop
predictivePopTransitionSpec = {
slideInHorizontally { -it } togetherWith slideOutHorizontally { it }
}
)
}
```
Expand All@@ -1613,17 +1620,17 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Phone())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() },
exitTransition = { fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { fadeOut() }
transitionSpec = { fadeIn() togetherWith fadeOut() },
popTransitionSpec = { fadeIn() togetherWith fadeOut() },
predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }
)
}
```
Expand All@@ -1635,17 +1642,22 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Facebook())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
exitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) },
popEnterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
popExitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) }
transitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
},
popTransitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
}
)
}
```
Expand All@@ -1655,20 +1667,56 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
// A vertical push: the new step rises from the bottom as the old one leaves via the top
transitionSpec = { slideInVertically { it } togetherWith slideOutVertically { -it } }
Comment thread
demolaf marked this conversation as resolved.
)
}
```

**Per-destination animations:**

Read `authRoute()` off `initialState` / `targetState` to vary the animation by the screen being
navigated to or from:

```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions
import com.firebase.ui.auth.ui.screens.AuthRoute
import com.firebase.ui.auth.ui.screens.authRoute

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
enterTransition = { slideInVertically { it } }, // Slide up
exitTransition = { slideOutVertically { -it } } // Slide down
transitionSpec = {
if (targetState.authRoute() is AuthRoute.Success) {
fadeIn() togetherWith fadeOut()
} else {
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
}
)
}
```

> **Note:** If not specified, default fade in/out transitions with 700ms duration are used.
> **Note:** Each spec is independent. Any one left unset falls back to the library's default
> 700ms cross-fade — `predictivePopTransitionSpec` included, which does *not* fall back to
> `popTransitionSpec`. `predictivePopTransitionSpec` also receives the swipe edge
> (`NavigationEvent.EDGE_LEFT`, `EDGE_RIGHT` or `EDGE_NONE`) and runs when the gesture *starts*,
> so a side effect placed in it fires even for gestures the user goes on to cancel.

## Advanced Features

Expand Down
, '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
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 64 additions & 16 deletions auth/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1585,13 +1585,16 @@ If left unset (`null`), the top app bar falls back to colors derived from `color

### Screen Transitions

Customize the animations when navigating between screens using the `AuthUITransitions` object:
Customize the animations when navigating between screens using the `AuthUITransitions` object.
Each spec is an `AnimatedContentTransitionScope<Scene<NavKey>>` receiver returning one
`ContentTransform`, so the enter and exit halves are paired with `togetherWith`:

**Slide animations:**

```kotlin
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
Expand All@@ -1600,10 +1603,14 @@ val configuration = authUIConfiguration {
provider(AuthProvider.Google())
}
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } }, // Slide in from right
exitTransition = { slideOutHorizontally { -it } }, // Slide out to left
popEnterTransition = { slideInHorizontally { -it } }, // Slide in from left
popExitTransition = { slideOutHorizontally { it } } // Slide out to right
// Slide in from right, slide out to left
transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
// Slide in from left, slide out to right
popTransitionSpec = { slideInHorizontally { -it } togetherWith slideOutHorizontally { it } },
// Predictive back falls back to the default cross-fade if left unset, so mirror the pop
predictivePopTransitionSpec = {
slideInHorizontally { -it } togetherWith slideOutHorizontally { it }
}
)
}
```
Expand All@@ -1613,17 +1620,17 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Phone())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() },
exitTransition = { fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { fadeOut() }
transitionSpec = { fadeIn() togetherWith fadeOut() },
popTransitionSpec = { fadeIn() togetherWith fadeOut() },
predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }
)
}
```
Expand All@@ -1635,17 +1642,22 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Facebook())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
exitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) },
popEnterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
popExitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) }
transitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
},
popTransitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
}
)
}
```
Expand All@@ -1655,20 +1667,56 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
// A vertical push: the new step rises from the bottom as the old one leaves via the top
transitionSpec = { slideInVertically { it } togetherWith slideOutVertically { -it } }
Comment thread
demolaf marked this conversation as resolved.
)
}
```

**Per-destination animations:**

Read `authRoute()` off `initialState` / `targetState` to vary the animation by the screen being
navigated to or from:

```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions
import com.firebase.ui.auth.ui.screens.AuthRoute
import com.firebase.ui.auth.ui.screens.authRoute

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
enterTransition = { slideInVertically { it } }, // Slide up
exitTransition = { slideOutVertically { -it } } // Slide down
transitionSpec = {
if (targetState.authRoute() is AuthRoute.Success) {
fadeIn() togetherWith fadeOut()
} else {
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
}
)
}
```

> **Note:** If not specified, default fade in/out transitions with 700ms duration are used.
> **Note:** Each spec is independent. Any one left unset falls back to the library's default
> 700ms cross-fade — `predictivePopTransitionSpec` included, which does *not* fall back to
> `popTransitionSpec`. `predictivePopTransitionSpec` also receives the swipe edge
> (`NavigationEvent.EDGE_LEFT`, `EDGE_RIGHT` or `EDGE_NONE`) and runs when the gesture *starts*,
> so a side effect placed in it fires even for gestures the user goes on to cancel.

## Advanced Features

Expand Down
, '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
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 64 additions & 16 deletions auth/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1585,13 +1585,16 @@ If left unset (`null`), the top app bar falls back to colors derived from `color

### Screen Transitions

Customize the animations when navigating between screens using the `AuthUITransitions` object:
Customize the animations when navigating between screens using the `AuthUITransitions` object.
Each spec is an `AnimatedContentTransitionScope<Scene<NavKey>>` receiver returning one
`ContentTransform`, so the enter and exit halves are paired with `togetherWith`:

**Slide animations:**

```kotlin
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
Expand All@@ -1600,10 +1603,14 @@ val configuration = authUIConfiguration {
provider(AuthProvider.Google())
}
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } }, // Slide in from right
exitTransition = { slideOutHorizontally { -it } }, // Slide out to left
popEnterTransition = { slideInHorizontally { -it } }, // Slide in from left
popExitTransition = { slideOutHorizontally { it } } // Slide out to right
// Slide in from right, slide out to left
transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
// Slide in from left, slide out to right
popTransitionSpec = { slideInHorizontally { -it } togetherWith slideOutHorizontally { it } },
// Predictive back falls back to the default cross-fade if left unset, so mirror the pop
predictivePopTransitionSpec = {
slideInHorizontally { -it } togetherWith slideOutHorizontally { it }
}
)
}
```
Expand All@@ -1613,17 +1620,17 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Phone())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() },
exitTransition = { fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { fadeOut() }
transitionSpec = { fadeIn() togetherWith fadeOut() },
popTransitionSpec = { fadeIn() togetherWith fadeOut() },
predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }
)
}
```
Expand All@@ -1635,17 +1642,22 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Facebook())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
exitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) },
popEnterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
popExitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) }
transitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
},
popTransitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
}
)
}
```
Expand All@@ -1655,20 +1667,56 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
// A vertical push: the new step rises from the bottom as the old one leaves via the top
transitionSpec = { slideInVertically { it } togetherWith slideOutVertically { -it } }
Comment thread
demolaf marked this conversation as resolved.
)
}
```

**Per-destination animations:**

Read `authRoute()` off `initialState` / `targetState` to vary the animation by the screen being
navigated to or from:

```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions
import com.firebase.ui.auth.ui.screens.AuthRoute
import com.firebase.ui.auth.ui.screens.authRoute

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
enterTransition = { slideInVertically { it } }, // Slide up
exitTransition = { slideOutVertically { -it } } // Slide down
transitionSpec = {
if (targetState.authRoute() is AuthRoute.Success) {
fadeIn() togetherWith fadeOut()
} else {
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
}
)
}
```

> **Note:** If not specified, default fade in/out transitions with 700ms duration are used.
> **Note:** Each spec is independent. Any one left unset falls back to the library's default
> 700ms cross-fade — `predictivePopTransitionSpec` included, which does *not* fall back to
> `popTransitionSpec`. `predictivePopTransitionSpec` also receives the swipe edge
> (`NavigationEvent.EDGE_LEFT`, `EDGE_RIGHT` or `EDGE_NONE`) and runs when the gesture *starts*,
> so a side effect placed in it fires even for gestures the user goes on to cancel.

## Advanced Features

Expand Down
, '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
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 64 additions & 16 deletions auth/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1585,13 +1585,16 @@ If left unset (`null`), the top app bar falls back to colors derived from `color

### Screen Transitions

Customize the animations when navigating between screens using the `AuthUITransitions` object:
Customize the animations when navigating between screens using the `AuthUITransitions` object.
Each spec is an `AnimatedContentTransitionScope<Scene<NavKey>>` receiver returning one
`ContentTransform`, so the enter and exit halves are paired with `togetherWith`:

**Slide animations:**

```kotlin
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
Expand All@@ -1600,10 +1603,14 @@ val configuration = authUIConfiguration {
provider(AuthProvider.Google())
}
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } }, // Slide in from right
exitTransition = { slideOutHorizontally { -it } }, // Slide out to left
popEnterTransition = { slideInHorizontally { -it } }, // Slide in from left
popExitTransition = { slideOutHorizontally { it } } // Slide out to right
// Slide in from right, slide out to left
transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
// Slide in from left, slide out to right
popTransitionSpec = { slideInHorizontally { -it } togetherWith slideOutHorizontally { it } },
// Predictive back falls back to the default cross-fade if left unset, so mirror the pop
predictivePopTransitionSpec = {
slideInHorizontally { -it } togetherWith slideOutHorizontally { it }
}
)
}
```
Expand All@@ -1613,17 +1620,17 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Phone())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() },
exitTransition = { fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { fadeOut() }
transitionSpec = { fadeIn() togetherWith fadeOut() },
popTransitionSpec = { fadeIn() togetherWith fadeOut() },
predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }
)
}
```
Expand All@@ -1635,17 +1642,22 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Facebook())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
exitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) },
popEnterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
popExitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) }
transitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
},
popTransitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
}
)
}
```
Expand All@@ -1655,20 +1667,56 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
// A vertical push: the new step rises from the bottom as the old one leaves via the top
transitionSpec = { slideInVertically { it } togetherWith slideOutVertically { -it } }
Comment thread
demolaf marked this conversation as resolved.
)
}
```

**Per-destination animations:**

Read `authRoute()` off `initialState` / `targetState` to vary the animation by the screen being
navigated to or from:

```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions
import com.firebase.ui.auth.ui.screens.AuthRoute
import com.firebase.ui.auth.ui.screens.authRoute

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
enterTransition = { slideInVertically { it } }, // Slide up
exitTransition = { slideOutVertically { -it } } // Slide down
transitionSpec = {
if (targetState.authRoute() is AuthRoute.Success) {
fadeIn() togetherWith fadeOut()
} else {
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
}
)
}
```

> **Note:** If not specified, default fade in/out transitions with 700ms duration are used.
> **Note:** Each spec is independent. Any one left unset falls back to the library's default
> 700ms cross-fade — `predictivePopTransitionSpec` included, which does *not* fall back to
> `popTransitionSpec`. `predictivePopTransitionSpec` also receives the swipe edge
> (`NavigationEvent.EDGE_LEFT`, `EDGE_RIGHT` or `EDGE_NONE`) and runs when the gesture *starts*,
> so a side effect placed in it fires even for gestures the user goes on to cancel.

## Advanced Features

Expand Down
, '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
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 64 additions & 16 deletions auth/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1585,13 +1585,16 @@ If left unset (`null`), the top app bar falls back to colors derived from `color

### Screen Transitions

Customize the animations when navigating between screens using the `AuthUITransitions` object:
Customize the animations when navigating between screens using the `AuthUITransitions` object.
Each spec is an `AnimatedContentTransitionScope<Scene<NavKey>>` receiver returning one
`ContentTransform`, so the enter and exit halves are paired with `togetherWith`:

**Slide animations:**

```kotlin
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
Expand All@@ -1600,10 +1603,14 @@ val configuration = authUIConfiguration {
provider(AuthProvider.Google())
}
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } }, // Slide in from right
exitTransition = { slideOutHorizontally { -it } }, // Slide out to left
popEnterTransition = { slideInHorizontally { -it } }, // Slide in from left
popExitTransition = { slideOutHorizontally { it } } // Slide out to right
// Slide in from right, slide out to left
transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
// Slide in from left, slide out to right
popTransitionSpec = { slideInHorizontally { -it } togetherWith slideOutHorizontally { it } },
// Predictive back falls back to the default cross-fade if left unset, so mirror the pop
predictivePopTransitionSpec = {
slideInHorizontally { -it } togetherWith slideOutHorizontally { it }
}
)
}
```
Expand All@@ -1613,17 +1620,17 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Phone())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() },
exitTransition = { fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { fadeOut() }
transitionSpec = { fadeIn() togetherWith fadeOut() },
popTransitionSpec = { fadeIn() togetherWith fadeOut() },
predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }
)
}
```
Expand All@@ -1635,17 +1642,22 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Facebook())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
exitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) },
popEnterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
popExitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) }
transitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
},
popTransitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
}
)
}
```
Expand All@@ -1655,20 +1667,56 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
// A vertical push: the new step rises from the bottom as the old one leaves via the top
transitionSpec = { slideInVertically { it } togetherWith slideOutVertically { -it } }
Comment thread
demolaf marked this conversation as resolved.
)
}
```

**Per-destination animations:**

Read `authRoute()` off `initialState` / `targetState` to vary the animation by the screen being
navigated to or from:

```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions
import com.firebase.ui.auth.ui.screens.AuthRoute
import com.firebase.ui.auth.ui.screens.authRoute

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
enterTransition = { slideInVertically { it } }, // Slide up
exitTransition = { slideOutVertically { -it } } // Slide down
transitionSpec = {
if (targetState.authRoute() is AuthRoute.Success) {
fadeIn() togetherWith fadeOut()
} else {
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
}
)
}
```

> **Note:** If not specified, default fade in/out transitions with 700ms duration are used.
> **Note:** Each spec is independent. Any one left unset falls back to the library's default
> 700ms cross-fade — `predictivePopTransitionSpec` included, which does *not* fall back to
> `popTransitionSpec`. `predictivePopTransitionSpec` also receives the swipe edge
> (`NavigationEvent.EDGE_LEFT`, `EDGE_RIGHT` or `EDGE_NONE`) and runs when the gesture *starts*,
> so a side effect placed in it fires even for gestures the user goes on to cancel.

## Advanced Features

Expand Down
, '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
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 64 additions & 16 deletions auth/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1585,13 +1585,16 @@ If left unset (`null`), the top app bar falls back to colors derived from `color

### Screen Transitions

Customize the animations when navigating between screens using the `AuthUITransitions` object:
Customize the animations when navigating between screens using the `AuthUITransitions` object.
Each spec is an `AnimatedContentTransitionScope<Scene<NavKey>>` receiver returning one
`ContentTransform`, so the enter and exit halves are paired with `togetherWith`:

**Slide animations:**

```kotlin
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
Expand All@@ -1600,10 +1603,14 @@ val configuration = authUIConfiguration {
provider(AuthProvider.Google())
}
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } }, // Slide in from right
exitTransition = { slideOutHorizontally { -it } }, // Slide out to left
popEnterTransition = { slideInHorizontally { -it } }, // Slide in from left
popExitTransition = { slideOutHorizontally { it } } // Slide out to right
// Slide in from right, slide out to left
transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
// Slide in from left, slide out to right
popTransitionSpec = { slideInHorizontally { -it } togetherWith slideOutHorizontally { it } },
// Predictive back falls back to the default cross-fade if left unset, so mirror the pop
predictivePopTransitionSpec = {
slideInHorizontally { -it } togetherWith slideOutHorizontally { it }
}
)
}
```
Expand All@@ -1613,17 +1620,17 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Phone())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() },
exitTransition = { fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { fadeOut() }
transitionSpec = { fadeIn() togetherWith fadeOut() },
popTransitionSpec = { fadeIn() togetherWith fadeOut() },
predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }
)
}
```
Expand All@@ -1635,17 +1642,22 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Facebook())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
exitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) },
popEnterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
popExitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) }
transitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
},
popTransitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
}
)
}
```
Expand All@@ -1655,20 +1667,56 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
// A vertical push: the new step rises from the bottom as the old one leaves via the top
transitionSpec = { slideInVertically { it } togetherWith slideOutVertically { -it } }
Comment thread
demolaf marked this conversation as resolved.
)
}
```

**Per-destination animations:**

Read `authRoute()` off `initialState` / `targetState` to vary the animation by the screen being
navigated to or from:

```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions
import com.firebase.ui.auth.ui.screens.AuthRoute
import com.firebase.ui.auth.ui.screens.authRoute

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
enterTransition = { slideInVertically { it } }, // Slide up
exitTransition = { slideOutVertically { -it } } // Slide down
transitionSpec = {
if (targetState.authRoute() is AuthRoute.Success) {
fadeIn() togetherWith fadeOut()
} else {
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
}
)
}
```

> **Note:** If not specified, default fade in/out transitions with 700ms duration are used.
> **Note:** Each spec is independent. Any one left unset falls back to the library's default
> 700ms cross-fade — `predictivePopTransitionSpec` included, which does *not* fall back to
> `popTransitionSpec`. `predictivePopTransitionSpec` also receives the swipe edge
> (`NavigationEvent.EDGE_LEFT`, `EDGE_RIGHT` or `EDGE_NONE`) and runs when the gesture *starts*,
> so a side effect placed in it fires even for gestures the user goes on to cancel.

## Advanced Features

Expand Down
, '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
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 64 additions & 16 deletions auth/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1585,13 +1585,16 @@ If left unset (`null`), the top app bar falls back to colors derived from `color

### Screen Transitions

Customize the animations when navigating between screens using the `AuthUITransitions` object:
Customize the animations when navigating between screens using the `AuthUITransitions` object.
Each spec is an `AnimatedContentTransitionScope<Scene<NavKey>>` receiver returning one
`ContentTransform`, so the enter and exit halves are paired with `togetherWith`:

**Slide animations:**

```kotlin
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
Expand All@@ -1600,10 +1603,14 @@ val configuration = authUIConfiguration {
provider(AuthProvider.Google())
}
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } }, // Slide in from right
exitTransition = { slideOutHorizontally { -it } }, // Slide out to left
popEnterTransition = { slideInHorizontally { -it } }, // Slide in from left
popExitTransition = { slideOutHorizontally { it } } // Slide out to right
// Slide in from right, slide out to left
transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
// Slide in from left, slide out to right
popTransitionSpec = { slideInHorizontally { -it } togetherWith slideOutHorizontally { it } },
// Predictive back falls back to the default cross-fade if left unset, so mirror the pop
predictivePopTransitionSpec = {
slideInHorizontally { -it } togetherWith slideOutHorizontally { it }
}
)
}
```
Expand All@@ -1613,17 +1620,17 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Phone())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() },
exitTransition = { fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { fadeOut() }
transitionSpec = { fadeIn() togetherWith fadeOut() },
popTransitionSpec = { fadeIn() togetherWith fadeOut() },
predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }
)
}
```
Expand All@@ -1635,17 +1642,22 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Facebook())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
exitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) },
popEnterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
popExitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) }
transitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
},
popTransitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
}
)
}
```
Expand All@@ -1655,20 +1667,56 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
// A vertical push: the new step rises from the bottom as the old one leaves via the top
transitionSpec = { slideInVertically { it } togetherWith slideOutVertically { -it } }
Comment thread
demolaf marked this conversation as resolved.
)
}
```

**Per-destination animations:**

Read `authRoute()` off `initialState` / `targetState` to vary the animation by the screen being
navigated to or from:

```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions
import com.firebase.ui.auth.ui.screens.AuthRoute
import com.firebase.ui.auth.ui.screens.authRoute

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
enterTransition = { slideInVertically { it } }, // Slide up
exitTransition = { slideOutVertically { -it } } // Slide down
transitionSpec = {
if (targetState.authRoute() is AuthRoute.Success) {
fadeIn() togetherWith fadeOut()
} else {
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
}
)
}
```

> **Note:** If not specified, default fade in/out transitions with 700ms duration are used.
> **Note:** Each spec is independent. Any one left unset falls back to the library's default
> 700ms cross-fade — `predictivePopTransitionSpec` included, which does *not* fall back to
> `popTransitionSpec`. `predictivePopTransitionSpec` also receives the swipe edge
> (`NavigationEvent.EDGE_LEFT`, `EDGE_RIGHT` or `EDGE_NONE`) and runs when the gesture *starts*,
> so a side effect placed in it fires even for gestures the user goes on to cancel.

## Advanced Features

Expand Down
, '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
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 64 additions & 16 deletions auth/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1585,13 +1585,16 @@ If left unset (`null`), the top app bar falls back to colors derived from `color

### Screen Transitions

Customize the animations when navigating between screens using the `AuthUITransitions` object:
Customize the animations when navigating between screens using the `AuthUITransitions` object.
Each spec is an `AnimatedContentTransitionScope<Scene<NavKey>>` receiver returning one
`ContentTransform`, so the enter and exit halves are paired with `togetherWith`:

**Slide animations:**

```kotlin
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
Expand All@@ -1600,10 +1603,14 @@ val configuration = authUIConfiguration {
provider(AuthProvider.Google())
}
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } }, // Slide in from right
exitTransition = { slideOutHorizontally { -it } }, // Slide out to left
popEnterTransition = { slideInHorizontally { -it } }, // Slide in from left
popExitTransition = { slideOutHorizontally { it } } // Slide out to right
// Slide in from right, slide out to left
transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
// Slide in from left, slide out to right
popTransitionSpec = { slideInHorizontally { -it } togetherWith slideOutHorizontally { it } },
// Predictive back falls back to the default cross-fade if left unset, so mirror the pop
predictivePopTransitionSpec = {
slideInHorizontally { -it } togetherWith slideOutHorizontally { it }
}
)
}
```
Expand All@@ -1613,17 +1620,17 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Phone())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() },
exitTransition = { fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { fadeOut() }
transitionSpec = { fadeIn() togetherWith fadeOut() },
popTransitionSpec = { fadeIn() togetherWith fadeOut() },
predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }
)
}
```
Expand All@@ -1635,17 +1642,22 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Facebook())
}
transitions = AuthUITransitions(
enterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
exitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) },
popEnterTransition = { fadeIn() + scaleIn(initialScale = 0.9f) },
popExitTransition = { fadeOut() + scaleOut(targetScale = 0.9f) }
transitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
},
popTransitionSpec = {
fadeIn() + scaleIn(initialScale = 0.9f) togetherWith
fadeOut() + scaleOut(targetScale = 0.9f)
}
)
}
```
Expand All@@ -1655,20 +1667,56 @@ val configuration = authUIConfiguration {
```kotlin
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
// A vertical push: the new step rises from the bottom as the old one leaves via the top
transitionSpec = { slideInVertically { it } togetherWith slideOutVertically { -it } }
Comment thread
demolaf marked this conversation as resolved.
)
}
```

**Per-destination animations:**

Read `authRoute()` off `initialState` / `targetState` to vary the animation by the screen being
navigated to or from:

```kotlin
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import com.firebase.ui.auth.configuration.AuthUITransitions
import com.firebase.ui.auth.ui.screens.AuthRoute
import com.firebase.ui.auth.ui.screens.authRoute

val configuration = authUIConfiguration {
providers {
provider(AuthProvider.Email())
}
transitions = AuthUITransitions(
enterTransition = { slideInVertically { it } }, // Slide up
exitTransition = { slideOutVertically { -it } } // Slide down
transitionSpec = {
if (targetState.authRoute() is AuthRoute.Success) {
fadeIn() togetherWith fadeOut()
} else {
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
}
)
}
```

> **Note:** If not specified, default fade in/out transitions with 700ms duration are used.
> **Note:** Each spec is independent. Any one left unset falls back to the library's default
> 700ms cross-fade — `predictivePopTransitionSpec` included, which does *not* fall back to
> `popTransitionSpec`. `predictivePopTransitionSpec` also receives the swipe edge
> (`NavigationEvent.EDGE_LEFT`, `EDGE_RIGHT` or `EDGE_NONE`) and runs when the gesture *starts*,
> so a side effect placed in it fires even for gestures the user goes on to cancel.

## Advanced Features

Expand Down