Auto-reconnect if camera already found; catch all errors

This commit is contained in:
Ingvar Stepanyan
2021-07-19 17:57:50 +00:00
parent 826aca5b9d
commit e62ab51f4c

73
ui.js
View File

@@ -4,11 +4,14 @@ import initModule from './libapi.mjs';
/** @typedef {InstanceType<import('./libapi.mjs').Module['Context']>} Context */
/** @typedef {import('./libapi.mjs').Config} Config */
if (new URLSearchParams(location.search).has('debug')) {
let isDebug = new URLSearchParams(location.search).has('debug');
if (isDebug) {
// @ts-ignore
await import('preact/debug');
}
/** This function should be called once user has selected the camera and other operations can begin. */
let prepareContext;
/** Schedules an exclusive async operation on the global context. */
@@ -246,21 +249,60 @@ class CaptureButton extends Component {
}
}
/** @typedef {{ type: 'Initial' } | { type: 'Status', message: string } | { type: 'Config', config: Config }} AppState */
/** @typedef {{ type: 'CameraPicker' } | { type: 'Status', message: string } | { type: 'Config', config: Config }} AppState */
const DEVICE_CLASS = 6; // PTP
const DEVICE_SUBCLASS = 1; // MTP
/** @extends Component<null, AppState> */
class App extends Component {
state = /** @type {AppState} */ ({ type: 'Initial' });
state = /** @type {AppState} */ ({
type: 'Status',
message: 'Looking for cameras...'
});
constructor(...args) {
super(...args);
// @ts-ignore
navigator.usb.getDevices().then(devices => {
for (let dev of devices) {
for (let conf of dev.configurations) {
for (let intf of conf.interfaces) {
for (let alt of intf.alternates) {
if (
alt.interfaceClass === DEVICE_CLASS &&
alt.interfaceSubclass === DEVICE_SUBCLASS
) {
return this.connectToCamera();
}
}
}
}
}
this.setState({ type: 'CameraPicker' });
});
window.onerror = message => {
this.setState({
type: 'Status',
message: `${message}`
});
};
}
selectDevice = async () => {
// @ts-ignore
await navigator.usb.requestDevice({
filters: [
{
classCode: 6, // PTP
subclassCode: 1 // MTP
classCode: DEVICE_CLASS,
subclassCode: DEVICE_SUBCLASS
}
]
});
this.connectToCamera();
};
connectToCamera() {
prepareContext();
this.setState({ type: 'Status', message: 'Connecting...' });
(async () => {
@@ -269,25 +311,22 @@ class App extends Component {
await new Promise(resolve => setTimeout(resolve, 100));
}
})();
};
}
async refreshConfig() {
try {
this.setState({
type: 'Config',
config: await scheduleOp(context => context.configToJS())
});
} catch (e) {
this.setState({
type: 'Status',
message: String(e)
});
let config = await scheduleOp(context => context.configToJS());
if (!isDebug) {
delete config.children.other;
}
this.setState({
type: 'Config',
config
});
}
render(/** @type {App['props']} */ props, /** @type {App['state']} */ state) {
switch (state.type) {
case 'Initial':
case 'CameraPicker':
return h(
'div',
{ class: 'center-parent' },