// Copyright (c) 2022 Robin Davies // // 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 React, { SyntheticEvent,Component } from 'react'; import IconButton from '@mui/material/IconButton'; import Typography from '@mui/material/Typography'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import Button from "@mui/material/Button"; import ButtonBase from "@mui/material/ButtonBase"; import DialogEx from './DialogEx'; import AppBar from '@mui/material/AppBar'; import Toolbar from '@mui/material/Toolbar'; import DraggableGrid, { ScrollDirection } from './DraggableGrid'; import MoreVertIcon from '@mui/icons-material//MoreVert'; import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemText from '@mui/material/ListItemText'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import Fade from '@mui/material/Fade'; import UploadPresetDialog from './UploadPresetDialog'; import {PluginUiPresets,PluginUiPreset} from './PluginPreset'; import SelectHoverBackground from './SelectHoverBackground'; import CloseIcon from '@mui/icons-material//Close'; import ArrowBackIcon from '@mui/icons-material//ArrowBack'; import EditIcon from '@mui/icons-material//Edit'; import RenameDialog from './RenameDialog'; import Slide, {SlideProps} from '@mui/material/Slide'; import { createStyles, Theme } from '@mui/material/styles'; import { WithStyles, withStyles} from '@mui/styles'; import {ReactComponent as PluginPresetIcon} from "./svg/ic_pluginpreset2.svg"; import { ReactComponent as DownloadIcon} from './svg/file_download_black_24dp.svg'; import { ReactComponent as UploadIcon} from './svg/file_upload_black_24dp.svg'; interface PluginPresetsDialogProps extends WithStyles { show: boolean; isEditDialog: boolean; instanceId: number; presets :PluginUiPresets; onDialogClose: () => void; }; interface PluginPresetsDialogState { showActionBar: boolean; selectedItem: number; renameOpen: boolean; moreMenuAnchorEl: HTMLElement | null; openUploadPresetDialog: boolean; }; const styles = (theme: Theme) => createStyles({ listIcon: { width: 24, height: 24, opacity: 0.6,fill: theme.palette.text.primary }, dialogAppBar: { position: 'relative', top: 0, left: 0 }, itemBackground: { background: theme.palette.background.paper }, dialogActionBar: { position: 'relative', top: 0, left: 0, background: "black" }, dialogTitle: { marginLeft: theme.spacing(2), textOverflow: "ellipsis", flex: "1 1", }, itemFrame: { display: "flex", flexDirection: "row", flexWrap: "nowrap", width: "100%", height: "56px", alignItems: "center", textAlign: "left", justifyContent: "center", paddingLeft: 8 }, iconFrame: { flex: "0 0 auto", }, itemIcon: { width: 24, height: 24, margin: 12, opacity: 0.6, fill: theme.palette.text.primary }, itemLabel: { flex: "1 1 1px", marginLeft: 8 } }); const Transition = React.forwardRef(function Transition( props: SlideProps, ref: React.Ref ) { return (); }); const PluginPresetsDialog = withStyles(styles, { withTheme: true })( class extends Component { model: PiPedalModel; constructor(props: PluginPresetsDialogProps) { super(props); this.model = PiPedalModelFactory.getInstance(); this.handleDialogClose = this.handleDialogClose.bind(this); this.state = { showActionBar: false, selectedItem: -1, renameOpen: false, moreMenuAnchorEl: null, openUploadPresetDialog: false }; } selectItemAtIndex(index: number) { let instanceId = this.props.presets.presets[index].instanceId; this.setState({ selectedItem: instanceId }); } isEditMode() { return this.state.showActionBar || this.props.isEditDialog; } onMoreClick(e: SyntheticEvent): void { this.setState({ moreMenuAnchorEl: e.currentTarget as HTMLElement }) } handleDownloadPresets() { this.handleMoreClose(); if (this.props.presets.pluginUri !== "") { this.model.download("downloadPluginPresets", this.props.presets.pluginUri); } } handleUploadPresets() { this.handleMoreClose(); this.setState({ openUploadPresetDialog: true }); } handleMoreClose(): void { this.setState({ moreMenuAnchorEl: null }); } componentDidUpdate() { if (!this.props.presets.getItem(this.state.selectedItem)) { if (this.props.presets.presets.length !== 0) { this.setState({selectedItem: this.props.presets.presets[0].instanceId}); } } } componentDidMount() { // scroll selected item into view. } componentWillUnmount() { } getSelectedIndex() { let instanceId = this.state.selectedItem; let presets = this.props.presets; for (let i = 0; i < presets.presets.length; ++i) { if (presets.presets[i].instanceId === instanceId) return i; } return -1; } handleDeleteClick() { let selectedItem = this.state.selectedItem; if (selectedItem !== -1) { let newPresets = this.props.presets.clone(); for (let i = 0; i < newPresets.presets.length; ++i) { if (newPresets.presets[i].instanceId === selectedItem) { newPresets.presets.splice(i,1); this.model.updatePluginPresets(newPresets.pluginUri,newPresets) .catch((error) => { this.model.showAlert(error); }); let newPos = i; if (newPos >= newPresets.presets.length) { --i; } let newSelection = i < 0? -1: newPresets.presets[i].instanceId; this.setState({selectedItem: newSelection}); } } } } handleDialogClose() { this.props.onDialogClose(); } handleItemClick(instanceId: number): void { if (this.isEditMode()) { this.setState({ selectedItem: instanceId }); } else { this.model.loadPreset(instanceId); this.props.onDialogClose(); } } showActionBar(show: boolean): void { this.setState({ showActionBar: show }); } mapElement(el: any): React.ReactNode { let presetEntry = el as PluginUiPreset; let classes = this.props.classes; let selectedItem = this.state.selectedItem; return (
this.handleItemClick(presetEntry.instanceId)} >
{presetEntry.label}
); } updateServerPluginPresets(newPresets: PluginUiPresets) { newPresets = newPresets.clone(); this.model.updatePluginPresets(this.getPluginUri(),newPresets) .catch((error) => { this.model.showAlert(error); }); } moveElement(from: number, to: number): void { let newPresets: PluginUiPresets = this.props.presets.clone(); newPresets.movePreset(from, to); this.setState({ selectedItem: newPresets.presets[to].instanceId }); this.updateServerPluginPresets(newPresets); } getSelectedName(): string { let item = this.props.presets.getItem(this.state.selectedItem); if (item) return item.label; return ""; } handleRenameClick() { let item = this.props.presets.getItem(this.state.selectedItem); if (item) { this.setState({ renameOpen: true }); } } handleRenameOk(text: string) { let item = this.props.presets.getItem(this.state.selectedItem); if (!item) return; if (item.label !== text) { let newPresets = this.props.presets.clone(); let newItem = newPresets.getItem(this.state.selectedItem); if (!newItem) return; newItem.label = text; this.updateServerPluginPresets(newPresets); } this.setState({ renameOpen: false }); } getPluginUri() : string { let pedalboardItem = this.model.pedalboard.get().getItem(this.props.instanceId); return pedalboardItem.uri; } handleCopy() { let item = this.props.presets.getItem(this.state.selectedItem); if (!item) return; this.model.duplicatePluginPreset(this.getPluginUri(),this.state.selectedItem) .then((newId) => { this.setState({ selectedItem: newId }); }).catch((error) => { this.onError(error); }); } onError(error: string): void { this.model?.showAlert(error); } render() { let classes = this.props.classes; let actionBarClass = this.props.isEditDialog ? classes.dialogAppBar : classes.dialogActionBar; let defaultSelectedIndex = this.getSelectedIndex(); let title: string = ""; let pluginUri = this.getPluginUri(); let plugin = this.model.getUiPlugin(pluginUri); if (plugin) { title = "Presets - " + plugin.name; } return ( { this.handleDialogClose() }} TransitionComponent={Transition} style={{userSelect: "none"}}>
{title} this.showActionBar(true)} > { e.stopPropagation(); e.preventDefault(); }} > {(!this.props.isEditDialog) ? ( this.showActionBar(false)} aria-label="close"> ) : ( )} { title } {(this.props.presets.getItem(this.state.selectedItem) != null) && (
{ this.setState({ renameOpen: false }) }} onOk={(text: string) => { this.handleRenameOk(text); } } /> this.handleDeleteClick()} > Delete { this.onMoreClick(e) }} > this.handleMoreClose()} TransitionComponent={Fade} > { this.handleDownloadPresets(); }} disabled={this.props.presets.presets.length === 0} > Download presets { this.handleUploadPresets() }}> Upload presets
) }
this.showActionBar(true)} canDrag={this.isEditMode()} onDragStart={(index, x, y) => { this.selectItemAtIndex(index) }} moveElement={(from, to) => { this.moveElement(from, to); }} scroll={ScrollDirection.Y} defaultSelectedIndex={defaultSelectedIndex} > { this.props.presets.presets.map((element) => { return this.mapElement(element); }) }
{} } uploadAfter={this.state.selectedItem} open={this.state.openUploadPresetDialog} onClose={() => { this.setState({ openUploadPresetDialog: false }) }} />
); } } ); export default PluginPresetsDialog;