+3
-2
@@ -48,9 +48,10 @@ install (FILES ${PROJECT_SOURCE_DIR}/build/src/notices.txt
|
||||
DESTINATION /etc/pipedal/react/var/)
|
||||
|
||||
install (FILES ${PROJECT_SOURCE_DIR}/src/template.service
|
||||
${PROJECT_SOURCE_DIR}/src/templateShutdown.service
|
||||
${PROJECT_SOURCE_DIR}/src/templateAdmin.service
|
||||
${PROJECT_SOURCE_DIR}/src/templateJack.service
|
||||
DESTINATION /etc/pipedal )
|
||||
${PROJECT_SOURCE_DIR}/src/defaultFavorites.json
|
||||
DESTINATION /etc/pipedal/config )
|
||||
|
||||
install (DIRECTORY ${LV2_SOURCE_DIRECTORY}
|
||||
DESTINATION /usr/lib/lv2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"socket_server_port": 80,
|
||||
"socket_server_port": 8080,
|
||||
"socket_server_address": "*",
|
||||
"debug": true,
|
||||
"max_upload_size": 1048576,
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import React, { ReactNode, SyntheticEvent, CSSProperties } from 'react';
|
||||
|
||||
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||
import { PiPedalModel, PiPedalModelFactory, FavoritesList } from './PiPedalModel';
|
||||
import { UiPlugin, PluginType } from './Lv2Plugin';
|
||||
import ButtonBase from '@mui/material/ButtonBase';
|
||||
import Button from '@mui/material/Button';
|
||||
@@ -42,10 +42,10 @@ import SearchControl from './SearchControl';
|
||||
import SearchFilter from './SearchFilter';
|
||||
import { FixedSizeGrid } from 'react-window';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
import Slide, {SlideProps} from '@mui/material/Slide';
|
||||
import StarBorderIcon from '@mui/icons-material/StarBorder';
|
||||
import Slide, { SlideProps } from '@mui/material/Slide';
|
||||
import { createStyles, Theme } from '@mui/material/styles';
|
||||
import { WithStyles, withStyles} from '@mui/styles';
|
||||
import { WithStyles, withStyles } from '@mui/styles';
|
||||
|
||||
|
||||
export type CloseEventHandler = () => void;
|
||||
@@ -119,6 +119,9 @@ const pluginGridStyles = (theme: Theme) => createStyles({
|
||||
paddingLeft: 16, whiteSpace: "nowrap"
|
||||
|
||||
},
|
||||
favoriteDecoration: {
|
||||
flex: "0 0 auto"
|
||||
},
|
||||
table: {
|
||||
borderCollapse: "collapse",
|
||||
},
|
||||
@@ -167,6 +170,7 @@ type PluginGridState = {
|
||||
grid_cell_width: number,
|
||||
grid_cell_columns: number,
|
||||
minimumItemWidth: number,
|
||||
favoritesList: FavoritesList
|
||||
|
||||
}
|
||||
|
||||
@@ -203,7 +207,8 @@ export const LoadPluginDialog =
|
||||
client_height: window.innerHeight,
|
||||
grid_cell_width: this.getCellWidth(window.innerWidth),
|
||||
grid_cell_columns: this.getCellColumns(window.innerWidth),
|
||||
minimumItemWidth: props.minimumItemWidth ? props.minimumItemWidth : 220
|
||||
minimumItemWidth: props.minimumItemWidth ? props.minimumItemWidth : 220,
|
||||
favoritesList: this.model.favorites.get()
|
||||
};
|
||||
|
||||
this.updateWindowSize = this.updateWindowSize.bind(this);
|
||||
@@ -211,6 +216,7 @@ export const LoadPluginDialog =
|
||||
this.handleOk = this.handleOk.bind(this);
|
||||
this.handleSearchStringReady = this.handleSearchStringReady.bind(this);
|
||||
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||
this.handleFavoritesChanged = this.handleFavoritesChanged.bind(this);
|
||||
}
|
||||
|
||||
nominal_column_width: number = 250;
|
||||
@@ -264,12 +270,23 @@ export const LoadPluginDialog =
|
||||
grid_cell_columns: this.getCellColumns(window.innerWidth)
|
||||
});
|
||||
}
|
||||
|
||||
handleFavoritesChanged() {
|
||||
this.setState(
|
||||
{
|
||||
favoritesList: this.model.favorites.get()
|
||||
});
|
||||
}
|
||||
componentDidMount() {
|
||||
super.componentDidMount();
|
||||
this.updateWindowSize();
|
||||
window.addEventListener('resize', this.updateWindowSize);
|
||||
this.model.favorites.addOnChangedHandler(this.handleFavoritesChanged);
|
||||
this.setState({ favoritesList: this.model.favorites.get() });
|
||||
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.model.favorites.removeOnChangedHandler(this.handleFavoritesChanged);
|
||||
super.componentWillUnmount();
|
||||
window.removeEventListener('resize', this.updateWindowSize);
|
||||
}
|
||||
@@ -352,18 +369,17 @@ export const LoadPluginDialog =
|
||||
let isDoubleClick = e.detail === 2;
|
||||
// we have to synthesize double clicks because
|
||||
// DOM rewrites interfere with natural double click.
|
||||
if (isDoubleClick)
|
||||
{
|
||||
if (isDoubleClick) {
|
||||
this.props.onOk(uri);
|
||||
}
|
||||
|
||||
}
|
||||
handleMouseEnter(e: SyntheticEvent, uri: string): void {
|
||||
// this.setHoverUri(uri);
|
||||
// this.setHoverUri(uri);
|
||||
|
||||
}
|
||||
handleMouseLeave(e: SyntheticEvent, uri: string): void {
|
||||
// this.setHoverUri("");
|
||||
// this.setHoverUri("");
|
||||
|
||||
}
|
||||
onInfoClicked(): void {
|
||||
@@ -421,6 +437,9 @@ export const LoadPluginDialog =
|
||||
let score = searchFilter.score(plugin.name, plugin.plugin_display_type, plugin.author_name);
|
||||
|
||||
if (score !== 0) {
|
||||
if (this.state.favoritesList[plugin.uri]) {
|
||||
score += 32768;
|
||||
}
|
||||
results.push({ score: score, plugin: plugin });
|
||||
}
|
||||
}
|
||||
@@ -469,6 +488,7 @@ export const LoadPluginDialog =
|
||||
let value = this.gridItems[item];
|
||||
|
||||
let classes = this.props.classes;
|
||||
let isFavorite: boolean = this.state.favoritesList[value.uri] ?? false;
|
||||
return (
|
||||
<div key={value.uri}
|
||||
onDoubleClick={(e) => { this.onDoubleClick(e, value.uri) }}
|
||||
@@ -491,12 +511,19 @@ export const LoadPluginDialog =
|
||||
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={classes.favoriteDecoration}>
|
||||
<StarBorderIcon sx={{ color: "#C80", opacity: isFavorite ? 1 : 0 }} />
|
||||
</div>
|
||||
</div>
|
||||
</ButtonBase>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
setFavorite(pluginUri: string | undefined, isFavorite: boolean): void {
|
||||
if (!pluginUri) return;
|
||||
this.model.setFavorite(pluginUri, isFavorite);
|
||||
}
|
||||
gridItems: UiPlugin[] = [];
|
||||
gridColumnCount: number = 1;
|
||||
|
||||
@@ -516,6 +543,7 @@ export const LoadPluginDialog =
|
||||
this.gridItems = this.getFilteredPlugins();
|
||||
let gridColumnCount = this.state.grid_cell_columns;
|
||||
this.gridColumnCount = gridColumnCount;
|
||||
let isFavorite = this.state.favoritesList[this.state.selected_uri ?? ""];
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Dialog
|
||||
@@ -530,7 +558,7 @@ export const LoadPluginDialog =
|
||||
aria-labelledby="select-plugin-dialog-title">
|
||||
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", height: "100%" }}>
|
||||
<DialogTitle id="select-plugin-dialog-title" style={{ flex: "0 0 auto", padding: "0px", height: 54 }}>
|
||||
<div style={{ display: "flex",flexDirection: "row", paddingTop: 3, paddingBottom: 3, flexWrap: "nowrap", width: "100%", alignItems: "center" }}>
|
||||
<div style={{ display: "flex", flexDirection: "row", paddingTop: 3, paddingBottom: 3, flexWrap: "nowrap", width: "100%", alignItems: "center" }}>
|
||||
<IconButton onClick={() => { this.cancel(); }} style={{ flex: "0 0 auto" }} >
|
||||
<ArrowBackIcon />
|
||||
</IconButton>
|
||||
@@ -567,7 +595,7 @@ export const LoadPluginDialog =
|
||||
key={this.state.filterType}
|
||||
onChange={(e) => { this.onFilterChange(e); }}
|
||||
style={{ flex: "0 0 160px" }}
|
||||
>
|
||||
>
|
||||
{this.createFilterOptions()}
|
||||
</Select>
|
||||
<div style={{ flex: "0 0 auto", marginRight: 24, visibility: this.state.filterType === PluginType.Plugin ? "hidden" : "visible" }} >
|
||||
@@ -625,6 +653,16 @@ export const LoadPluginDialog =
|
||||
<Typography display='block' variant='body2' color="textPrimary" noWrap >
|
||||
{this.info_string(selectedPlugin)}
|
||||
</Typography>
|
||||
<div style={{
|
||||
color: isFavorite ? "#F80" : "#CCC", display: (this.state.selected_uri !== "" ? "block" : "none"),
|
||||
position: "relative", top: -2
|
||||
}}>
|
||||
<IconButton color="inherit" aria-label="Set as favorite"
|
||||
onClick={() => { this.setFavorite(this.state.selected_uri, !isFavorite); }}
|
||||
>
|
||||
<StarBorderIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ position: "relative", float: "right", flex: "0 1 200px", width: 200, display: "flex", alignItems: "center" }}>
|
||||
<Button onClick={this.handleCancel} style={{ width: 120 }} >Cancel</Button>
|
||||
@@ -640,6 +678,16 @@ export const LoadPluginDialog =
|
||||
<Typography display='block' variant='body2' color="textPrimary" noWrap >
|
||||
{this.info_string(selectedPlugin)}
|
||||
</Typography>
|
||||
<div style={{
|
||||
color: isFavorite ? "#F80" : "#CCC", display: (this.state.selected_uri ? "block" : "block"),
|
||||
position: "relative", top: -5
|
||||
}}>
|
||||
<IconButton color="inherit" aria-label="Set as favorite"
|
||||
onClick={() => { this.setFavorite(this.state.selected_uri, !isFavorite); }}
|
||||
>
|
||||
<StarBorderIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.bottom}>
|
||||
<div style={{ flex: "1 1 1px" }} />
|
||||
|
||||
@@ -299,6 +299,9 @@ interface ControlChangedBody {
|
||||
value: number;
|
||||
};
|
||||
|
||||
export interface FavoritesList {
|
||||
[url: string]: boolean;
|
||||
}
|
||||
|
||||
export interface PiPedalModel {
|
||||
clientId: number;
|
||||
@@ -319,6 +322,7 @@ export interface PiPedalModel {
|
||||
jackServerSettings: ObservableProperty<JackServerSettings>;
|
||||
wifiConfigSettings: ObservableProperty<WifiConfigSettings>;
|
||||
governorSettings: ObservableProperty<GovernorSettings>;
|
||||
favorites: ObservableProperty<FavoritesList>;
|
||||
|
||||
presets: ObservableProperty<PresetIndex>;
|
||||
|
||||
@@ -422,6 +426,8 @@ export interface PiPedalModel {
|
||||
|
||||
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void;
|
||||
clearZoomedControl(): void;
|
||||
|
||||
setFavorite(pluginUrl: string, isFavorite: boolean): void;
|
||||
};
|
||||
|
||||
class PiPedalModelImpl implements PiPedalModel {
|
||||
@@ -453,6 +459,8 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
wifiConfigSettings: ObservableProperty<WifiConfigSettings> = new ObservableProperty<WifiConfigSettings>(new WifiConfigSettings());
|
||||
governorSettings: ObservableProperty<GovernorSettings> = new ObservableProperty<GovernorSettings>(new GovernorSettings());
|
||||
|
||||
favorites: ObservableProperty<FavoritesList> = new ObservableProperty<FavoritesList>({});
|
||||
|
||||
|
||||
presets: ObservableProperty<PresetIndex> = new ObservableProperty<PresetIndex>
|
||||
(
|
||||
@@ -496,6 +504,25 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
if (this.visibilityState.get() === VisibilityState.Hidden) return;
|
||||
this.onError(errorMessage);
|
||||
}
|
||||
|
||||
compareFavorites(left: FavoritesList, right: FavoritesList): boolean
|
||||
{
|
||||
for (let key of Object.keys(left))
|
||||
{
|
||||
if (!right[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (let key of Object.keys(right))
|
||||
{
|
||||
if (!left[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
onSocketMessage(header: PiPedalMessageHeader, body?: any) {
|
||||
if (this.visibilityState.get() === VisibilityState.Hidden) return;
|
||||
|
||||
@@ -512,7 +539,13 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
if (header.replyTo) {
|
||||
this.webSocket?.reply(header.replyTo, "onMonitorPortOutput", true);
|
||||
}
|
||||
|
||||
} else if (message === "onFavoritesChanged")
|
||||
{
|
||||
let favorites = body as FavoritesList;
|
||||
if (!this.compareFavorites(favorites,this.favorites.get()))
|
||||
{
|
||||
this.favorites.set(favorites);
|
||||
}
|
||||
} else if (message === "onChannelSelectionChanged") {
|
||||
let channelSelectionBody = body as ChannelSelectionChangedBody;
|
||||
let channelSelection = new JackChannelSelection().deserialize(channelSelectionBody.jackChannelSelection);
|
||||
@@ -705,6 +738,10 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
.then((data) => {
|
||||
this.banks.set(new BankIndex().deserialize(data));
|
||||
|
||||
return this.getWebSocket().request<FavoritesList>("getFavorites");
|
||||
})
|
||||
.then((data)=> {
|
||||
this.favorites.set(data);
|
||||
|
||||
this.setState(State.Ready);
|
||||
})
|
||||
@@ -839,6 +876,17 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
})
|
||||
.then((data) => {
|
||||
this.banks.set(new BankIndex().deserialize(data));
|
||||
if (this.webSocket)
|
||||
{
|
||||
// MUST not allow reconnect until at least one complete load has finished.
|
||||
this.webSocket.canReconnect = true;
|
||||
}
|
||||
|
||||
return this.getWebSocket().request<FavoritesList>("getFavorites");
|
||||
})
|
||||
.then((data)=> {
|
||||
this.favorites.set(data);
|
||||
|
||||
if (this.webSocket)
|
||||
{
|
||||
// MUST not allow reconnect until at least one complete load has finished.
|
||||
@@ -1891,6 +1939,29 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
this.zoomedUiControl.set(undefined);
|
||||
}
|
||||
|
||||
setFavorite(pluginUrl: string, isFavorite: boolean): void
|
||||
{
|
||||
let favorites = this.favorites.get();
|
||||
let newFavorites: FavoritesList = {};
|
||||
Object.assign(newFavorites,favorites);
|
||||
if (isFavorite)
|
||||
{
|
||||
newFavorites[pluginUrl] = true;
|
||||
} else {
|
||||
if (newFavorites[pluginUrl])
|
||||
{
|
||||
delete newFavorites[pluginUrl];
|
||||
}
|
||||
}
|
||||
this.favorites.set(newFavorites);
|
||||
if (this.webSocket)
|
||||
{
|
||||
this.webSocket.send("setFavorites",newFavorites);
|
||||
}
|
||||
// stub: update server.
|
||||
}
|
||||
|
||||
|
||||
preloadImages(imageList: string): void {
|
||||
let imageNames = imageList.split(';');
|
||||
for (let i = 0; i < imageNames.length; ++i) {
|
||||
|
||||
+3
-3
@@ -378,7 +378,7 @@ void InstallJackService()
|
||||
// deploy the systemd service file
|
||||
std::map<std::string, std::string> map; // nothing to customize.
|
||||
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/templateJack.service"), GetServiceFileName(JACK_SERVICE));
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/config/templateJack.service"), GetServiceFileName(JACK_SERVICE));
|
||||
|
||||
MaybeStartJackService();
|
||||
}
|
||||
@@ -554,7 +554,7 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
|
||||
map["COMMAND"] = s.str();
|
||||
}
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/template.service"), GetServiceFileName(NATIVE_SERVICE));
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/config/template.service"), GetServiceFileName(NATIVE_SERVICE));
|
||||
|
||||
map["DESCRIPTION"] = "PiPedal Shutdown Service";
|
||||
{
|
||||
@@ -566,7 +566,7 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
|
||||
map["COMMAND"] = s.str();
|
||||
}
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/templateShutdown.service"), GetServiceFileName(ADMIN_SERVICE));
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/config/templateAdmin.service"), GetServiceFileName(ADMIN_SERVICE));
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
||||
|
||||
|
||||
+27
-1
@@ -111,7 +111,8 @@ PiPedalModel::~PiPedalModel()
|
||||
void PiPedalModel::LoadLv2PluginInfo(const PiPedalConfiguration&configuration)
|
||||
{
|
||||
|
||||
storage.SetDataRoot(configuration.GetLocalStoragePath().c_str());
|
||||
storage.SetConfigRoot(configuration.GetDocRoot());
|
||||
storage.SetDataRoot(configuration.GetLocalStoragePath());
|
||||
storage.Initialize();
|
||||
|
||||
// Not all Lv2 directories have the lv2 base declarations. Load a full set of plugin classes generated on a default /usr/local/lib/lv2 directory.
|
||||
@@ -1316,3 +1317,28 @@ const std::filesystem::path& PiPedalModel::GetWebRoot() const
|
||||
{
|
||||
return webRoot;
|
||||
}
|
||||
|
||||
std::map<std::string,bool> PiPedalModel::GetFavorites() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(const_cast<std::recursive_mutex&>(mutex));
|
||||
|
||||
return storage.GetFavorites();
|
||||
}
|
||||
void PiPedalModel::SetFavorites(const std::map<std::string,bool> &favorites)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
storage.SetFavorites(favorites);
|
||||
|
||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||
std::vector<IPiPedalModelSubscriber*> t;
|
||||
t.reserve(this->subscribers.size());
|
||||
|
||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||
{
|
||||
t.push_back(this->subscribers[i]);
|
||||
}
|
||||
for (size_t i = 0; i < t.size(); ++i)
|
||||
{
|
||||
t[i]->OnFavoritesChanged(favorites);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
virtual void OnNotifyAtomOutput(int64_t clientModel,uint64_t instanceId,const std::string&atomType, const std::string&atomJson) = 0;
|
||||
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) = 0;
|
||||
virtual void OnGovernorSettingsChanged(const std::string &governor) = 0;
|
||||
virtual void OnFavoritesChanged(const std::map<std::string,bool> &favorites) = 0;
|
||||
virtual void Close() = 0;
|
||||
};
|
||||
|
||||
@@ -235,6 +236,9 @@ public:
|
||||
|
||||
std::vector<AlsaDeviceInfo> GetAlsaDevices();
|
||||
const std::filesystem::path& GetWebRoot() const;
|
||||
|
||||
std::map<std::string,bool> GetFavorites() const;
|
||||
void SetFavorites(const std::map<std::string,bool> &favorites);
|
||||
};
|
||||
|
||||
} // namespace pipedal.
|
||||
+15
-1
@@ -1098,7 +1098,7 @@ public:
|
||||
[this, subscriptionHandle_](const bool &result)
|
||||
{
|
||||
this->portMonitorAck(subscriptionHandle_); // please can we have some more.
|
||||
// (....complexity not worth the effort. :-( )
|
||||
|
||||
},
|
||||
[](const std::exception &e)
|
||||
{
|
||||
@@ -1169,6 +1169,16 @@ public:
|
||||
{
|
||||
|
||||
this->Reply(replyTo, "imageList", imageList);
|
||||
} else if (message == "getFavorites")
|
||||
{
|
||||
std::map<std::string,bool> favorites = this->model.GetFavorites();
|
||||
this->Reply(replyTo,"getFavorites",favorites);
|
||||
|
||||
} else if (message == "setFavorites")
|
||||
{
|
||||
std::map<std::string,bool> favorites;
|
||||
pReader->read(&favorites);
|
||||
this->model.SetFavorites(favorites);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1243,6 +1253,10 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void OnFavoritesChanged(const std::map<std::string,bool> &favorites)
|
||||
{
|
||||
Send("onFavoritesChanged",favorites);
|
||||
}
|
||||
virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection &channelSelection)
|
||||
{
|
||||
ChannelSelectionChangedBody body;
|
||||
|
||||
+39
-2
@@ -36,6 +36,7 @@ const char *BANKS_FILENAME = "index.banks";
|
||||
|
||||
Storage::Storage()
|
||||
{
|
||||
SetConfigRoot("~/var/Config");
|
||||
SetDataRoot("~/var/PiPedal");
|
||||
}
|
||||
|
||||
@@ -127,7 +128,7 @@ std::string Storage::SafeEncodeName(const std::string &name)
|
||||
return s.str();
|
||||
}
|
||||
|
||||
std::filesystem::path ResolveHomePath(std::filesystem::path path)
|
||||
std::filesystem::path ResolveHomePath(const std::filesystem::path& path)
|
||||
{
|
||||
if (path.begin() == path.end())
|
||||
return path;
|
||||
@@ -156,7 +157,12 @@ std::filesystem::path ResolveHomePath(std::filesystem::path path)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void Storage::SetDataRoot(const char *path)
|
||||
|
||||
void Storage::SetConfigRoot(const std::filesystem::path& path)
|
||||
{
|
||||
this->configRoot = ResolveHomePath(path);
|
||||
}
|
||||
void Storage::SetDataRoot(const std::filesystem::path& path)
|
||||
{
|
||||
this->dataRoot = ResolveHomePath(path);
|
||||
}
|
||||
@@ -1186,6 +1192,37 @@ uint64_t Storage::CopyPluginPreset(const std::string&pluginUri,uint64_t presetId
|
||||
|
||||
}
|
||||
|
||||
std::map<std::string,bool> Storage::GetFavorites() const
|
||||
{
|
||||
std::map<std::string,bool> result;
|
||||
|
||||
std::filesystem::path fileName = this->dataRoot / "favorites.json";
|
||||
if (!std::filesystem::exists(fileName))
|
||||
{
|
||||
fileName = this->configRoot / "defaultFavorites.json";
|
||||
}
|
||||
std::ifstream f;
|
||||
f.open(fileName);
|
||||
if (f.is_open())
|
||||
{
|
||||
json_reader reader(f);
|
||||
reader.read(&result);
|
||||
}
|
||||
return result;
|
||||
|
||||
|
||||
}
|
||||
void Storage::SetFavorites(const std::map<std::string,bool>&favorites) {
|
||||
std::filesystem::path fileName = this->dataRoot / "favorites.json";
|
||||
std::ofstream f;
|
||||
f.open(fileName);
|
||||
if (f.is_open())
|
||||
{
|
||||
json_writer writer(f);
|
||||
writer.write(favorites);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JSON_MAP_BEGIN(CurrentPreset)
|
||||
JSON_MAP_REFERENCE(CurrentPreset,modified)
|
||||
|
||||
+7
-1
@@ -26,6 +26,7 @@
|
||||
#include "Banks.hpp"
|
||||
#include "JackConfiguration.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include <map>
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
@@ -44,6 +45,7 @@ public:
|
||||
class Storage {
|
||||
private:
|
||||
std::filesystem::path dataRoot;
|
||||
std::filesystem::path configRoot;
|
||||
BankIndex bankIndex;
|
||||
BankFile currentBank;
|
||||
PluginPresetIndex pluginPresetIndex;
|
||||
@@ -78,7 +80,8 @@ public:
|
||||
void Initialize();
|
||||
void CreateBank(const std::string & name);
|
||||
|
||||
void SetDataRoot(const char*path);
|
||||
void SetDataRoot(const std::filesystem::path& path);
|
||||
void SetConfigRoot(const std::filesystem::path& path);
|
||||
|
||||
std::vector<std::string> GetPedalBoards();
|
||||
|
||||
@@ -140,6 +143,9 @@ public:
|
||||
void UpdatePluginPresets(const PluginUiPresets &pluginPresets);
|
||||
uint64_t CopyPluginPreset(const std::string&pluginUri,uint64_t presetId);
|
||||
|
||||
std::map<std::string,bool> GetFavorites() const;
|
||||
void SetFavorites(const std::map<std::string,bool>&favorites);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"http://two-play.com/plugins/toob-cab-sim": true,
|
||||
"http://two-play.com/plugins/toob-chorus": true,
|
||||
"http://two-play.com/plugins/toob-delay": true,
|
||||
"http://two-play.com/plugins/toob-freeverb": true,
|
||||
"http://two-play.com/plugins/toob-input_stage": true,
|
||||
"http://two-play.com/plugins/toob-ml": true,
|
||||
"http://two-play.com/plugins/toob-power-stage-2": true,
|
||||
"http://two-play.com/plugins/toob-spectrum": true,
|
||||
"http://two-play.com/plugins/toob-tone-stack": true,
|
||||
"http://two-play.com/plugins/toob-tuner": true
|
||||
}
|
||||
Reference in New Issue
Block a user