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
+1 -1
View File
@@ -96,7 +96,7 @@ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IoT guitar effect pedal for Raspberry Pi"
set(CPACK_DEBIAN_PACKAGE_SECTION sound)
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "lv2-dev, authbind, curl, gpg, alsa-base| pipewire, alsa-utils" )
set(CPACK_DEBIAN_PACKAGE_DEPENDS "lv2-dev, ffmpeg, authbind, curl, gpg, alsa-base| pipewire, alsa-utils" )
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE})
set(CPACK_PACKAGING_INSTALL_PREFIX /usr)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
+1 -1
View File
@@ -29,7 +29,7 @@
let galleryFrame = 0;
let calculateWidth = function () {
width = Math.min(maxWidth, window.innerWidth * 0.8);
width = Math.min(maxWidth, document.documentElement.clientWidth * 0.8);
height = width * aspectY / aspectX;
frameWidth = width + borderWidth * 2;
frameHeight = height + borderWidth * 2;
+1 -1
View File
@@ -34,7 +34,7 @@
let galleryFrame = 0;
let calculateWidth = function () {
width = Math.min(maxWidth, window.innerWidth * 0.8);
width = Math.min(maxWidth, document.documentElement.clientWidth * 0.8);
height = width * aspectY / aspectX;
frameWidth = width + borderWidth * 2;
frameHeight = height + borderWidth * 2;
+17 -17
View File
@@ -82,27 +82,27 @@ static bool isJackServiceRunning()
return std::filesystem::exists(path);
}
#if ENABLE_BACKTRACE
void segvHandler(int sig)
{
void *array[10];
#if 0 && ENABLE_BACKTRACE
// void segvHandler(int sig)
// {
// void *array[10];
// Get void*'s for all entries on the stack
size_t size;
size = backtrace(array, 10);
// // Get void*'s for all entries on the stack
// size_t size;
// size = backtrace(array, 10);
// Print out all the frames to stderr
const char *message = "Error: SEGV signal received.\n";
auto _ = write(STDERR_FILENO, message, strlen(message));
// // Print out all the frames to stderr
// const char *message = "Error: SEGV signal received.\n";
// auto _ = write(STDERR_FILENO, message, strlen(message));
backtrace_symbols_fd(array + 2, size - 2, STDERR_FILENO);
_exit(EXIT_FAILURE);
}
// backtrace_symbols_fd(array + 2, size - 2, STDERR_FILENO);
// _exit(EXIT_FAILURE);
// }
static void EnableBacktrace()
{
signal(SIGSEGV, segvHandler);
}
// static void EnableBacktrace()
// {
// signal(SIGSEGV, segvHandler);
// }
#endif
static bool TryGetLogLevel(const std::string &strLogLevel, LogLevel *result)
+3 -18
View File
@@ -1,22 +1,10 @@
Persist and reconnect IP addresses in client.
Zeroconv crash assert. /var/pipedal/audio_uploads/ReverbImpulseFiles/
Magic zoom.
request cacheing not working.
Investigate if ((keyCode == KeyEvent.KEYCODE_BACK))
MOD ir uses some scheme to limit the minimum buffer size, which is not implemented in Pipedal.
MOD ir layout issues.
MOD gui control should disable, not disappear.
MOD ir font (cooper-hewitt)
detect self-set control values to prevent weird jitter in mod ui levels.
ZAMEq2 Low control not working.
Modgui view should be persistent/per-plugin
Vu Meters, move rendering to background images, in order to reduce layout overhead.
@@ -26,9 +14,6 @@ Remove FullScreenIME in PluginControlView.tsx
Exactly one underrun per seek in Toob Player
Test autohotspot detection.
Ellipsis on plugin Title
check filetime conversion in gcc 12.2! (missing c++ 20 time conversion functions)
AudioFiles.cpp fileTimeToInt64
+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)
{