Model/IR Select dialog for large downloads
This commit is contained in:
Vendored
+1
-1
@@ -175,7 +175,7 @@
|
|||||||
"cSpell.ignoreWords": [
|
"cSpell.ignoreWords": [
|
||||||
"nammodel"
|
"nammodel"
|
||||||
],
|
],
|
||||||
"cSpell.enabled": true,
|
"cSpell.enabled": false,
|
||||||
|
|
||||||
// Disable all automatic completion suggestions - only show when Ctrl+Space is pressed
|
// Disable all automatic completion suggestions - only show when Ctrl+Space is pressed
|
||||||
"editor.quickSuggestions": {
|
"editor.quickSuggestions": {
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ static std::map<std::string, std::string> gearEnumValues =
|
|||||||
{"full-rig", "Full rig"},
|
{"full-rig", "Full rig"},
|
||||||
{"pedal", "Pedal"},
|
{"pedal", "Pedal"},
|
||||||
{"outboard", "Outboard"},
|
{"outboard", "Outboard"},
|
||||||
{"ir", "I/R"}};
|
{"ir", "IR"}};
|
||||||
|
|
||||||
static std::string mdGear(const std::string &gear)
|
static std::string mdGear(const std::string &gear)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -713,7 +713,7 @@ static std::map<std::string, std::string> gearEnumValues =
|
|||||||
{"full-rig", "Full rig"},
|
{"full-rig", "Full rig"},
|
||||||
{"pedal", "Pedal"},
|
{"pedal", "Pedal"},
|
||||||
{"outboard", "Outboard"},
|
{"outboard", "Outboard"},
|
||||||
{"ir", "I/R"}};
|
{"ir", "IR"}};
|
||||||
|
|
||||||
static std::string mdGear(const std::string &gear)
|
static std::string mdGear(const std::string &gear)
|
||||||
{
|
{
|
||||||
@@ -926,7 +926,7 @@ static std::string mdLicense(const std::string &license)
|
|||||||
static std::map<std::string, std::string> platformEnumValues =
|
static std::map<std::string, std::string> platformEnumValues =
|
||||||
{
|
{
|
||||||
{"nam", "NAM"},
|
{"nam", "NAM"},
|
||||||
{"ir", "I/R"},
|
{"ir", "IR"},
|
||||||
{"aida-x", "Aida X"},
|
{"aida-x", "Aida X"},
|
||||||
{"aa-snapshot", "aa-snapshot"},
|
{"aa-snapshot", "aa-snapshot"},
|
||||||
{"proteus", "Proteus"}};
|
{"proteus", "Proteus"}};
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ namespace
|
|||||||
{"full-rig", "Full rig"},
|
{"full-rig", "Full rig"},
|
||||||
{"pedal", "Pedal"},
|
{"pedal", "Pedal"},
|
||||||
{"outboard", "Outboard"},
|
{"outboard", "Outboard"},
|
||||||
{"ir", "I/R"}};
|
{"ir", "IR"}};
|
||||||
|
|
||||||
static std::string mdGear(const std::string &gear)
|
static std::string mdGear(const std::string &gear)
|
||||||
{
|
{
|
||||||
@@ -356,7 +356,7 @@ namespace
|
|||||||
static std::map<std::string, std::string> platformEnumValues =
|
static std::map<std::string, std::string> platformEnumValues =
|
||||||
{
|
{
|
||||||
{"nam", "NAM"},
|
{"nam", "NAM"},
|
||||||
{"ir", "I/R"},
|
{"ir", "IR"},
|
||||||
{"aida-x", "Aida X"},
|
{"aida-x", "Aida X"},
|
||||||
{"aa-snapshot", "aa-snapshot"},
|
{"aa-snapshot", "aa-snapshot"},
|
||||||
{"proteus", "Proteus"}};
|
{"proteus", "Proteus"}};
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ add_custom_command(
|
|||||||
public/css/roboto.css
|
public/css/roboto.css
|
||||||
public/html/t3k_response.html
|
public/html/t3k_response.html
|
||||||
public/var/current_pedalboard.json
|
public/var/current_pedalboard.json
|
||||||
public/var/config.json.disabled
|
public/var/config.json
|
||||||
public/var/uiplugins.json
|
public/var/uiplugins.json
|
||||||
public/var/plugin_classes.json
|
public/var/plugin_classes.json
|
||||||
public/testTone300Popup.html
|
public/testTone300Popup.html
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
npm run dev -- --host 0.0.0.0 --host lothlorien.local
|
npm run dev -- --host 0.0.0.0
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ interface DialogExState {
|
|||||||
interface DialogExProps extends DialogProps {
|
interface DialogExProps extends DialogProps {
|
||||||
tag: string;
|
tag: string;
|
||||||
fullwidth?: boolean;
|
fullwidth?: boolean;
|
||||||
onEnterKey: () => void;
|
onEnterKey?: () => void;
|
||||||
dlgRef?: (instance: HTMLDivElement | null) => void;
|
dlgRef?: (instance: HTMLDivElement | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ import HomeIcon from '@mui/icons-material/Home';
|
|||||||
import FilePropertyDirectorySelectDialog from './FilePropertyDirectorySelectDialog';
|
import FilePropertyDirectorySelectDialog from './FilePropertyDirectorySelectDialog';
|
||||||
import { getAlbumArtUri, getTrackTitle } from './AudioFileMetadata';
|
import { getAlbumArtUri, getTrackTitle } from './AudioFileMetadata';
|
||||||
import Tone3000DownloadType from './Tone3000DownloadType';
|
import Tone3000DownloadType from './Tone3000DownloadType';
|
||||||
|
import { ModelSelectionDialog, ModelSelectionDialogParams } from './ModelSelectionDialog';
|
||||||
|
|
||||||
|
|
||||||
const ToobNamModelFileUrl = "http://two-play.com/plugins/toob-nam#modelFile";
|
const ToobNamModelFileUrl = "http://two-play.com/plugins/toob-nam#modelFile";
|
||||||
@@ -182,6 +183,7 @@ export interface FilePropertyDialogState {
|
|||||||
|
|
||||||
textFileName?: string;
|
textFileName?: string;
|
||||||
|
|
||||||
|
modelSelectionDialogParams?: ModelSelectionDialogParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface DragState {
|
interface DragState {
|
||||||
@@ -255,7 +257,8 @@ export default withStyles(
|
|||||||
multiSelect: false,
|
multiSelect: false,
|
||||||
selectedFiles: [],
|
selectedFiles: [],
|
||||||
openTone3000Help: false,
|
openTone3000Help: false,
|
||||||
openGuitarMlHelp: false
|
openGuitarMlHelp: false,
|
||||||
|
modelSelectionDialogParams: undefined,
|
||||||
};
|
};
|
||||||
this.requestScroll = true;
|
this.requestScroll = true;
|
||||||
}
|
}
|
||||||
@@ -588,8 +591,19 @@ export default withStyles(
|
|||||||
this.requestFiles(this.state.navDirectory)
|
this.requestFiles(this.state.navDirectory)
|
||||||
this.model.onTone3000DownloadCompleteEvent.addEventHandler(this.handleTone3000DownloadComplete);
|
this.model.onTone3000DownloadCompleteEvent.addEventHandler(this.handleTone3000DownloadComplete);
|
||||||
this.requestScroll = true;
|
this.requestScroll = true;
|
||||||
|
|
||||||
|
this.model.setT3kModelSelectionDialogListener({
|
||||||
|
onShowDialog: (modelSelectionDialogParams: ModelSelectionDialogParams) => {
|
||||||
|
this.setState({
|
||||||
|
modelSelectionDialogParams: modelSelectionDialogParams
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
this.model.setT3kModelSelectionDialogListener(undefined);
|
||||||
this.stopAutoScroll();
|
this.stopAutoScroll();
|
||||||
this.cancelProgressTimeout();
|
this.cancelProgressTimeout();
|
||||||
this.model.onTone3000DownloadCompleteEvent.removeEventHandler(this.handleTone3000DownloadComplete);
|
this.model.onTone3000DownloadCompleteEvent.removeEventHandler(this.handleTone3000DownloadComplete);
|
||||||
@@ -939,7 +953,8 @@ export default withStyles(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultPath(): string {
|
// yyy: depends on dialog type!!!
|
||||||
|
private getDefaultPath(): string {
|
||||||
try {
|
try {
|
||||||
let storage = window.localStorage;
|
let storage = window.localStorage;
|
||||||
let result = storage.getItem("fpDefaultPath");
|
let result = storage.getItem("fpDefaultPath");
|
||||||
@@ -1100,14 +1115,13 @@ export default withStyles(
|
|||||||
let downloadType: Tone3000DownloadType = Tone3000DownloadType.Nam;
|
let downloadType: Tone3000DownloadType = Tone3000DownloadType.Nam;
|
||||||
if (this.props.fileProperty.patchProperty === ToobNamModelFileUrl) {
|
if (this.props.fileProperty.patchProperty === ToobNamModelFileUrl) {
|
||||||
downloadType = Tone3000DownloadType.Nam;
|
downloadType = Tone3000DownloadType.Nam;
|
||||||
} else if (ToobCabIrFileUrls.includes(this.props.fileProperty.patchProperty))
|
} else if (ToobCabIrFileUrls.includes(this.props.fileProperty.patchProperty)) {
|
||||||
{
|
|
||||||
downloadType = Tone3000DownloadType.CabIr;
|
downloadType = Tone3000DownloadType.CabIr;
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unsupported file property for Tone3000 dialog");
|
throw new Error("Unsupported file property for Tone3000 dialog");
|
||||||
}
|
}
|
||||||
this.model.showTone3000DownloadPopup(
|
this.model.showTone3000DownloadPopup(
|
||||||
downloadType,
|
downloadType,
|
||||||
this.state.currentDirectory);
|
this.state.currentDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1147,14 +1161,14 @@ export default withStyles(
|
|||||||
// }
|
// }
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const isTracksDirectory = this.isTracksDirectory();
|
const isTracksDirectory = this.isTracksDirectory();
|
||||||
const isToobNamModelFile = this.props.fileProperty.patchProperty === ToobNamModelFileUrl;
|
const isToobNamModelFile = this.props.fileProperty.patchProperty === ToobNamModelFileUrl;
|
||||||
const isToobCabIrFile = ToobCabIrFileUrls.includes(this.props.fileProperty.patchProperty);
|
const isToobCabIrFile = ToobCabIrFileUrls.includes(this.props.fileProperty.patchProperty);
|
||||||
const isToobMLModelFile = this.props.fileProperty.patchProperty === ToobMlModelFileUrl;
|
const isToobMLModelFile = this.props.fileProperty.patchProperty === ToobMlModelFileUrl;
|
||||||
|
|
||||||
const classes = withStyles.getClasses(this.props);
|
const classes = withStyles.getClasses(this.props);
|
||||||
@@ -1726,6 +1740,16 @@ export default withStyles(
|
|||||||
|
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
{this.state.modelSelectionDialogParams && (
|
||||||
|
<ModelSelectionDialog open={true}
|
||||||
|
params={
|
||||||
|
this.state.modelSelectionDialogParams
|
||||||
|
}
|
||||||
|
onClose={
|
||||||
|
() => { this.setState({ modelSelectionDialogParams: undefined }); }
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<OkCancelDialog open={this.state.openConfirmDeleteDialog}
|
<OkCancelDialog open={this.state.openConfirmDeleteDialog}
|
||||||
|
|
||||||
text={
|
text={
|
||||||
@@ -1826,7 +1850,8 @@ export default withStyles(
|
|||||||
title={pathFileNameOnly(this.state.textFileName)}
|
title={pathFileNameOnly(this.state.textFileName)}
|
||||||
fileName={this.state.textFileName} onClose={() => this.setState({ textFileName: undefined })}
|
fileName={this.state.textFileName} onClose={() => this.setState({ textFileName: undefined })}
|
||||||
onT3kLinkClick={(href) => {
|
onT3kLinkClick={(href) => {
|
||||||
return this.handleT3kLinkClick(href); }
|
return this.handleT3kLinkClick(href);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -1853,7 +1878,7 @@ export default withStyles(
|
|||||||
// open pdf in new tab
|
// open pdf in new tab
|
||||||
this.model.displayMediaFile(fileName);
|
this.model.displayMediaFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShowTextFile(fileName: string) {
|
handleShowTextFile(fileName: string) {
|
||||||
this.setState({ textFileName: fileName });
|
this.setState({ textFileName: fileName });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 Robin E. R. Davies
|
||||||
|
* All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import Checkbox from "@mui/material/Checkbox";
|
||||||
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
|
import Paper from "@mui/material/Paper";
|
||||||
|
import Table from "@mui/material/Table";
|
||||||
|
import TableBody from "@mui/material/TableBody";
|
||||||
|
import TableCell from "@mui/material/TableCell";
|
||||||
|
import TableContainer from "@mui/material/TableContainer";
|
||||||
|
import TableHead from "@mui/material/TableHead";
|
||||||
|
import TableRow from "@mui/material/TableRow";
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
|
||||||
|
import DialogEx from "./DialogEx";
|
||||||
|
import { Model } from "./t3k/types.ts";
|
||||||
|
import Tone3000DownloadType from "./Tone3000DownloadType.tsx";
|
||||||
|
import Divider from "@mui/material/Divider";
|
||||||
|
import Toolbar from "@mui/material/Toolbar";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import IconButtonEx from "./IconButtonEx.tsx";
|
||||||
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
|
import DialogTitle from "@mui/material/DialogTitle";
|
||||||
|
import useWindowSize from "./UseWindowSize.tsx";
|
||||||
|
|
||||||
|
interface ModelSelection {
|
||||||
|
selected: boolean;
|
||||||
|
model: Model;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModelSelectionDialogParams {
|
||||||
|
downloadType: Tone3000DownloadType;
|
||||||
|
toneName: string;
|
||||||
|
models: Model[];
|
||||||
|
onCancel: () => void;
|
||||||
|
onModelsSelected: (selectedModels: Model[]) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ModelSelectionDialog(
|
||||||
|
props: {
|
||||||
|
open: boolean;
|
||||||
|
params: ModelSelectionDialogParams;
|
||||||
|
onClose: () => void;
|
||||||
|
}) {
|
||||||
|
|
||||||
|
const { models, toneName, onCancel, onModelsSelected } = props.params;
|
||||||
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
|
const [modelSelection, setModelSelection] = React.useState<ModelSelection[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setModelSelection(models.map((model) => ({
|
||||||
|
selected: false,
|
||||||
|
model,
|
||||||
|
})));
|
||||||
|
}, [models]);
|
||||||
|
|
||||||
|
const selectedCount = modelSelection.filter((selection) => selection.selected).length;
|
||||||
|
const allSelected = modelSelection.length > 0 && selectedCount === modelSelection.length;
|
||||||
|
const partiallySelected = selectedCount > 0 && selectedCount < modelSelection.length;
|
||||||
|
|
||||||
|
const toggleAll = () => {
|
||||||
|
setModelSelection((currentSelection) => {
|
||||||
|
const nextSelected = !allSelected;
|
||||||
|
return currentSelection.map((selection) => ({
|
||||||
|
...selection,
|
||||||
|
selected: nextSelected,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleModel = (modelId: number) => {
|
||||||
|
setModelSelection((currentSelection) => currentSelection.map((selection) => {
|
||||||
|
if (selection.model.id !== modelId) {
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...selection,
|
||||||
|
selected: !selection.selected,
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
onCancel();
|
||||||
|
props.onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOk = () => {
|
||||||
|
onModelsSelected(
|
||||||
|
modelSelection
|
||||||
|
.filter((selection) => selection.selected)
|
||||||
|
.map((selection) => selection.model)
|
||||||
|
);
|
||||||
|
props.onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
let title = props.params.downloadType === Tone3000DownloadType.Nam
|
||||||
|
? "Select Models" :
|
||||||
|
"Select IRs ";
|
||||||
|
|
||||||
|
let tableTitle =
|
||||||
|
"(" + selectedCount.toString() + " of " + models.length.toString() + " selected) - " + toneName
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DialogEx tag="selectModels" open={props.open} onClose={() => { /* Do nothing */ }}
|
||||||
|
fullWidth={true} maxWidth="md"
|
||||||
|
fullScreen={windowSize[0].width < 450}
|
||||||
|
|
||||||
|
|
||||||
|
>
|
||||||
|
<DialogTitle style={{
|
||||||
|
paddingBottom: 0,
|
||||||
|
marginBottom: 0, paddingTop: 0,
|
||||||
|
}} >
|
||||||
|
|
||||||
|
<Toolbar style={{ padding: 0 }}>
|
||||||
|
<IconButtonEx
|
||||||
|
tooltip="Back"
|
||||||
|
edge="start"
|
||||||
|
color="inherit"
|
||||||
|
aria-label="back"
|
||||||
|
style={{ opacity: 0.6 }}
|
||||||
|
onClick={() => { handleCancel(); }}
|
||||||
|
>
|
||||||
|
<ArrowBackIcon style={{ width: 24, height: 24 }} />
|
||||||
|
</IconButtonEx>
|
||||||
|
<Typography noWrap component="div" sx={{ flexGrow: 1 }}>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
</Toolbar>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent sx={{ marginLeft: 0, marginRight: 0, paddingLeft: 0, paddingRight: 0 }}>
|
||||||
|
<TableContainer component={Paper} variant="outlined" sx={{ backgroundColor: "transparent", border: "0px" }} >
|
||||||
|
<Table sx={{ backgroundColor: "transparent" }}>
|
||||||
|
<TableHead style={{ backgroundColor: "transparent" }}>
|
||||||
|
<TableRow sx={{ backgroundColor: "transparent" }} onClick={toggleAll}>
|
||||||
|
<TableCell padding="checkbox" sx={{ backgroundColor: "transparent" }}>
|
||||||
|
<Checkbox
|
||||||
|
checked={allSelected}
|
||||||
|
indeterminate={partiallySelected}
|
||||||
|
onChange={toggleAll}
|
||||||
|
sx={{marginLeft: 1}}
|
||||||
|
inputProps={{ 'aria-label': 'select all models' }}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell sx={{ backgroundColor: "transparent" }}>
|
||||||
|
<Typography noWrap variant="body1">{tableTitle}</Typography>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody style={{ backgroundColor: "transparent" }}>
|
||||||
|
{modelSelection.map((selection) => (
|
||||||
|
<TableRow
|
||||||
|
key={selection.model.id}
|
||||||
|
onClick={() => toggleModel(selection.model.id)}
|
||||||
|
sx={{ cursor: 'pointer', backgroundColor: 'transparent' }}
|
||||||
|
>
|
||||||
|
<TableCell padding="checkbox" sx={{ backgroundColor: "transparent", paddingLeft: 3, borderBottom: "0px" }}>
|
||||||
|
<Checkbox
|
||||||
|
checked={selection.selected}
|
||||||
|
onClick={(event) => { event.stopPropagation(); }}
|
||||||
|
onChange={() => toggleModel(selection.model.id)}
|
||||||
|
inputProps={{ 'aria-labelledby': `model-selection-${selection.model.id}` }}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell id={`model-selection-${selection.model.id}`} sx={{ backgroundColor: "transparent", borderBottom: "0px" }}>
|
||||||
|
<Typography noWrap variant="body2">
|
||||||
|
{selection.model.name}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</DialogContent>
|
||||||
|
<Divider />
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleCancel} variant="dialogSecondary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleOk} variant="dialogPrimary" disabled={selectedCount === 0}>
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</DialogEx>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -50,7 +50,8 @@ import { AlsaSequencerConfiguration, AlsaSequencerPortSelection } from './AlsaSe
|
|||||||
import { getDefaultModGuiPreference } from './ModGuiHost';
|
import { getDefaultModGuiPreference } from './ModGuiHost';
|
||||||
import ChannelRouterSettings from './ChannelRouterSettings';
|
import ChannelRouterSettings from './ChannelRouterSettings';
|
||||||
import Tone3000DownloadProgress from './Tone3000DownloadProgress';
|
import Tone3000DownloadProgress from './Tone3000DownloadProgress';
|
||||||
import { Tone } from './t3k/types';
|
import { Model, Tone } from './t3k/types';
|
||||||
|
import { ModelSelectionDialogParams } from './ModelSelectionDialog';
|
||||||
|
|
||||||
|
|
||||||
export enum State {
|
export enum State {
|
||||||
@@ -66,6 +67,11 @@ export enum State {
|
|||||||
HotspotChanging,
|
HotspotChanging,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface T3kModelSelectionDialogListener {
|
||||||
|
onShowDialog: (
|
||||||
|
modelSelectionDialogParams: ModelSelectionDialogParams
|
||||||
|
) => void;
|
||||||
|
};
|
||||||
export interface Tone3000PkceParams {
|
export interface Tone3000PkceParams {
|
||||||
publishableKey: string;
|
publishableKey: string;
|
||||||
redirectUrl: string;
|
redirectUrl: string;
|
||||||
@@ -708,19 +714,16 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async makeTone3000Pkce(redirectUrl: string) : Promise<Tone3000PkceParams>
|
async makeTone3000Pkce(redirectUrl: string): Promise<Tone3000PkceParams> {
|
||||||
{
|
if (this.webSocket === undefined) {
|
||||||
if (this.webSocket === undefined)
|
|
||||||
{
|
|
||||||
throw new Error("Server disconnected.");
|
throw new Error("Server disconnected.");
|
||||||
}
|
}
|
||||||
return await this.webSocket.request<Tone3000PkceParams>(
|
return await this.webSocket.request<Tone3000PkceParams>(
|
||||||
"makeTone3000Pkce", redirectUrl);
|
"makeTone3000Pkce", redirectUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
async sha256Base64url(intput: string) : Promise<string> {
|
async sha256Base64url(intput: string): Promise<string> {
|
||||||
if (this.webSocket === undefined)
|
if (this.webSocket === undefined) {
|
||||||
{
|
|
||||||
throw new Error("Server disconnected.");
|
throw new Error("Server disconnected.");
|
||||||
}
|
}
|
||||||
return this.webSocket.request<string>(
|
return this.webSocket.request<string>(
|
||||||
@@ -774,7 +777,7 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
showTone3000DownloadPopup(
|
showTone3000DownloadPopup(
|
||||||
downloadType: Tone3000DownloadType,
|
downloadType: Tone3000DownloadType,
|
||||||
downloadPath: string,
|
downloadPath: string,
|
||||||
options?: {
|
options?: {
|
||||||
userName?: string;
|
userName?: string;
|
||||||
}
|
}
|
||||||
): void {
|
): void {
|
||||||
@@ -1336,7 +1339,7 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
async writeTone3000Readme(
|
async writeTone3000Readme(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
tone: Tone,
|
tone: Tone,
|
||||||
thumbnailUrl: string
|
thumbnailUrl: string
|
||||||
|
|
||||||
@@ -3938,14 +3941,50 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
downloadType: Tone3000DownloadType
|
downloadType: Tone3000DownloadType
|
||||||
): void {
|
): void {
|
||||||
if (this.webSocket) {
|
if (this.webSocket) {
|
||||||
this.webSocket.send("DownloadModelsFromTone3000", {
|
this.webSocket.send("DownloadModelsFromTone3000", {
|
||||||
responseUri: responseUri,
|
responseUri: responseUri,
|
||||||
tone3000PckceParams: tone3000PckceParams,
|
tone3000PckceParams: tone3000PckceParams,
|
||||||
downloadPath: downloadPath,
|
downloadPath: downloadPath,
|
||||||
downloadType: downloadType === Tone3000DownloadType.Nam ? 0: 1
|
downloadType: downloadType === Tone3000DownloadType.Nam ? 0 : 1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private t3kModelSelectionDialogListener?: T3kModelSelectionDialogListener = undefined;
|
||||||
|
|
||||||
|
setT3kModelSelectionDialogListener(
|
||||||
|
listener: T3kModelSelectionDialogListener | undefined
|
||||||
|
) {
|
||||||
|
this.t3kModelSelectionDialogListener = listener;
|
||||||
|
}
|
||||||
|
showT3kModelSelectionDialog(
|
||||||
|
downloadType: Tone3000DownloadType,
|
||||||
|
toneName: string,
|
||||||
|
models: Model[],
|
||||||
|
onModelsSelected: (selectedModels: Model[]) => void,
|
||||||
|
onCancel: () => void
|
||||||
|
) {
|
||||||
|
if (!this.t3kModelSelectionDialogListener) {
|
||||||
|
onCancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.tone3000Downloading.set(false);
|
||||||
|
this.t3kModelSelectionDialogListener.onShowDialog(
|
||||||
|
{
|
||||||
|
downloadType: downloadType,
|
||||||
|
toneName: toneName,
|
||||||
|
models: models,
|
||||||
|
onModelsSelected: (selectedModels: Model[]) => {
|
||||||
|
this.tone3000Downloading.set(true);
|
||||||
|
onModelsSelected(selectedModels);
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
this.tone3000Downloading.set(false);
|
||||||
|
onCancel();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -211,6 +211,28 @@ export class Tone3000DownloadHandler {
|
|||||||
this.progress.transferring = false;
|
this.progress.transferring = false;
|
||||||
this.model.onTone3000DownloadComplete(resultPath);
|
this.model.onTone3000DownloadComplete(resultPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async maybeSelectModels(toneName: string, models: Model[]): Promise<Model[]> {
|
||||||
|
let result = new Promise<Model[]>((resolve, reject) => {
|
||||||
|
if (models.length < 12) {
|
||||||
|
resolve(models);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.model.showT3kModelSelectionDialog(
|
||||||
|
this.downloadType,
|
||||||
|
toneName,
|
||||||
|
models,
|
||||||
|
(models: Model[])=> {
|
||||||
|
resolve(models);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
reject(new Error("canceled"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
private async DownloadModelsFromTone3000(
|
private async DownloadModelsFromTone3000(
|
||||||
responseUri: string,
|
responseUri: string,
|
||||||
tone3000PckceParams: Tone3000PkceParams,
|
tone3000PckceParams: Tone3000PkceParams,
|
||||||
@@ -293,6 +315,14 @@ export class Tone3000DownloadHandler {
|
|||||||
}
|
}
|
||||||
++page;
|
++page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
models = await this.maybeSelectModels(tone.title, models);
|
||||||
|
} catch (e) {
|
||||||
|
// canceled.
|
||||||
|
this.onTone3000DownloadComplete("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
let uploadPath = this.downloadPath;
|
let uploadPath = this.downloadPath;
|
||||||
let extension: string;
|
let extension: string;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ export default defineConfig({
|
|||||||
target: 'http://localhost:8080',
|
target: 'http://localhost:8080',
|
||||||
changeOrigin: false,
|
changeOrigin: false,
|
||||||
},
|
},
|
||||||
'^/var/.*': {
|
'^/var/(?!config\\.json$).*': {
|
||||||
target: 'http://localhost:8080',
|
target: 'http://localhost:8080',
|
||||||
changeOrigin: false,
|
changeOrigin: false,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user