Skip to content

Commit

Permalink
Merge pull request #12 from klay2000/presets
Browse files Browse the repository at this point in the history
Presets
  • Loading branch information
jonahshader authored Apr 25, 2023
2 parents 42a0d22 + fecc6a5 commit a6cdf04
Show file tree
Hide file tree
Showing 19 changed files with 564 additions and 23 deletions.
2 changes: 1 addition & 1 deletion web2/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ function App({ selectedPage }) {
const Page = () => {
switch(selectedPage) {
default:
return <Home selectedSource={selectedSource} setSelectedPage={setSelectedPage} setSelectedSource={setSelectedSource} />
return <Home selectedSource={selectedSource} setSelectedSource={setSelectedSource} />
case 1:
return <Player selectedSource={selectedSource} />
case 2:
Expand Down
5 changes: 3 additions & 2 deletions web2/src/components/PlayerCard/PlayerCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ import PlayerImage from "../PlayerImage/PlayerImage";
import ZonesBadge from "../ZonesBadge/ZonesBadge";
import StreamsModal from "../StreamsModal/StreamsModal";
import ZonesModal from "../ZonesModal/ZonesModal";
import { router } from "@/main";

const PlayerCard = ({ sourceId, selectedSource, setSelectedPage, setSelectedSource }) => {
const PlayerCard = ({ sourceId, selectedSource, setSelectedSource }) => {
const [streamModalOpen, setStreamModalOpen] = useState(false);
const [zoneModalOpen, setZoneModalOpen] = useState(false);
const selected = selectedSource === sourceId

const select = () => {
if (selected) {
setSelectedPage(1)
router.navigate('/player')
}

setSelectedSource(sourceId)
Expand Down
95 changes: 95 additions & 0 deletions web2/src/components/PresetsModal/PresetsModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import './PresetsModal.scss'
import Modal from '@/components/Modal/Modal'
import Card from '@/components/Card/Card'
import { useStatusStore } from '@/App'
import { useState } from 'react'

const timeSince = (timeStamp) => {
var now = new Date(),
secondsPast = (now.getTime() - timeStamp) / 1000;
if (secondsPast < 60) {
return parseInt(secondsPast) + 's';
}
if (secondsPast < 3600) {
return parseInt(secondsPast / 60) + 'm';
}
if (secondsPast <= 86400) {
return parseInt(secondsPast / 3600) + 'h';
}
if (secondsPast > 86400) {
let day = timeStamp.getDate();
let month = timeStamp.toDateString().match(/ [a-zA-Z]*/)[0].replace(" ", "");
let year = timeStamp.getFullYear() == now.getFullYear() ? "" : " " + timeStamp.getFullYear();
return day + " " + month + year;
}
}

const PresetItem = ({ index, onClick, presetState }) => {
const preset = useStatusStore((state) => state.status.presets[index])
const name = preset.name
const last_used = timeSince(new Date(preset.last_used * 1000)) // js expects milliseconds from epoch
// const last_used = 0

// show checkmark if presetState is 'done'
// show spinner if presetState is 'loading'
return (
<div className="preset-item" onClick={() => onClick(index)}>
<div className="preset-name-and-last-used">
<div>{name}</div>
<div className="preset-item-last-used">{last_used}</div>
</div>

{presetState === 'done' && <div className="preset-item-icon"></div>}
{presetState === 'loading' && <div className="preset-item-icon"></div>}
</div>
)
}


const PresetsModal = ({ onClose }) => {
const presets = useStatusStore((state) => state.status.presets)
const [presetStates, setPresetStates] = useState(presets.map((preset) => false))

// resize presetStates (without overriding) if length changes
if (presetStates.length > presets.length) {
setPresetStates(presetStates.slice(0, presets.length))
} else if (presetStates.length < presets.length) {
setPresetStates([...presetStates, ...Array(presets.length - presetStates.length).fill(false)])
}

const apply = (index) => {
setPresetStates(presetStates.map((state, i) => (i === index ? 'loading' : state)))
const id = presets[index].id
console.log(`/api/presets/${id}/load`)
fetch(`/api/presets/${id}/load`, { method: 'POST', accept: 'application/json' })
.then(() => setPresetStates(presetStates.map((state, i) => (i === index ? 'done' : state))))
.catch(() => setPresetStates(presetStates.map((state, i) => (i === index ? false : state))))
}

const presetItems = presets.map((preset, index) => (
<PresetItem
key={index}
index={index}
onClick={apply}
presetState={presetStates[index]}
/>
))

return (
<Modal className="presets-modal" onClose={onClose}>
<Card className="presets-modal-card">
<div className="presets-modal-header">
Select Preset
</div>
<div className="presets-modal-body">
{presetItems}
</div>
</Card>
</Modal>
)
}

export default PresetsModal



62 changes: 62 additions & 0 deletions web2/src/components/PresetsModal/PresetsModal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@use "src/general.scss";

.presets-modal{
@include general.header-font;
font-size: 1.5rem;
color: general.$text-color;
}

.presets-modal-card{
max-height: 75vh;
overflow: hidden;
display: flex;
flex-direction: column;
}

.presets-modal-header {
margin: 0.5rem;
font-size: 3rem;
text-align: center;
}

.presets-modal-body {
padding: 1rem;
overflow-y: scroll;
//the below is to push the scrollbar out of the card to hide it
padding-right: 16px;
width: 100%;
height: 100%;
}

.presets-modal-list-item{
margin-bottom: 1rem;
}

.preset-item {
display: flex;
flex-direction: row;
justify-content: space-between;
// align-items: center;
// padding: 0.5rem;
// border: 1px solid #000000;
// border-radius: 5px;
// margin-bottom: 0.5rem;
}

.preset-name-and-last-used {
display: flex;
flex-direction: row;
justify-content: flex-start;
}

.preset-item-last-used {
// just want to make the font smaller
color: general.$select-color-gray;
font-size: 1.25rem;
padding-left: 8px;
}

.preset-item-icon {
font-size: 1.5rem;
padding-right: 2rem;
}
1 change: 0 additions & 1 deletion web2/src/components/StreamsModal/StreamsModal.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import "./StreamsModal.scss";
import Modal from "../Modal/Modal";
import Card from "../Card/Card";
import StreamBadge from "../StreamBadge/StreamBadge";
import { useStatusStore } from "@/App";

//TODO: fix RCA behavior
Expand Down
1 change: 1 addition & 0 deletions web2/src/general.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ $controls-color: #F2F2F2;
$icon-deselected-color: #8D8D8D;
$volume-slider-color: #0096FF;
$text-color: #FFFFFF;
$select-color-gray: #BDBDBD; // for preset used_last
$mute-color: #dc3545;

// fonts
Expand Down
4 changes: 4 additions & 0 deletions web2/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export const router = createHashRouter([
path: 'sessions',
element: <Settings openPage="sessions" />,
},
{
path: 'presets',
element: <Settings openPage="presets" />,
},
{
path: 'config',
element: <Settings openPage="config" />,
Expand Down
34 changes: 22 additions & 12 deletions web2/src/pages/Home/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "./Home.scss";
import { useStatusStore } from '@/App.jsx'
import ZonesModal from "@/components/ZonesModal/ZonesModal";
import StreamsModal from "@/components/StreamsModal/StreamsModal";
import PresetsModal from "@/components/PresetsModal/PresetsModal";
import { useState } from "react";

export const getSourceZones = (source_id, zones) => {
Expand All @@ -15,23 +16,23 @@ export const getSourceZones = (source_id, zones) => {
return matches;
};

const Home = ({ selectedSource, setSelectedPage, setSelectedSource }) => {
const Home = ({ selectedSource, setSelectedSource }) => {
const sources = useStatusStore((s)=>s.status.sources)
const clearSourceZones = useStatusStore((s)=>s.clearSourceZones)
const [zonesModalOpen, setZonesModalOpen] = useState(false)
const [streamsModalOpen, setStreamsModalOpen] = useState(false)
let playerCards = [];
const [presetsModalOpen, setPresetsModalOpen] = useState(false)
let cards = [];
let nextAvailableSource = null;

sources.forEach((source, i) => {
if(source.input.toUpperCase() != "NONE" && source.input != "" && source.input != "local"){
playerCards.push(
cards.push(
<PlayerCard
key={i}
sourceId={source.id}
selectedSource={selectedSource}
setSelectedSource={setSelectedSource}
setSelectedPage={setSelectedPage}
/>
)
} else {
Expand All @@ -47,21 +48,30 @@ const Home = ({ selectedSource, setSelectedPage, setSelectedSource }) => {
setZonesModalOpen(true)
}

const PresetAndAdd = () => {
if (cards.length < sources.length) {
return (
<div className="home-presets-container">
<div className="home-add-player-button" onClick={()=>{initSource(nextAvailableSource)}}>+</div>
<div style={{width: '1.25rem'}} />
<div className="home-presets-button" onClick={()=>setPresetsModalOpen(true)}>Presets</div>
</div>
)
} else {
return <div className="home-presets-button" onClick={()=>setPresetsModalOpen(true)}>Presets</div>
}
}

return (
<div className="home-outer">
<div className="home-view">

{
playerCards
}

{playerCards.length < sources.length &&
<div className="home-add-player-button" onClick={()=>{initSource(nextAvailableSource)}}>+</div>
}
{cards}
<PresetAndAdd />
</div>

{zonesModalOpen && <ZonesModal sourceId={nextAvailableSource} setZoneModalOpen={(o)=>{setStreamsModalOpen(!o); setZonesModalOpen(o)}} onClose={()=>setZonesModalOpen(false)}/>}
{streamsModalOpen && <StreamsModal sourceId={nextAvailableSource} setStreamModalOpen={(o)=>setStreamsModalOpen(o)} onClose={()=>setStreamsModalOpen(false)}/>}
{presetsModalOpen && <PresetsModal onClose={()=>setPresetsModalOpen(false)}/>}

</div>

Expand Down
34 changes: 32 additions & 2 deletions web2/src/pages/Home/Home.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
width: fit-content;
}

.home-add-player-button{
.home-add-player-button {
width: 100%;
height: 5rem;
height: 4rem;
display: flex;
flex-direction: column;
justify-content: center;
Expand All @@ -30,3 +30,33 @@
border-radius: 1rem;
background-color: general.$bg;
}

.home-presets-button {
@include general.header-font;
font-size: 2rem;
width: 100%;
height: 4rem;
// padding-left: 1rem;
// padding-right: 1rem;
// padding-top: 0.1rem;
// padding-bottom: 0.1rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;

color: general.$controls-color;
border-color: general.$secondary;
border-style: solid;
border-radius: 1rem;
background-color: general.$bg;
}

.home-presets-container {
display: flex;

flex-direction: row;
justify-content: space-between;
align-items: center;
}

4 changes: 2 additions & 2 deletions web2/src/pages/Settings/Groups/GroupModal/GroupModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ const GroupModal = ({ group, zones, onClose, del, apply }) => {
})}
</Select>
<div className="group-buttons">
<IconButton onClick={()=>{if(del) del(); onClose()}}> <DeleteIcon className="group-button-icon" style={{width:"3rem", height:"3rem"}}/> </IconButton>
<IconButton onClick={()=>{apply(groupName, groupZones); onClose()}}> <DoneIcon className="group-button-icon" style={{width:"3rem", height:"3rem"}}/> </IconButton>
<IconButton onClick={()=>{if(del) del(); onClose()}}> <DeleteIcon className="group-button-icon" style={{width:"3rem", height:"3rem"}}/> </IconButton>
<IconButton onClick={()=>{apply(groupName, groupZones); onClose()}}> <DoneIcon className="group-button-icon" style={{width:"3rem", height:"3rem"}}/> </IconButton>
</div>
</div>
</Card>
Expand Down
2 changes: 0 additions & 2 deletions web2/src/pages/Settings/Groups/Groups.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import GroupModal from './GroupModal/GroupModal'

const GroupListItem = ({ group, zones }) => {
const [modalOpen, setModalOpen] = useState(false)
const [groupName, setGroupName] = useState(group.name)
const [groupZones, setGroupZones] = useState(group.zones)

const editGroup = (name, zones) => {
fetch('/api/groups/' + group.id, {method: "PATCH", headers: {"Content-type": "application/json"}, body: JSON.stringify({name: name, zones: zones})})
Expand Down
Loading

0 comments on commit a6cdf04

Please sign in to comment.