Skip to content

Commit

Permalink
Move Stream type selection, Stream creation, and Preset creation moda…
Browse files Browse the repository at this point in the history
…ls into the components folder and reuse them on the home page
  • Loading branch information
SteveMicroNova committed Jan 16, 2025
1 parent f9a577a commit 259e28e
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 74 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Update Airplay icon to modern variant
* Add gradient to background to break up the solid color
* Reformat Admin Settings portion of Admin Panel (previously known as the Updater)
* Add ability to create streams, presets from the home screen

## 0.4.5
* Web App
Expand Down
49 changes: 49 additions & 0 deletions web/src/components/CreateStreamModal/CreateStreamModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from "react";
import PropTypes from "prop-types";
import StreamTemplates from "./StreamTemplates.json";
import TypeSelectModal from "./TypeSelectModal/TypeSelectModal";
import StreamModal from "./StreamModal/StreamModal";

export default function CreateStreamModal({showSelect, onClose}) {
// A wrapper for two modals so that their workflows can easily be placed wherever needed
const [showCreate, setShowCreate] = React.useState(false);
const [selectedType, setSelectedType] = React.useState("");

const initEmptyStream = (type) => {
const streamTemplate = StreamTemplates.filter((t) => t.type === type)[0];
let stream = { type: type, disabled: false };
streamTemplate.fields.forEach((field) => {
stream[field.name] = field.default;
});
return stream;
};

return(
<>
{showSelect && (
<TypeSelectModal
onClose={() => {
onClose();
}}
onSelect={(type) => {
setSelectedType(type);
onClose();
setShowCreate(true);
}}
/>
)}
{showCreate && (
<StreamModal
stream={initEmptyStream(selectedType)}
onClose={() => {
setShowCreate(false);
}}
/>
)}
</>
)
};
CreateStreamModal.propTypes = {
showSelect: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
};
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ const InternetRadioSearch = ({ onChange }) => {
InternetRadioSearch.propTypes = {
onChange: PropTypes.func.isRequired,
};
const StreamModal = ({ stream, onClose, apply, del }) => {
const StreamModal = ({ stream, onClose, del }) => {
const [streamFields, setStreamFields] = React.useState(
JSON.parse(JSON.stringify(stream))
); // set streamFields to copy of stream
Expand All @@ -208,6 +208,14 @@ const StreamModal = ({ stream, onClose, apply, del }) => {
const [hasError, setHasError] = React.useState(false); // Need a discrete hasError bool to trigger error
const [renderAlertAnimation, setAlertAnimation] = React.useState(0); // Need a discrete hasError bool to trigger error

const apply = (stream) => {
return fetch("/api/stream", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(stream),
});
};

const streamTemplate = StreamTemplates.filter(
(t) => t.type === stream.type
)[0];
Expand Down Expand Up @@ -383,7 +391,6 @@ const StreamModal = ({ stream, onClose, apply, del }) => {
StreamModal.propTypes = {
stream: PropTypes.any.isRequired,
onClose: PropTypes.func.isRequired,
apply: PropTypes.func.isRequired,
del: PropTypes.func,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const TypeSelectModal = ({ onClose, onSelect }) => {

return (
<>
<Modal className="streams-modal" onClose={onClose}>
<Modal onClose={onClose}>
<Card className="type-select-card">
<div className="type-select-title">Select A Stream Type</div>
<div>
Expand Down
5 changes: 5 additions & 0 deletions web/src/components/PresetsModal/PresetsModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { useStatusStore } from "@/App";
import { useState } from "react";
import List from "@/components/List/List";
import ListItem from "@/components/List/ListItem/ListItem";
import CreatePresetModal from "@/components/CreatePresetModal/CreatePresetModal";

import PropTypes from "prop-types";
import RectangularAddButton from "../RectangularAddButton/RectangularAddButton";

const timeSince = (timeStamp) => {
var now = new Date(),
Expand Down Expand Up @@ -71,6 +73,7 @@ const PresetsModal = ({ onClose }) => {
presets.map((preset) => {if(preset){return false;}}) // Changed this line so that preset wouldn't go unused as per eslint
);
const setSystemState = useStatusStore((s) => s.setSystemState);
const [createModalOpen, setCreateModalOpen] = React.useState(false);

// resize presetStates (without overriding) if length changes
if (presetStates.length > presets.length) {
Expand Down Expand Up @@ -118,6 +121,8 @@ const PresetsModal = ({ onClose }) => {
<div className="presets-modal-header">Select Preset</div>
<div className="presets-modal-body">
<List>{presetItems}</List>
<RectangularAddButton onClick={() => {setCreateModalOpen(true); onClose();}} />
{ createModalOpen && <CreatePresetModal onClose={() => {setCreateModalOpen(false);}} /> }
</div>
</Card>
</Modal>
Expand Down
18 changes: 18 additions & 0 deletions web/src/components/RectangularAddButton/RectangularAddButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import "./RectangularAddButton.scss"

import PropTypes from "prop-types";

export default function RectangularAddButton({onClick}){
return(
<div
className="rectangular-add-button"
onClick={onClick}
>
+
</div>
)
}
RectangularAddButton.propTypes = {
onClick: PropTypes.func.isRequired,
};
19 changes: 19 additions & 0 deletions web/src/components/RectangularAddButton/RectangularAddButton.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@use "src/general";

.rectangular-add-button {
// @include general.low-shadow;
width: 100%;
height: 4rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 3rem;
color: general.$controls-color;
border-color: general.$secondary;
border-style: solid;
border-radius: 1rem;
background-color: general.$bg;

@include general.button-hover;
}
6 changes: 6 additions & 0 deletions web/src/components/StreamsModal/StreamsModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import List from "@mui/material/List";
import ListItemButton from "@mui/material/ListItemButton";
import ListItemText from "@mui/material/ListItemText";
import Divider from "@mui/material/Divider";
import RectangularAddButton from "@/components/RectangularAddButton/RectangularAddButton";
import CreateStreamModal from "@/components/CreateStreamModal/CreateStreamModal";

import PropTypes from "prop-types";

Expand Down Expand Up @@ -44,6 +46,7 @@ const StreamsModal = ({
const status = useStatusStore((state) => state.status);
const playingStreamIds = status.sources.filter( (s) => s.input !== 'None').map( (s) => parseInt(s.input.replace('stream=', '')));
const playingStreams = streams.filter( (s) => playingStreamIds.includes(s.id) );
const [createModalOpen, setCreateModalOpen] = React.useState(false);
let filteredStreams = streams.filter( (s) => !playingStreamIds.includes(s.id) && !s.disabled);

// If there are any running bluetooth or FM streams, mark other instances as disabled - we do not (yet)
Expand Down Expand Up @@ -133,6 +136,9 @@ const StreamsModal = ({
return (
<ModalCard header="Select Stream" onClose={onClose} onCancel={onClose}>
<List>{streamsList}</List>
<RectangularAddButton onClick={() => {setCreateModalOpen(true);}} />
<CreateStreamModal showSelect={createModalOpen} onClose={() => {setCreateModalOpen(false);}} />

</ModalCard>
);
};
Expand Down
10 changes: 2 additions & 8 deletions web/src/pages/Home/Home.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";
import PlayerCardFb from "@/components/PlayerCard/PlayerCardFb";
import RectangularAddButton from "@/components/RectangularAddButton/RectangularAddButton";
import "./Home.scss";
import { useStatusStore } from "@/App.jsx";
import ZonesModal from "@/components/ZonesModal/ZonesModal";
Expand Down Expand Up @@ -35,14 +36,7 @@ const PresetAndAdd = ({
if (cards.length < sources.length) {
return (
<div className="home-presets-container">
<div
className="home-add-player-button"
onClick={() => {
initSource(nextAvailableSource);
}}
>
+
</div>
<RectangularAddButton onClick={() => {initSource(nextAvailableSource);}} />
<div style={{ width: "1.25rem" }} />
<div
className="home-presets-button"
Expand Down
18 changes: 0 additions & 18 deletions web/src/pages/Home/Home.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,6 @@
// width: fit-content;
}

.home-add-player-button {
// @include general.low-shadow;
width: 100%;
height: 4rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 3rem;
color: general.$controls-color;
border-color: general.$secondary;
border-style: solid;
border-radius: 1rem;
background-color: general.$bg;

@include general.button-hover;
}

.home-presets-button {
// @include general.low-shadow;
@include general.regular-font;
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/Settings/Presets/Presets.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "./Presets.scss";
import { useStatusStore } from "@/App.jsx";
import { Fab } from "@mui/material";
import AddIcon from "@mui/icons-material/Add";
import CreatePresetModal from "./CreatePresetModal/CreatePresetModal";
import CreatePresetModal from "@/components/CreatePresetModal/CreatePresetModal";
import EditPresetModal from "./EditPresetModal/EditPresetModal";
import { PlaylistAdd } from "@mui/icons-material";
import List from "@mui/material/List/List";
Expand Down
47 changes: 3 additions & 44 deletions web/src/pages/Settings/Streams/Streams.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,14 @@ import PageHeader from "@/components/PageHeader/PageHeader";
import "./Streams.scss";
import "../PageBody.scss";
import { useStatusStore } from "@/App.jsx";
import StreamModal from "./StreamModal/StreamModal";
import CreateStreamModal from "@/components/CreateStreamModal/CreateStreamModal";
import Fab from "@mui/material/Fab";
import AddIcon from "@mui/icons-material/Add";
import TypeSelectModal from "./TypeSelectModal/TypeSelectModal";
import StreamTemplates from "./StreamTemplates.json";
import { getIcon } from "@/utils/getIcon";
import List from "@mui/material/List/List";
import ListItemButton from "@mui/material/ListItemButton";
import Divider from "@mui/material/Divider";

const initEmptyStream = (type) => {
const streamTemplate = StreamTemplates.filter((t) => t.type === type)[0];
let stream = { type: type, disabled: false };
streamTemplate.fields.forEach((field) => {
stream[field.name] = field.default;
});
return stream;
};
import StreamModal from "@/components/CreateStreamModal/StreamModal/StreamModal";

const applyStreamChanges = (stream) => {
return fetch(`/api/streams/${stream.id}`, {
Expand All @@ -31,14 +21,6 @@ const applyStreamChanges = (stream) => {
});
};

const makeNewStream = (stream) => {
return fetch("/api/stream", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(stream),
});
};

const deleteStream = (stream) => {
fetch(`/api/streams/${stream.id}`, { method: "DELETE" });
};
Expand Down Expand Up @@ -76,9 +58,7 @@ StreamListItem.propTypes = {

const Streams = ({ onClose }) => {
const streams = useStatusStore((state) => state.status.streams);
const [showModal, setShowModal] = React.useState(false);
const [showSelect, setShowSelect] = React.useState(false);
const [selectedType, setSelectedType] = React.useState("");

return (
<div className="page-container">
Expand All @@ -95,28 +75,7 @@ const Streams = ({ onClose }) => {
</Fab>
</div>
</div>

{showSelect && (
<TypeSelectModal
onClose={() => {
setShowSelect(false);
}}
onSelect={(type) => {
setSelectedType(type);
setShowSelect(false);
setShowModal(true);
}}
/>
)}
{showModal && (
<StreamModal
stream={initEmptyStream(selectedType)}
apply={makeNewStream}
onClose={() => {
setShowModal(false);
}}
/>
)}
<CreateStreamModal showSelect={showSelect} onClose={() => {setShowSelect(false);}} />
</div>
);
};
Expand Down

0 comments on commit 259e28e

Please sign in to comment.