mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 17:23:25 +00:00
FIX - support folder dragging across scaling (#41)
This commit is contained in:
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
normalizePhoneViewportRect,
|
||||
phoneViewportRectContainsPoint,
|
||||
readPhoneViewportGeometry,
|
||||
type PhoneViewportRect,
|
||||
} from '@/utils/phoneViewportGeometry'
|
||||
@@ -63,7 +64,78 @@ function createGeometryFixture(options: {
|
||||
}
|
||||
}
|
||||
|
||||
const PHONE_BASE_ZOOM = 0.69 * 1.2
|
||||
const PHONE_HEIGHT = 844
|
||||
const PHONE_WIDTH = 390
|
||||
const REFERENCE_VIEWPORT_HEIGHT = 1080
|
||||
const REFERENCE_VIEWPORT_WIDTH = 1920
|
||||
|
||||
const displayCases = [
|
||||
{ height: 1080, label: '1080p 16:9', width: 1920 },
|
||||
{ height: 2160, label: '4K 16:9', width: 3840 },
|
||||
{ height: 1440, label: '21:9', width: 3440 },
|
||||
{ height: 1440, label: '32:9', width: 5120 },
|
||||
{ height: 1600, label: '16:10', width: 2560 },
|
||||
] as const
|
||||
|
||||
const phoneScales = [80, 100, 120] as const
|
||||
|
||||
function productionPhoneZoom(
|
||||
viewportWidth: number,
|
||||
viewportHeight: number,
|
||||
phoneScale: number,
|
||||
): number {
|
||||
const viewportScale = Math.min(
|
||||
viewportWidth / REFERENCE_VIEWPORT_WIDTH,
|
||||
viewportHeight / REFERENCE_VIEWPORT_HEIGHT,
|
||||
)
|
||||
const preferred = PHONE_BASE_ZOOM * viewportScale * (phoneScale / 100)
|
||||
const edgeGap = 24 * viewportScale
|
||||
const viewportMaximum = Math.max(
|
||||
0,
|
||||
Math.min(
|
||||
(viewportWidth - edgeGap) / PHONE_WIDTH,
|
||||
(viewportHeight - edgeGap) / PHONE_HEIGHT,
|
||||
),
|
||||
)
|
||||
|
||||
return Math.min(viewportMaximum, Math.max(260 / PHONE_WIDTH, preferred))
|
||||
}
|
||||
|
||||
const cefDisplayMatrix = displayCases.flatMap((display) =>
|
||||
phoneScales.map((phoneScale) => ({ display, phoneScale })),
|
||||
)
|
||||
|
||||
describe('phone viewport geometry', () => {
|
||||
it('treats every rectangle boundary as inside and rejects points beyond it', () => {
|
||||
const rect: PhoneViewportRect = {
|
||||
bottom: 260,
|
||||
height: 160,
|
||||
left: 120,
|
||||
right: 360,
|
||||
top: 100,
|
||||
width: 240,
|
||||
}
|
||||
|
||||
expect(phoneViewportRectContainsPoint(rect, 240, 180)).toBe(true)
|
||||
expect(phoneViewportRectContainsPoint(rect, rect.left, rect.top)).toBe(true)
|
||||
expect(phoneViewportRectContainsPoint(rect, rect.right, rect.bottom)).toBe(
|
||||
true,
|
||||
)
|
||||
expect(phoneViewportRectContainsPoint(rect, rect.left - 0.001, 180)).toBe(
|
||||
false,
|
||||
)
|
||||
expect(phoneViewportRectContainsPoint(rect, rect.right + 0.001, 180)).toBe(
|
||||
false,
|
||||
)
|
||||
expect(phoneViewportRectContainsPoint(rect, 240, rect.top - 0.001)).toBe(
|
||||
false,
|
||||
)
|
||||
expect(phoneViewportRectContainsPoint(rect, 240, rect.bottom + 0.001)).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
it('leaves modern Chrome measurements unchanged when the canvas BCR is already rendered', () => {
|
||||
const wrapper = measuredRect(1573.09, 126.25, 322.92, 698.832)
|
||||
const layer = measuredRect(1589.783336, 177.75, 289.533328, 603.2)
|
||||
@@ -124,6 +196,76 @@ describe('phone viewport geometry', () => {
|
||||
},
|
||||
)
|
||||
|
||||
it.each(cefDisplayMatrix)(
|
||||
'keeps an opened folder panel hit-test exact at $phoneScale% on $display.label',
|
||||
({ display, phoneScale }) => {
|
||||
const viewportScale = Math.min(
|
||||
display.width / REFERENCE_VIEWPORT_WIDTH,
|
||||
display.height / REFERENCE_VIEWPORT_HEIGHT,
|
||||
)
|
||||
const zoom = productionPhoneZoom(
|
||||
display.width,
|
||||
display.height,
|
||||
phoneScale,
|
||||
)
|
||||
const edgeGap = 24 * viewportScale
|
||||
const wrapper = measuredRect(
|
||||
display.width - edgeGap - PHONE_WIDTH * zoom,
|
||||
display.height - edgeGap - PHONE_HEIGHT * zoom,
|
||||
PHONE_WIDTH * zoom,
|
||||
PHONE_HEIGHT * zoom,
|
||||
)
|
||||
// Live CEF 103 can report the zoomed canvas in a different coordinate
|
||||
// space from pointer events. Preserve that mismatch in this fixture.
|
||||
const rawCanvas = measuredRect(
|
||||
display.width + 117.375,
|
||||
83.625,
|
||||
PHONE_WIDTH,
|
||||
PHONE_HEIGHT,
|
||||
)
|
||||
const rawPanel = measuredRect(
|
||||
rawCanvas.left + 23.25,
|
||||
rawCanvas.top + 246.75,
|
||||
343.5,
|
||||
324.25,
|
||||
)
|
||||
const panel = normalizePhoneViewportRect(rawPanel, rawCanvas, wrapper)
|
||||
const expected = {
|
||||
bottom: wrapper.top + (246.75 + 324.25) * zoom,
|
||||
height: 324.25 * zoom,
|
||||
left: wrapper.left + 23.25 * zoom,
|
||||
right: wrapper.left + (23.25 + 343.5) * zoom,
|
||||
top: wrapper.top + 246.75 * zoom,
|
||||
width: 343.5 * zoom,
|
||||
}
|
||||
|
||||
expectRectClose(panel, expected)
|
||||
expect(
|
||||
phoneViewportRectContainsPoint(
|
||||
panel,
|
||||
panel.left + panel.width / 2,
|
||||
panel.top + panel.height / 2,
|
||||
),
|
||||
).toBe(true)
|
||||
expect(phoneViewportRectContainsPoint(panel, panel.left, panel.top)).toBe(
|
||||
true,
|
||||
)
|
||||
expect(
|
||||
phoneViewportRectContainsPoint(panel, panel.right, panel.bottom),
|
||||
).toBe(true)
|
||||
expect(
|
||||
phoneViewportRectContainsPoint(panel, panel.left - 0.25, panel.top),
|
||||
).toBe(false)
|
||||
expect(
|
||||
phoneViewportRectContainsPoint(panel, panel.right + 0.25, panel.bottom),
|
||||
).toBe(false)
|
||||
expect(panel.left).toBeGreaterThanOrEqual(0)
|
||||
expect(panel.right).toBeLessThanOrEqual(display.width)
|
||||
expect(panel.top).toBeGreaterThanOrEqual(0)
|
||||
expect(panel.bottom).toBeLessThanOrEqual(display.height)
|
||||
},
|
||||
)
|
||||
|
||||
it('reads visual scale and normalized element rects from a canvas anchor', () => {
|
||||
const fixture = createGeometryFixture({
|
||||
canvasOffsetHeight: 844,
|
||||
|
||||
Reference in New Issue
Block a user