Android Cilent Layout Issues

This commit is contained in:
Robin E. R. Davies
2025-07-14 18:13:09 -04:00
parent 890368352f
commit 818a08824c
24 changed files with 195 additions and 175 deletions
+108 -87
View File
@@ -1,112 +1,133 @@
<!doctype html>
<html lang="en">
<head>
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-visual" />
<meta name="theme-color" content="#000000" />
<meta name="color-scheme" content="dark light"/> <!-- uses media queries in web views. -->
<meta name="color-scheme" content="dark light" /> <!-- uses media queries in web views. -->
<meta name="description" content="PiPedal Guitar Stomp Box for Raspberry Pi" />
<link rel="stylesheet" href="/css/roboto.css" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="stylesheet" href="/css/modGui.css" />
<style>
BODY {
background: #D0D0D0;
}
BODY {
background: #D0D0D0;
}
</style>
<style id="bgStyle">
BODY {
background: #333; overscroll-behavior: "none"
}
BODY {
background: #333;
overscroll-behavior: none;
}
</style>
<script>
const androidHosted = !!(window.AndroidHost);
var colorScheme = localStorage.getItem("colorScheme");
if (androidHosted)
{
var hostColorScheme = window.AndroidHost.getThemePreference();
switch (hostColorScheme)
{
case 0:
colorScheme = "Light";
break;
case 1:
colorScheme = "Dark";
break;
case 2:
{
// use the host's interpretation of the current system night mode.
colorScheme = window.AndroidHost.isDarkTheme() ? "Dark": "Light";
const androidHosted = !!(window.AndroidHost);
var colorScheme = localStorage.getItem("colorScheme");
if (androidHosted) {
var hostColorScheme = window.AndroidHost.getThemePreference();
switch (hostColorScheme) {
case 0:
colorScheme = "Light";
break;
case 1:
colorScheme = "Dark";
break;
case 2:
{
// use the host's interpretation of the current system night mode.
colorScheme = window.AndroidHost.isDarkTheme() ? "Dark" : "Light";
}
break;
}
break;
}
}
if (!colorScheme)
{
colorScheme = "Dark";
}
var darkMode = false;
var useSystem = false;
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
switch (colorScheme) {
case null:
default:
darkMode = false;
break;
case "Light":
darkMode = false;
break;
case "Dark":
darkMode = true;
break;
case "System":
useSystem = true;
break;
}
if (useSystem) {
darkMode = prefersDark;
}
if (!darkMode) {
let bgStyle = document.getElementById("bgStyle");
if (bgStyle) {
// disable the style block.
bgStyle.setAttribute('media', "max-width: 1px");
}
}
function removeHashOnLoad() {
if (window.location.hash) {
// Store the hash value (without the '#' symbol)
var hash = window.location.hash.substring(1);
// Replace the current URL without the hash
var newUrl = window.location.href.replace(window.location.hash, '');
// Use HTML5 history API to change the URL without reloading the page
history.replaceState(null, document.title, newUrl);
if (!colorScheme) {
colorScheme = "Dark";
}
var darkMode = false;
var useSystem = false;
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
switch (colorScheme) {
case null:
default:
darkMode = false;
break;
case "Light":
darkMode = false;
break;
case "Dark":
darkMode = true;
break;
case "System":
useSystem = true;
break;
}
if (useSystem) {
darkMode = prefersDark;
}
if (!darkMode) {
let bgStyle = document.getElementById("bgStyle");
if (bgStyle) {
// disable the style block.
bgStyle.setAttribute('media', "max-width: 1px");
}
}
function removeHashOnLoad() {
if (window.location.hash) {
// Store the hash value (without the '#' symbol)
var hash = window.location.hash.substring(1);
// Replace the current URL without the hash
var newUrl = window.location.href.replace(window.location.hash, '');
// Use HTML5 history API to change the URL without reloading the page
history.replaceState(null, document.title, newUrl);
}
}
// Run the function when the window loads
window.addEventListener('load', removeHashOnLoad);
function getFocusedElementBounds() {
let focusedElement = document.activeElement;
if (focusedElement && focusedElement !== document.body) {
let rect = focusedElement.getBoundingClientRect();
return {
top: rect.top,
left: rect.left,
right: rect.right,
bottom: rect.bottom,
windowWidth: window.innerWidth,
windowHeight: window.innerHeight,
};
}
return null;
}
}
// Run the function when the window loads
window.addEventListener('load', removeHashOnLoad);
</script>
<title>PiPedal</title>
</head>
<body>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</body>
</html>
+1
View File
@@ -40,6 +40,7 @@
}
.mod-pedal {
touch-action: none;
}
.mod-pedal .mod-light {
+6 -2
View File
@@ -113,6 +113,7 @@ const AutoZoom = withStyles(
buttonPadding: number
): Rect {
console.log("Zoom: " + clientRect.toString() + " content: " + contentWidth + "x" + contentHeight + " buttonPadding: " + buttonPadding);
let rightButtonZoom = Math.min((clientRect.width - buttonPadding) / contentWidth, clientRect.height / contentHeight);
let topButtonZoom = Math.min((clientRect.width - buttonPadding) / contentWidth, (clientRect.height - buttonPadding) / contentHeight);
@@ -302,12 +303,13 @@ const AutoZoom = withStyles(
render() {
const classes = withStyles.getClasses(this.props);
void classes; // suppress unused variable warning
const landscape = this.state.screenWidth > this.state.screenHeight;
return (<div style={{ overflow: "hidden", height: "100%", width: "100%" }} ref={(ref) => { this.setNormalRef(ref); }}>
<div style={{
display: "inline-block",
position: "absolute",
visibility: this.props.contentReady ? "visible" : "hidden",
position: "relative",
}}>
{!this.props.showZoomed && this.props.children}
</div>
@@ -349,7 +351,9 @@ const AutoZoom = withStyles(
<IconButtonEx tooltip="Exit fullscreen"
style={{
position: "absolute", right: 16, top: 16, zIndex: 1104,
position: "absolute",
right: landscape? 80: 16, // avoid potential cutout in landscape mode
top: 16, zIndex: 1104,
}}
onClick={(e) => {
+1 -1
View File
@@ -246,7 +246,7 @@ export default withStyles(
this.requestScroll = true;
}
getFullScreen() {
return window.innerWidth < 450 || window.innerHeight < 450;
return document.documentElement.clientWidth < 450 || document.documentElement.clientHeight < 450;
}
hProgressTimeout: number | null = null;
+4 -4
View File
@@ -99,14 +99,14 @@ const FullScreenIME =
// because we can't determine the initial window heigth anymore.
if (this.currentWidth === undefined)
{
this.currentWidth = window.innerWidth;
this.currentWidth = document.documentElement.clientWidth;
}
if (this.currentWidth !== window.innerWidth)
if (this.currentWidth !== document.documentElement.clientWidth)
{
this.validateInput(true);
}
// eslint-disable-next-line no-restricted-globals
if (window.innerHeight >= this.props.initialHeight) {
if (document.documentElement.clientHeight >= this.props.initialHeight) {
this.validateInput(true);
}
}
@@ -194,7 +194,7 @@ const FullScreenIME =
this.currentWidth = undefined;
return (<div/>);
}
this.currentWidth = window.innerWidth;
this.currentWidth = document.documentElement.clientWidth;
this.uiControl = control;
+7 -7
View File
@@ -209,10 +209,10 @@ export const LoadPluginDialog =
search_string: "",
search_collapsed: true,
filterType: filterType_,
client_width: window.innerWidth,
client_height: window.innerHeight,
grid_cell_width: this.getCellWidth(window.innerWidth),
grid_cell_columns: this.getCellColumns(window.innerWidth),
client_width: document.documentElement.clientWidth,
client_height: document.documentElement.clientHeight,
grid_cell_width: this.getCellWidth(document.documentElement.clientWidth),
grid_cell_columns: this.getCellColumns(document.documentElement.clientWidth),
minimumItemWidth: props.minimumItemWidth ? props.minimumItemWidth : 220,
favoritesList: this.model.favorites.get(),
uiPlugins: this.model.ui_plugins.get()
@@ -276,9 +276,9 @@ export const LoadPluginDialog =
updateWindowSize() {
this.setState({
client_width: window.innerWidth,
client_height: window.innerHeight,
grid_cell_width: this.getCellWidth(window.innerWidth),
client_width: document.documentElement.clientWidth,
client_height: document.documentElement.clientHeight,
grid_cell_width: this.getCellWidth(document.documentElement.clientWidth),
grid_cell_columns: this.getCellColumns(window.innerWidth)
});
}
+9 -9
View File
@@ -82,7 +82,7 @@ const styles = ({ palette }: Theme) => {
}),
pedalboardScroll: css({
position: "relative", width: "100%",
flex: "0 0 auto", overflow: "auto", maxHeight: 220
flex: "0 0 auto", overflow: "auto", maxHeight: 220,
}),
pedalboardScrollSmall: css({
position: "relative", width: "100%",
@@ -100,7 +100,7 @@ const styles = ({ palette }: Theme) => {
flex: "0 0 64px", width: "100%", paddingLeft: 24, paddingRight: 16, paddingBottom: 16
}),
controlContent: css({
flex: "1 1 auto", width: "100%", overflowY: "hidden", minHeight: 300
flex: "1 1 auto", width: "100%", overflowY: "hidden", minHeight: 185
}),
controlContentSmall: css({
flex: "0 0 162px", width: "100%", height: 162, overflowY: "hidden",
@@ -145,7 +145,7 @@ export const MainPage =
model: PiPedalModel;
getSplitToolbar() {
return this.windowSize.width < SPLIT_CONTROLBAR_THRESHHOLD;
return this.windowSize.width < SPLIT_CONTROLBAR_THRESHHOLD && this.windowSize.height >= HORIZONTAL_CONTROL_SCROLL_HEIGHT_BREAK;
}
getDisplayAuthor() {
if (this.getSplitToolbar()) {
@@ -621,12 +621,12 @@ export const MainPage =
<div className={classes.frame}>
<div id="pedalboardScroll" className={horizontalScrollLayout ? classes.pedalboardScrollSmall : classes.pedalboardScroll}
style={{ maxHeight: horizontalScrollLayout ? undefined : this.state.screenHeight / 2 }}>
<PedalboardView key={pluginUri} selectedId={this.state.selectedPedal}
enableStructureEditing={this.props.enableStructureEditing}
onSelectionChanged={this.onSelectionChanged}
onDoubleClick={this.onPedalDoubleClick}
hasTinyToolBar={this.props.hasTinyToolBar}
/>
<PedalboardView key={pluginUri} selectedId={this.state.selectedPedal}
enableStructureEditing={this.props.enableStructureEditing}
onSelectionChanged={this.onSelectionChanged}
onDoubleClick={this.onPedalDoubleClick}
hasTinyToolBar={this.props.hasTinyToolBar}
/>
</div>
<div className={classes.separator} />
<div className={classes.controlToolBar}>
+3 -3
View File
@@ -58,13 +58,13 @@ export enum MidiControlType {
}
export function getMidiControlType(uiPlugin: UiPlugin | undefined, symbol: string): MidiControlType {
if (symbol === "__bypass") {
return MidiControlType.Toggle;
}
if (!uiPlugin) return MidiControlType.None;
let port = uiPlugin.getControl(symbol);
if (!port) return MidiControlType.None;
if (symbol === "__bypass") {
return MidiControlType.Toggle;
}
if (!port) return MidiControlType.None;
+9
View File
@@ -609,6 +609,13 @@ export class PiPedalModel //implements PiPedalModel
let message = header.message;
if (message === "onControlChanged") {
let controlChangedBody = body as ControlChangedBody;
if (body.clientId !== this.clientId) {
this.lastControlMessageWasSentbyMe = false;
}
if (this.lastControlMessageWasSentbyMe) {
return; // shortcut!
}
this._setPedalboardControlValue(
controlChangedBody.instanceId,
controlChangedBody.symbol,
@@ -1529,6 +1536,7 @@ export class PiPedalModel //implements PiPedalModel
}
}
private lastControlMessageWasSentbyMe = false;
private _setPedalboardControlValue(instanceId: number, key: string, value: number, notifyServer: boolean): void {
let pedalboard = this.pedalboard.get();
@@ -1547,6 +1555,7 @@ export class PiPedalModel //implements PiPedalModel
if (changed) {
if (notifyServer) {
this.lastControlMessageWasSentbyMe = true;
this._setServerControl("setControl", instanceId, key, value);
}
this.setModelPedalboard(newPedalboard);
+4 -4
View File
@@ -146,9 +146,9 @@ const styles = (theme: Theme) => createStyles({
flexDirection: "row",
flexWrap: "nowrap",
paddingTop: "0px",
paddingBottom: "0px",
paddingBottom: "96px",
overflowX: "hidden",
overflowY: "auto"
overflowY: "auto",
}),
vuMeterL: css({
position: "absolute",
@@ -175,7 +175,7 @@ const styles = (theme: Theme) => createStyles({
right: 0, top: 0,
paddingRight: 6,
paddingLeft: 12,
paddingBottom: 12, // cover bottom line of a portgroup in landscape.
paddingBottom: 13, // cover bottom line of a portgroup in landscape.
background: theme.mainBackground,
zIndex: 3
@@ -448,7 +448,7 @@ const PluginControlView =
imeUiControl: uiControl,
imeValue: value,
imeCaption: uiControl.name,
imeInitialHeight: window.innerHeight
imeInitialHeight: document.documentElement.clientHeight
});
}
@@ -24,8 +24,8 @@ class ResizeResponsiveComponent<PROPS={},STATE={},S=any> extends React.Component
constructor(props: PROPS) {
super(props);
this.handleWindowResize = this.handleWindowResize.bind(this);
this.windowSize.width = window.innerWidth;
this.windowSize.height = window.innerHeight;
this.windowSize.width = document.documentElement.clientWidth;
this.windowSize.height = document.documentElement.clientHeight;
}
windowSize: {width: number,height:number} = {width: 1280, height: 1024};
@@ -34,8 +34,8 @@ class ResizeResponsiveComponent<PROPS={},STATE={},S=any> extends React.Component
}
handleWindowResize() {
let width_ = window.innerWidth;
let height_ = window.innerHeight;
let width_ = document.documentElement.clientWidth;
let height_ = document.documentElement.clientHeight;
if (width_ !== this.windowSize.width || height_ !== this.windowSize.height)
{
this.windowSize = {width: width_, height: height_};
@@ -49,8 +49,8 @@ class ResizeResponsiveComponent<PROPS={},STATE={},S=any> extends React.Component
componentDidMount() {
window.addEventListener('resize', this.handleWindowResize);
let width_ = window.innerWidth;
let height_ = window.innerHeight;
let width_ = document.documentElement.clientWidth;
let height_ = document.documentElement.clientHeight;
this.windowSize = {width: width_, height: height_};
this.onWindowSizeChanged(this.windowSize.width,this.windowSize.height);
}
+1 -1
View File
@@ -89,7 +89,7 @@ export default class SnapshotDialog extends ResizeResponsiveComponent<SnapshotDi
}
getFullScreen() {
return window.innerHeight < 450 || window.innerWidth < 450;
return document.documentElement.clientHeight < 450 || document.documentElement.clientWidth < 450;
}
onWindowSizeChanged(width: number, height: number): void {
this.setState(
+4 -4
View File
@@ -123,17 +123,17 @@ export default class SnapshotPanel extends ResizeResponsiveComponent<SnapshotPan
getCollapseButtons() {
if (this.getPortraitOrientation())
{
return window.innerWidth < 550;
return document.documentElement.clientWidth < 550;
} else {
return window.innerWidth < 800;
return document.documentElement.clientWidth < 800;
}
}
getPortraitOrientation() {
return window.innerWidth * 2 < window.innerHeight * 3;
return document.documentElement.clientWidth * 2 < document.documentElement.clientHeight * 3;
}
getLargeText() {
return window.innerHeight > 700 && window.innerWidth > 1000;
return document.documentElement.clientHeight > 700 && document.documentElement.clientWidth > 1000;
}
onSaveSnapshot(index: number) {
let snapshot = this.state.snapshots[index];
@@ -64,7 +64,7 @@ export default class SnapshotPropertiesDialog extends ResizeResponsiveComponent<
this.state = this.stateFromProps();
}
getCompactVertical() {
return window.innerHeight < 450;
return document.documentElement.clientHeight < 450;
}
stateFromProps() {
let color = this.props.color;
+1 -1
View File
@@ -52,7 +52,7 @@ const TextFieldEx = withStyles(styles, { withTheme: true })(
}
private getUseImeMask() {
return this.state.androidHosted && window.innerHeight < 4500;
return this.state.androidHosted && document.documentElement.clientHeight < 4500;
}
private originalInputHref: HTMLInputElement | undefined = undefined;
+2 -2
View File
@@ -25,8 +25,8 @@ import { useState, useEffect } from 'react';
const getSize = () => {
return {
width: window.innerWidth,
height: window.innerHeight,
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
};
};
+3 -3
View File
@@ -39,13 +39,13 @@ export interface ControlEntry {
const Utility = class {
static isLandscape(): boolean {
return window.innerWidth > window.innerHeight;
return document.documentElement.clientWidth > document.documentElement.clientHeight;
}
static needsZoomedControls(): boolean {
if (!this.isLandscape()) return false;
if (window.innerHeight > 500) return false;
if (window.innerHeight > 300) return true;
if (document.documentElement.clientHeight > 500) return false;
if (document.documentElement.clientHeight > 300) return true;
return (('ontouchstart' in window) &&
((navigator.maxTouchPoints??0) > 0) );
}
+1 -1
View File
@@ -51,7 +51,7 @@ export default class VirtualKeyboardHandler
enabled = false;
}
this.enabled = enabled;
this.originalPosition = new Rectangle(0,0, window.innerWidth,window.innerHeight)
this.originalPosition = new Rectangle(0,0, document.documentElement.clientWidth,document.documentElement.clientHeight)
}
private handleVisualViewportResize(event: Event): void {
const viewport = event.target as VisualViewport;
+1 -1
View File
@@ -15,7 +15,7 @@ export function getValidWindowScales(): number[]
return [1.0];
}
let result: number[] = [];
let minDimension = Math.min(window.innerHeight,window.innerWidth);
let minDimension = Math.min(document.documentElement.clientHeight,document.documentElement.clientWidth);
for (let validScale of validScales)
{