mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-30 17:59:02 +00:00
dca0868753
* FIX - stabilize homescreen dragging across scaling Render the home drag preview in an unzoomed viewport portal and normalize FiveM CEF DOM geometry before hit testing and drop settling. Cover Chrome 103, fractional scaling, 4K, ultrawide, and non-16:9 viewport behavior. * FIX - Implement LB guest app layout and lifecycle bridge Ensure custom LB apps are properly sized and visible by applying the required CSS contract on initialization and upon receiving the 'componentsLoaded' signal. * FIX - match uppercase script tags in LB bridge test
196 lines
6.0 KiB
TypeScript
196 lines
6.0 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import {
|
|
maximumRenderedWidgetPage,
|
|
nearestSpringboardRectIndex,
|
|
resolveSpringboardEdgeTurn,
|
|
resolveSpringboardHomeEdgeTurn,
|
|
springboardEdgeDirection,
|
|
springboardPageDragCompensation,
|
|
springboardSwipeIntent,
|
|
springboardViewportDeltaToLocal,
|
|
springboardViewportToLocal,
|
|
} from '@/utils/springboardDrag'
|
|
|
|
describe('springboard widget drag', () => {
|
|
it('turns pages from the reachable phone edge zones', () => {
|
|
expect(springboardEdgeDirection(113, 100, 468)).toBe(-1)
|
|
expect(springboardEdgeDirection(455, 100, 468)).toBe(1)
|
|
expect(springboardEdgeDirection(284, 100, 468)).toBe(0)
|
|
})
|
|
|
|
it('keeps both phone edges reachable at normal and reduced FiveM scales', () => {
|
|
expect(springboardEdgeDirection(125, 100, 468)).toBe(-1)
|
|
expect(springboardEdgeDirection(150, 100, 468)).toBe(0)
|
|
expect(springboardEdgeDirection(420, 100, 468)).toBe(0)
|
|
expect(springboardEdgeDirection(443, 100, 468)).toBe(1)
|
|
expect(springboardEdgeDirection(117, 100, 247)).toBe(-1)
|
|
expect(springboardEdgeDirection(200, 100, 247)).toBe(0)
|
|
expect(springboardEdgeDirection(230, 100, 247)).toBe(1)
|
|
expect(springboardEdgeDirection(100, 100, 100)).toBe(0)
|
|
})
|
|
|
|
it('resolves reachable page destinations without crossing page bounds', () => {
|
|
expect(resolveSpringboardEdgeTurn(455, 100, 468, 1, 0, 3)).toEqual({
|
|
destination: 2,
|
|
direction: 1,
|
|
})
|
|
expect(resolveSpringboardEdgeTurn(113, 100, 468, 2, 0, 3)).toEqual({
|
|
destination: 1,
|
|
direction: -1,
|
|
})
|
|
expect(resolveSpringboardEdgeTurn(113, 100, 468, 0, 0, 3)).toBeNull()
|
|
expect(resolveSpringboardEdgeTurn(455, 100, 468, 3, 0, 3)).toBeNull()
|
|
})
|
|
|
|
it('resolves consecutive edge turns while an app remains at the same edge', () => {
|
|
const firstTurn = resolveSpringboardHomeEdgeTurn(
|
|
113,
|
|
100,
|
|
468,
|
|
4,
|
|
4,
|
|
5,
|
|
false,
|
|
)
|
|
expect(firstTurn).toEqual({
|
|
destination: 3,
|
|
direction: -1,
|
|
previewsPage: false,
|
|
})
|
|
expect(
|
|
resolveSpringboardHomeEdgeTurn(
|
|
113,
|
|
100,
|
|
468,
|
|
firstTurn?.destination ?? 4,
|
|
4,
|
|
5,
|
|
false,
|
|
),
|
|
).toEqual({ destination: 2, direction: -1, previewsPage: false })
|
|
})
|
|
|
|
it('previews one new trailing page without crossing the home-page limit', () => {
|
|
expect(
|
|
resolveSpringboardHomeEdgeTurn(455, 100, 468, 2, 2, 5, false),
|
|
).toEqual({ destination: 3, direction: 1, previewsPage: true })
|
|
expect(
|
|
resolveSpringboardHomeEdgeTurn(455, 100, 468, 2, 3, 5, true),
|
|
).toEqual({ destination: 3, direction: 1, previewsPage: false })
|
|
expect(
|
|
resolveSpringboardHomeEdgeTurn(455, 100, 468, 5, 5, 5, false),
|
|
).toBeNull()
|
|
})
|
|
|
|
it('keeps the original widget page mounted during a drag preview', () => {
|
|
expect(maximumRenderedWidgetPage([1, 3], [1, 2])).toBe(3)
|
|
expect(maximumRenderedWidgetPage([], [])).toBe(1)
|
|
})
|
|
|
|
it('distinguishes a page swipe from a tap or vertical gesture', () => {
|
|
expect(springboardSwipeIntent(5, 2)).toBe('pending')
|
|
expect(springboardSwipeIntent(30, 8)).toBe('horizontal')
|
|
expect(springboardSwipeIntent(8, 30)).toBe('vertical')
|
|
})
|
|
|
|
it('keeps a dragged item under the pointer while the track changes pages', () => {
|
|
expect(springboardPageDragCompensation(3, 2, 368)).toBe(-368)
|
|
expect(springboardPageDragCompensation(2, 3, 368)).toBe(368)
|
|
expect(springboardPageDragCompensation(2, 2, 368)).toBe(0)
|
|
})
|
|
|
|
it('selects drop slots directly in viewport order', () => {
|
|
const slots = [
|
|
{ height: 80, left: 100, top: 150, width: 70 },
|
|
{ height: 80, left: 180, top: 150, width: 70 },
|
|
{ height: 80, left: 260, top: 150, width: 70 },
|
|
]
|
|
|
|
expect(nearestSpringboardRectIndex(115, 190, slots)).toBe(0)
|
|
expect(nearestSpringboardRectIndex(300, 190, slots)).toBe(2)
|
|
expect(nearestSpringboardRectIndex(220, 190, slots)).toBe(1)
|
|
expect(nearestSpringboardRectIndex(220, 190, [])).toBeNull()
|
|
})
|
|
|
|
it('converts viewport coordinates into local phone coordinates under zoom', () => {
|
|
const point = springboardViewportToLocal(
|
|
169,
|
|
238,
|
|
100,
|
|
100,
|
|
253.92,
|
|
582.36,
|
|
368,
|
|
844,
|
|
)
|
|
expect(point.x).toBeCloseTo(100)
|
|
expect(point.y).toBeCloseTo(200)
|
|
expect(
|
|
springboardViewportToLocal(200, 250, 100, 50, 0, 0, 368, 844),
|
|
).toEqual({ x: 100, y: 200 })
|
|
const delta = springboardViewportDeltaToLocal(
|
|
69,
|
|
138,
|
|
253.92,
|
|
582.36,
|
|
368,
|
|
844,
|
|
)
|
|
expect(delta.x).toBeCloseTo(100)
|
|
expect(delta.y).toBeCloseTo(200)
|
|
})
|
|
|
|
it.each([
|
|
['80% preview', 0.6624],
|
|
['80% production clamp', 2 / 3],
|
|
['100%', 0.828],
|
|
['120%', 0.9936],
|
|
])('keeps the rendered drag delta 1:1 at %s zoom', (_label, zoom) => {
|
|
const layoutWidth = 350
|
|
const layoutHeight = 808
|
|
const viewportLeft = 128.25
|
|
const viewportTop = 64.5
|
|
const viewportWidth = layoutWidth * zoom
|
|
const viewportHeight = layoutHeight * zoom
|
|
const pointerStart = {
|
|
x: viewportLeft + 48.5 * zoom,
|
|
y: viewportTop + 132.25 * zoom,
|
|
}
|
|
const viewportDelta = { x: 73.25, y: -41.75 }
|
|
const start = springboardViewportToLocal(
|
|
pointerStart.x,
|
|
pointerStart.y,
|
|
viewportLeft,
|
|
viewportTop,
|
|
viewportWidth,
|
|
viewportHeight,
|
|
layoutWidth,
|
|
layoutHeight,
|
|
)
|
|
const end = springboardViewportToLocal(
|
|
pointerStart.x + viewportDelta.x,
|
|
pointerStart.y + viewportDelta.y,
|
|
viewportLeft,
|
|
viewportTop,
|
|
viewportWidth,
|
|
viewportHeight,
|
|
layoutWidth,
|
|
layoutHeight,
|
|
)
|
|
const localDelta = springboardViewportDeltaToLocal(
|
|
viewportDelta.x,
|
|
viewportDelta.y,
|
|
viewportWidth,
|
|
viewportHeight,
|
|
layoutWidth,
|
|
layoutHeight,
|
|
)
|
|
|
|
expect((end.x - start.x) * zoom).toBeCloseTo(viewportDelta.x, 6)
|
|
expect((end.y - start.y) * zoom).toBeCloseTo(viewportDelta.y, 6)
|
|
expect(localDelta.x * zoom).toBeCloseTo(viewportDelta.x, 6)
|
|
expect(localDelta.y * zoom).toBeCloseTo(viewportDelta.y, 6)
|
|
})
|
|
})
|