François Pachet commited on
Commit
f2beb6f
·
1 Parent(s): ebc2684

Improve Android phone detection

Browse files
Files changed (3) hide show
  1. README.md +10 -4
  2. frontend/app.js +28 -1
  3. 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. The phone surface contains only the virtual keyboard, a
89
- small live-status message, and the captured/generated piano rolls. Configuration,
90
- accounts, memory inspection, hardware MIDI, and device routing remain available
91
- in the unchanged desktop/tablet layout.
 
 
 
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
- return Boolean(window.matchMedia?.(PHONE_LAYOUT_MEDIA_QUERY).matches);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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-phone2" />
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-phone2"></script>
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>