TASK-069: bottom tab switches glide the whole width

Agent: main (opus)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
최민영 2026-10-12 14:28:44 +09:00
parent 85352d3a1c
commit 7368b27c65
3 changed files with 27 additions and 8 deletions

View File

@ -17,10 +17,12 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.tween
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 androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
@ -41,6 +43,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntOffset
import com.ubisam.ubgitea.core.auth.protocol.UBGiteaOAuthDefaults
import com.ubisam.ubgitea.core.notifications.FavoritePushNotifier
import com.ubisam.ubgitea.core.notifications.FavoritePushScheduler
@ -436,13 +439,19 @@ class MainActivity : ComponentActivity() {
transitionSpec = {
val fromTab = initialState.tab
val toTab = targetState.tab
val direction = when {
stackDepth != shownDepth[0] -> stackDepth - shownDepth[0]
fromTab != null && toTab != null -> toTab.ordinal - fromTab.ordinal
else -> 0
}.coerceIn(-1, 1)
val tabSwitch = stackDepth == shownDepth[0] && fromTab != null && toTab != null
if (tabSwitch) {
// Tabs sit side by side: the old one glides out as the new one
// glides in, the whole width, like turning to the next page.
val direction = (toTab.ordinal - fromTab.ordinal).coerceIn(-1, 1)
val glide = tween<IntOffset>(320, easing = FastOutSlowInEasing)
slideInHorizontally(glide) { it * direction }
.togetherWith(slideOutHorizontally(glide) { -it * direction })
} else {
val direction = (stackDepth - shownDepth[0]).coerceIn(-1, 1)
(fadeIn(tween(200, delayMillis = 50)) + slideInHorizontally(tween(260)) { it / 10 * direction })
.togetherWith(fadeOut(tween(90)))
}
},
contentKey = { it::class },
label = "route",

View File

@ -1552,3 +1552,12 @@ This is the append-only implementation and handoff record shared by Codex and Cl
superseded. Publishing is the three steps in `tasks/070-update-from-gitea.md`.
- Caution: the page at `choimy0204.github.io/ubgitea/` still exists (password, 0.2.0). Copies of
the app older than 0.2.2 keep reading it and see "up to date".
## 2026-10-12 (continued) — TASK-069: tab switches glide
- Request: the product owner wanted moving between bottom tabs to glide.
- What changed: a tab switch now moves both screens the whole width, the old one out as the new
one comes in (320 ms), in place of the short nudge with a fade. Pushed and popped screens keep
the short slide.
- Checks and results: the five required checks pass. Not seen on a device; not in the published
0.2.2.

View File

@ -17,7 +17,8 @@ The app moves where it used to jump, and what moves is the launcher icon's tea c
6. Pull to refresh brings the cup down with the finger; the steam appears near the release point.
7. A file's diff arrives row by row the first time it is shown.
8. Added while this was in progress (product owner, 2026-10-12): switching bottom tabs slides the
screen in from the side that tab sits on, and the tab's icon springs.
whole screen sideways, the old tab gliding out as the new one glides in, and the tab's icon
springs.
## Scope