UI: enable the back-swipe inside Telegram (fix lost swipe-back)
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 41s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 57s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 41s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 57s
The gesture was disabled inside Telegram on the mistaken assumption it would
fight a Telegram horizontal close gesture — but Telegram's only close/minimise
gesture is vertical (disableVerticalSwipes, Bot API 7.7+). Disabling it there,
together with dropping the old left-edge swipe, removed every swipe-back in
Telegram (which that edge-swipe — deliberately enabled in TG, commit 7e34897 —
had provided).
Make shouldArm Telegram-agnostic (drop the insideTelegram guard + its now-unused
import); the gesture works in Telegram too, alongside the native BackButton.
Drop the redundant overscroll-behavior-x on .router (body already sets
overscroll-behavior: none). Regression: an e2e drives the swipe under an
injected Telegram WebApp stub and asserts it navigates back.
This commit is contained in:
+3
-2
@@ -31,8 +31,9 @@ Login uses `Screen`.
|
|||||||
back). The live parent mounts only on commit, which suppresses that one route slide so the
|
back). The live parent mounts only on commit, which suppresses that one route slide so the
|
||||||
hand-off is seamless. The gesture yields to native **vertical scroll** on a vertical move
|
hand-off is seamless. The gesture yields to native **vertical scroll** on a vertical move
|
||||||
and skips the rack, a draggable pending tile, text inputs and the board **while zoomed-in**
|
and skips the rack, a draggable pending tile, text inputs and the board **while zoomed-in**
|
||||||
(so it never fights the board pan); it stays disabled inside Telegram, whose native
|
(so it never fights the board pan). It works **inside Telegram** too — Telegram's only
|
||||||
BackButton owns this.
|
close/minimise gesture is *vertical* (disabled separately via `disableVerticalSwipes`), so
|
||||||
|
a horizontal back-swipe has nothing to fight; the native header BackButton complements it.
|
||||||
- **No hamburger**: navigation is entirely bottom tab bars (the former `Menu.svelte`
|
- **No hamburger**: navigation is entirely bottom tab bars (the former `Menu.svelte`
|
||||||
dropdown is gone — it fought the Telegram-fullscreen layout, where it had to be re-centred).
|
dropdown is gone — it fought the Telegram-fullscreen layout, where it had to be re-centred).
|
||||||
Destinations beyond the lobby live behind **hub screens** reached from a tab: a ⚙️
|
Destinations beyond the lobby live behind **hub screens** reached from a tab: a ⚙️
|
||||||
|
|||||||
@@ -22,6 +22,22 @@ async function openAnnGame(page: Page): Promise<void> {
|
|||||||
await page.waitForTimeout(400); // let the open slide settle before measuring/aiming
|
await page.waitForTimeout(400); // let the open slide settle before measuring/aiming
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A minimal Telegram WebApp stub: non-empty initData makes insideTelegram() true and drives
|
||||||
|
// the Mini App auto-auth into the lobby (the mock gateway accepts any initData).
|
||||||
|
function telegramStub() {
|
||||||
|
return {
|
||||||
|
Telegram: {
|
||||||
|
WebApp: {
|
||||||
|
initData: 'query_id=test&user=%7B%22id%22%3A1%7D&auth_date=1&hash=deadbeef',
|
||||||
|
initDataUnsafe: {},
|
||||||
|
themeParams: {},
|
||||||
|
ready() {},
|
||||||
|
expand() {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/** touchDrag dispatches a single-finger touch drag from (x0,y0) to (x1,y1) over the window. */
|
/** touchDrag dispatches a single-finger touch drag from (x0,y0) to (x1,y1) over the window. */
|
||||||
async function touchDrag(page: Page, x0: number, y0: number, x1: number, y1: number): Promise<void> {
|
async function touchDrag(page: Page, x0: number, y0: number, x1: number, y1: number): Promise<void> {
|
||||||
await page.evaluate(
|
await page.evaluate(
|
||||||
@@ -88,3 +104,20 @@ test('a vertical drag in the band scrolls instead of navigating', async ({ page
|
|||||||
await page.waitForTimeout(300);
|
await page.waitForTimeout(300);
|
||||||
expect(page.url()).toContain('/game/');
|
expect(page.url()).toContain('/game/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the back-swipe also works inside Telegram (its only swipe gesture is vertical)', async ({ page }) => {
|
||||||
|
await page.addInitScript((stub) => {
|
||||||
|
Object.assign(window, stub);
|
||||||
|
}, telegramStub());
|
||||||
|
await page.goto('/');
|
||||||
|
|
||||||
|
// Telegram auto-authenticates into the lobby (no guest click), then open the seeded game.
|
||||||
|
await page.getByRole('button', { name: /Ann/ }).click();
|
||||||
|
await expect(page.locator('[data-cell]').first()).toBeVisible();
|
||||||
|
await page.waitForTimeout(400);
|
||||||
|
|
||||||
|
await touchDrag(page, START_X, MID_Y, 300, MID_Y);
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(/#\/$/);
|
||||||
|
await expect(page.getByRole('button', { name: /Ann/ })).toBeVisible();
|
||||||
|
});
|
||||||
|
|||||||
@@ -141,8 +141,6 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
/* Keep a horizontal drag from also triggering the browser's history-swipe underneath. */
|
|
||||||
overscroll-behavior-x: contain;
|
|
||||||
}
|
}
|
||||||
.pane {
|
.pane {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
import { app } from './app.svelte';
|
import { app } from './app.svelte';
|
||||||
import { createBackSwipe, shouldArm } from './backswipe';
|
import { createBackSwipe, shouldArm } from './backswipe';
|
||||||
import { navigate } from './router.svelte';
|
import { navigate } from './router.svelte';
|
||||||
import { insideTelegram } from './telegram';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* backSwipe is the reactive view of the in-flight gesture. App binds `progress` to the
|
* backSwipe is the reactive view of the in-flight gesture. App binds `progress` to the
|
||||||
@@ -127,7 +126,6 @@ export function initBackSwipe(getParent: () => string | null): () => void {
|
|||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
pointerType: e.pointerType,
|
pointerType: e.pointerType,
|
||||||
hasParent: !!parent,
|
hasParent: !!parent,
|
||||||
insideTelegram: insideTelegram(),
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ describe('shouldArm', () => {
|
|||||||
width: 400,
|
width: 400,
|
||||||
pointerType: 'touch',
|
pointerType: 'touch',
|
||||||
hasParent: true,
|
hasParent: true,
|
||||||
insideTelegram: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
it('arms a touch press inside the left band of a screen with a parent', () => {
|
it('arms a touch press inside the left band of a screen with a parent', () => {
|
||||||
@@ -15,11 +14,10 @@ describe('shouldArm', () => {
|
|||||||
expect(shouldArm({ ...base, clientX: 0.38 * 400 - 1 })).toBe(true);
|
expect(shouldArm({ ...base, clientX: 0.38 * 400 - 1 })).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not arm past the band, for a mouse, at a root, or inside Telegram', () => {
|
it('does not arm past the band, for a mouse, or at a root', () => {
|
||||||
expect(shouldArm({ ...base, clientX: 0.38 * 400 + 1 })).toBe(false);
|
expect(shouldArm({ ...base, clientX: 0.38 * 400 + 1 })).toBe(false);
|
||||||
expect(shouldArm({ ...base, pointerType: 'mouse' })).toBe(false);
|
expect(shouldArm({ ...base, pointerType: 'mouse' })).toBe(false);
|
||||||
expect(shouldArm({ ...base, hasParent: false })).toBe(false);
|
expect(shouldArm({ ...base, hasParent: false })).toBe(false);
|
||||||
expect(shouldArm({ ...base, insideTelegram: true })).toBe(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('honours a custom band fraction', () => {
|
it('honours a custom band fraction', () => {
|
||||||
|
|||||||
@@ -30,18 +30,18 @@ export interface ArmInput {
|
|||||||
pointerType: string;
|
pointerType: string;
|
||||||
/** Whether the current screen has a parent to return to (false on a navigation root). */
|
/** Whether the current screen has a parent to return to (false on a navigation root). */
|
||||||
hasParent: boolean;
|
hasParent: boolean;
|
||||||
/** Whether the app is running inside Telegram, where its native Back button owns this. */
|
|
||||||
insideTelegram: boolean;
|
|
||||||
/** Fraction of the width forming the left activation band; defaults to 0.38. */
|
/** Fraction of the width forming the left activation band; defaults to 0.38. */
|
||||||
bandFrac?: number;
|
bandFrac?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shouldArm decides whether a pointerdown may begin a back-swipe: a touch or pen press in
|
* shouldArm decides whether a pointerdown may begin a back-swipe: a touch or pen press in
|
||||||
* the left band of a screen that has a parent, while not inside Telegram.
|
* the left band of a screen that has a parent. It is intentionally Telegram-agnostic —
|
||||||
|
* Telegram's only close/minimise gesture is vertical (handled by disableVerticalSwipes), so
|
||||||
|
* a horizontal back-swipe has nothing to conflict with there.
|
||||||
*/
|
*/
|
||||||
export function shouldArm(i: ArmInput): boolean {
|
export function shouldArm(i: ArmInput): boolean {
|
||||||
if (!i.hasParent || i.insideTelegram) return false;
|
if (!i.hasParent) return false;
|
||||||
if (i.pointerType === 'mouse') return false;
|
if (i.pointerType === 'mouse') return false;
|
||||||
const band = (i.bandFrac ?? 0.38) * i.width;
|
const band = (i.bandFrac ?? 0.38) * i.width;
|
||||||
return i.clientX <= band;
|
return i.clientX <= band;
|
||||||
|
|||||||
Reference in New Issue
Block a user