fix(profiles): keep the picker chrome-free
/profiles was unknown to the layout shell, so reaching it from Settings rendered the bottom nav and global header over the picker -- letting someone tab straight past the profile they were being asked to choose, and offering an in-app mini player as a route back into the previous profile's queue. Grouped with /login throughout layoutShell: it is a gate, not a page. OS lockscreen transport controls are unaffected, which is what keeps playing audio controllable while the app is locked.
This commit is contained in:
@@ -202,3 +202,37 @@ describe("showHeaderSearch", () => {
|
|||||||
expect(showHeaderSearch({ pathname: "/settings" })).toBe(false);
|
expect(showHeaderSearch({ pathname: "/settings" })).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The profile picker is a gate, not a page. It must be chrome-free for the same
|
||||||
|
* reason /login is: bottom nav over a "who's watching" screen lets someone tab
|
||||||
|
* straight past the profile they were being asked to choose, and an in-app mini
|
||||||
|
* player on it would offer a route into the previous profile's queue. OS
|
||||||
|
* lockscreen transport controls are unaffected — those are what keep playing
|
||||||
|
* audio controllable while the app is locked (DR-275).
|
||||||
|
*
|
||||||
|
* TRACES: UR-082 | DR-276
|
||||||
|
*/
|
||||||
|
describe("profile picker chrome", () => {
|
||||||
|
const pathname = "/profiles";
|
||||||
|
|
||||||
|
it("shows no bottom nav, even authenticated", () => {
|
||||||
|
expect(showBottomNav({ pathname, isAuthenticated: true })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows no global mini player", () => {
|
||||||
|
expect(showGlobalMiniPlayer({ pathname })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows no global header", () => {
|
||||||
|
expect(showGlobalHeader({ pathname, isAuthenticated: true })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("owns its own layout", () => {
|
||||||
|
expect(routeOwnsLayout({ pathname })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("lets the shell reserve the bottom inset, since nothing else will", () => {
|
||||||
|
expect(shellReservesBottomInset({ pathname, isAuthenticated: true })).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -28,10 +28,19 @@ export interface BottomUiVisibilityInput {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The bottom nav is shown on every authenticated route except the full-screen
|
* The bottom nav is shown on every authenticated route except the full-screen
|
||||||
* player and the login route.
|
* player, the login route, and the profile picker.
|
||||||
|
*
|
||||||
|
* `/profiles` is grouped with `/login` throughout this module because it is a
|
||||||
|
* gate rather than a page: a nav bar over "who's watching" lets someone tab
|
||||||
|
* straight past the choice they were being asked to make.
|
||||||
*/
|
*/
|
||||||
export function showBottomNav({ pathname, isAuthenticated }: BottomUiVisibilityInput): boolean {
|
export function showBottomNav({ pathname, isAuthenticated }: BottomUiVisibilityInput): boolean {
|
||||||
return isAuthenticated && !pathname.startsWith("/player/") && !pathname.startsWith("/login");
|
return (
|
||||||
|
isAuthenticated &&
|
||||||
|
!pathname.startsWith("/player/") &&
|
||||||
|
!pathname.startsWith("/login") &&
|
||||||
|
!pathname.startsWith("/profiles")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,6 +53,7 @@ export function showGlobalMiniPlayer({ pathname }: { pathname: string }): boolea
|
|||||||
return (
|
return (
|
||||||
!pathname.startsWith("/player/") &&
|
!pathname.startsWith("/player/") &&
|
||||||
!pathname.startsWith("/login") &&
|
!pathname.startsWith("/login") &&
|
||||||
|
!pathname.startsWith("/profiles") &&
|
||||||
!pathname.startsWith("/settings")
|
!pathname.startsWith("/settings")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -58,7 +68,8 @@ export function routeOwnsLayout({ pathname }: { pathname: string }): boolean {
|
|||||||
return (
|
return (
|
||||||
pathname.startsWith("/library") ||
|
pathname.startsWith("/library") ||
|
||||||
pathname.startsWith("/player/") ||
|
pathname.startsWith("/player/") ||
|
||||||
pathname.startsWith("/login")
|
pathname.startsWith("/login") ||
|
||||||
|
pathname.startsWith("/profiles")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +80,7 @@ export function routeOwnsLayout({ pathname }: { pathname: string }): boolean {
|
|||||||
* Routes that own their layout (library) render their own AppHeader, so the
|
* Routes that own their layout (library) render their own AppHeader, so the
|
||||||
* root must not double it up. `/settings` owns its content but deliberately has
|
* root must not double it up. `/settings` owns its content but deliberately has
|
||||||
* no account menu (the user is already there). `/player/*` and `/login` are
|
* no account menu (the user is already there). `/player/*` and `/login` are
|
||||||
* immersive/chrome-free. Everything else authenticated (`/`, `/search`,
|
* immersive/chrome-free, as is `/profiles`. Everything else authenticated (`/`, `/search`,
|
||||||
* `/downloads`) gets the header from the root — the whole point of UR-054.
|
* `/downloads`) gets the header from the root — the whole point of UR-054.
|
||||||
*
|
*
|
||||||
* TRACES: UR-054 | DR-076
|
* TRACES: UR-054 | DR-076
|
||||||
@@ -109,7 +120,8 @@ export function showBottomUi(input: BottomUiVisibilityInput): boolean {
|
|||||||
* Exactly one element may reserve it. BottomUi owns it whenever it renders,
|
* Exactly one element may reserve it. BottomUi owns it whenever it renders,
|
||||||
* because the padding belongs *inside* its surface box so the colour extends
|
* because the padding belongs *inside* its surface box so the colour extends
|
||||||
* behind the bar rather than leaving a strip of page background. On routes with
|
* behind the bar rather than leaving a strip of page background. On routes with
|
||||||
* no bottom UI at all (login, the full-screen player) nothing else would, so
|
* no bottom UI at all (login, the profile picker, the full-screen player)
|
||||||
|
* nothing else would, so
|
||||||
* the shell takes it.
|
* the shell takes it.
|
||||||
*
|
*
|
||||||
* TRACES: UR-066 | DR-112
|
* TRACES: UR-066 | DR-112
|
||||||
|
|||||||
Reference in New Issue
Block a user