Spaces:
Running
Running
François Pachet commited on
Commit ·
f2beb6f
1
Parent(s): ebc2684
Improve Android phone detection
Browse files- README.md +10 -4
- frontend/app.js +28 -1
- frontend/index.html +2 -2
README.md
CHANGED
|
@@ -85,10 +85,13 @@ The UX principle is to keep the performance flow visible at all times and hide l
|
|
| 85 |
|
| 86 |
Phones use the same application and backend as desktop browsers. A compact,
|
| 87 |
touch-oriented layout is selected from viewport and pointer capabilities rather
|
| 88 |
-
than device names.
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
Phone interaction is deliberately automatic:
|
| 94 |
|
|
@@ -104,6 +107,9 @@ Phone mode is intended for playing and listening. Use the desktop/tablet layout
|
|
| 104 |
when you need session management, model settings, memory inspection, MIDI
|
| 105 |
hardware, or sound routing.
|
| 106 |
|
|
|
|
|
|
|
|
|
|
| 107 |
## Saving Session MIDI
|
| 108 |
|
| 109 |
The Session panel includes `Save Session MIDI`.
|
|
|
|
| 85 |
|
| 86 |
Phones use the same application and backend as desktop browsers. A compact,
|
| 87 |
touch-oriented layout is selected from viewport and pointer capabilities rather
|
| 88 |
+
than device names. Detection combines the current viewport, mobile browser
|
| 89 |
+
client hints, touch-pointer capability, and physical CSS screen dimensions so
|
| 90 |
+
Android phones still select the phone surface when the browser reports a
|
| 91 |
+
desktop-sized viewport. The phone surface contains only the virtual keyboard,
|
| 92 |
+
a small live-status message, and the captured/generated piano rolls.
|
| 93 |
+
Configuration, accounts, memory inspection, hardware MIDI, and device routing
|
| 94 |
+
remain available in the unchanged desktop/tablet layout.
|
| 95 |
|
| 96 |
Phone interaction is deliberately automatic:
|
| 97 |
|
|
|
|
| 107 |
when you need session management, model settings, memory inspection, MIDI
|
| 108 |
hardware, or sound routing.
|
| 109 |
|
| 110 |
+
For troubleshooting, append `?layout=phone` to force the phone surface or
|
| 111 |
+
`?layout=desktop` to force the complete interface.
|
| 112 |
+
|
| 113 |
## Saving Session MIDI
|
| 114 |
|
| 115 |
The Session panel includes `Save Session MIDI`.
|
frontend/app.js
CHANGED
|
@@ -18,6 +18,7 @@ const VIRTUAL_KEYBOARD_DESKTOP_OCTAVES = 2;
|
|
| 18 |
const VIRTUAL_KEYBOARD_PHONE_OCTAVES = 1;
|
| 19 |
const PHONE_LAYOUT_MEDIA_QUERY =
|
| 20 |
"(max-width: 640px), (pointer: coarse) and (max-height: 500px)";
|
|
|
|
| 21 |
const VIRTUAL_KEYBOARD_DEFAULT_BASE_NOTE = 60;
|
| 22 |
const VIRTUAL_KEYBOARD_MIN_BASE_NOTE = 24;
|
| 23 |
const VIRTUAL_KEYBOARD_MAX_BASE_NOTE = 96;
|
|
@@ -1613,7 +1614,33 @@ function virtualKeyboardOctaves() {
|
|
| 1613 |
}
|
| 1614 |
|
| 1615 |
function isPhoneLayout() {
|
| 1616 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1617 |
}
|
| 1618 |
|
| 1619 |
function syncPhoneLayout() {
|
|
|
|
| 18 |
const VIRTUAL_KEYBOARD_PHONE_OCTAVES = 1;
|
| 19 |
const PHONE_LAYOUT_MEDIA_QUERY =
|
| 20 |
"(max-width: 640px), (pointer: coarse) and (max-height: 500px)";
|
| 21 |
+
const PHONE_SCREEN_MAX_CSS_PX = 700;
|
| 22 |
const VIRTUAL_KEYBOARD_DEFAULT_BASE_NOTE = 60;
|
| 23 |
const VIRTUAL_KEYBOARD_MIN_BASE_NOTE = 24;
|
| 24 |
const VIRTUAL_KEYBOARD_MAX_BASE_NOTE = 96;
|
|
|
|
| 1614 |
}
|
| 1615 |
|
| 1616 |
function isPhoneLayout() {
|
| 1617 |
+
const requestedLayout = new URLSearchParams(window.location.search).get("layout");
|
| 1618 |
+
if (requestedLayout === "phone") {
|
| 1619 |
+
return true;
|
| 1620 |
+
}
|
| 1621 |
+
if (requestedLayout === "desktop") {
|
| 1622 |
+
return false;
|
| 1623 |
+
}
|
| 1624 |
+
|
| 1625 |
+
const responsiveMatch = Boolean(
|
| 1626 |
+
window.matchMedia?.(PHONE_LAYOUT_MEDIA_QUERY).matches,
|
| 1627 |
+
);
|
| 1628 |
+
const mobileClientHint = navigator.userAgentData?.mobile === true;
|
| 1629 |
+
const coarseTouch =
|
| 1630 |
+
Boolean(window.matchMedia?.("(pointer: coarse)").matches) ||
|
| 1631 |
+
navigator.maxTouchPoints > 0;
|
| 1632 |
+
const screenDimensions = [window.screen?.width, window.screen?.height]
|
| 1633 |
+
.map(Number)
|
| 1634 |
+
.filter((value) => Number.isFinite(value) && value > 0);
|
| 1635 |
+
const compactPhysicalScreen =
|
| 1636 |
+
screenDimensions.length > 0 &&
|
| 1637 |
+
Math.min(...screenDimensions) <= PHONE_SCREEN_MAX_CSS_PX;
|
| 1638 |
+
|
| 1639 |
+
return (
|
| 1640 |
+
responsiveMatch ||
|
| 1641 |
+
mobileClientHint ||
|
| 1642 |
+
(coarseTouch && compactPhysicalScreen)
|
| 1643 |
+
);
|
| 1644 |
}
|
| 1645 |
|
| 1646 |
function syncPhoneLayout() {
|
frontend/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
<meta charset="utf-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
| 6 |
<title>Web Continuator</title>
|
| 7 |
-
<link rel="stylesheet" href="/assets/styles.css?v=20260729-
|
| 8 |
</head>
|
| 9 |
<body>
|
| 10 |
<div class="page-aura"></div>
|
|
@@ -1196,6 +1196,6 @@
|
|
| 1196 |
</section>
|
| 1197 |
</main>
|
| 1198 |
|
| 1199 |
-
<script type="module" src="/assets/app.js?v=20260729-
|
| 1200 |
</body>
|
| 1201 |
</html>
|
|
|
|
| 4 |
<meta charset="utf-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
| 6 |
<title>Web Continuator</title>
|
| 7 |
+
<link rel="stylesheet" href="/assets/styles.css?v=20260729-phone3" />
|
| 8 |
</head>
|
| 9 |
<body>
|
| 10 |
<div class="page-aura"></div>
|
|
|
|
| 1196 |
</section>
|
| 1197 |
</main>
|
| 1198 |
|
| 1199 |
+
<script type="module" src="/assets/app.js?v=20260729-phone3"></script>
|
| 1200 |
</body>
|
| 1201 |
</html>
|