Merge remote-tracking branch 'origin/master' into mstratford-duck-when-honking
This commit is contained in:
commit
e63535658b
6 changed files with 88 additions and 39 deletions
|
@ -125,6 +125,10 @@ class Player extends ((PlayerEmitter as unknown) as { new (): EventEmitter }) {
|
|||
}
|
||||
}
|
||||
|
||||
getVolume() {
|
||||
return this.volume;
|
||||
}
|
||||
|
||||
setVolume(val: number) {
|
||||
this.volume = val;
|
||||
this._applyVolume();
|
||||
|
|
|
@ -509,7 +509,12 @@ export const load = (
|
|||
const itsChannel = getState()
|
||||
.showplan.plan!.filter((x) => x.channel === item.channel)
|
||||
.sort((x, y) => x.weight - y.weight);
|
||||
const itsIndex = itsChannel.indexOf(item);
|
||||
// Sadly, we can't just do .indexOf() item directly,
|
||||
// since the player's idea of an item may be changed over it's lifecycle (setting played,intro/cue/outro etc.)
|
||||
// Therefore we'll find the updated item from the plan and match that.
|
||||
const itsIndex = itsChannel.findIndex(
|
||||
(x) => itemId(x) === itemId(item)
|
||||
);
|
||||
if (itsIndex > -1 && itsIndex !== itsChannel.length - 1) {
|
||||
dispatch(load(player, itsChannel[itsIndex + 1]));
|
||||
}
|
||||
|
@ -596,14 +601,12 @@ export const stop = (player: number): AppThunk => (dispatch, getState) => {
|
|||
|
||||
let cueTime = 0;
|
||||
|
||||
console.log(Math.round(playerInstance.currentTime));
|
||||
if (
|
||||
state.loadedItem &&
|
||||
"cue" in state.loadedItem &&
|
||||
Math.round(playerInstance.currentTime) !== Math.round(state.loadedItem.cue)
|
||||
) {
|
||||
cueTime = state.loadedItem.cue;
|
||||
console.log(cueTime);
|
||||
}
|
||||
|
||||
playerInstance.stop();
|
||||
|
@ -677,7 +680,14 @@ export const setVolume = (
|
|||
const state = getState().mixer.players[player];
|
||||
|
||||
const currentLevel = state.volume;
|
||||
const currentGain = state.gain;
|
||||
let currentGain = state.gain;
|
||||
|
||||
// If we can, use the engine's 'real' volume gain.
|
||||
// This helps when we've interupted a previous fade, so the state gain won't be correct.
|
||||
if (typeof audioEngine.players[player] !== "undefined") {
|
||||
currentGain = audioEngine.players[player]!.getVolume();
|
||||
}
|
||||
|
||||
const volumeTween = new Between(currentLevel, uiLevel)
|
||||
.time(FADE_TIME_SECONDS * 1000)
|
||||
.on("update", (val: number) => {
|
||||
|
|
|
@ -14,18 +14,19 @@ export function ImporterModal(props: ImporterProps) {
|
|||
// Add support for closing the modal when the importer wants to reload the show plan.
|
||||
// There is a similar listener in showplanner/index.tsx to actually reload the show plan.
|
||||
useEffect(() => {
|
||||
window.addEventListener(
|
||||
"message",
|
||||
(event) => {
|
||||
if (!event.origin.includes("ury.org.uk")) {
|
||||
return;
|
||||
}
|
||||
if (event.data === "reload_showplan") {
|
||||
props.close();
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
function reloadListener(event: MessageEvent) {
|
||||
if (!event.origin.includes("ury.org.uk")) {
|
||||
return;
|
||||
}
|
||||
if (event.data === "reload_showplan") {
|
||||
props.close();
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("message", reloadListener);
|
||||
return () => {
|
||||
window.removeEventListener("message", reloadListener);
|
||||
};
|
||||
});
|
||||
return (
|
||||
<Modal isOpen={props.isOpen} onRequestClose={props.close}>
|
||||
|
|
|
@ -67,6 +67,8 @@ const setTrackIntro = (
|
|||
player: number
|
||||
): AppThunk => async (dispatch, getState) => {
|
||||
try {
|
||||
// Api only deals with whole seconds.
|
||||
secs = Math.round(secs);
|
||||
dispatch(MixerState.setLoadedItemIntro(player, secs));
|
||||
if (getState().settings.saveShowPlanChanges) {
|
||||
await api.setTrackIntro(track.trackid, secs);
|
||||
|
@ -84,6 +86,8 @@ const setTrackOutro = (
|
|||
player: number
|
||||
): AppThunk => async (dispatch, getState) => {
|
||||
try {
|
||||
// Api only deals with whole seconds.
|
||||
secs = Math.round(secs);
|
||||
dispatch(MixerState.setLoadedItemOutro(player, secs));
|
||||
if (getState().settings.saveShowPlanChanges) {
|
||||
await api.setTrackOutro(track.trackid, secs);
|
||||
|
@ -101,6 +105,8 @@ const setTrackCue = (
|
|||
player: number
|
||||
): AppThunk => async (dispatch, getState) => {
|
||||
try {
|
||||
// Api only deals with whole seconds.
|
||||
secs = Math.round(secs);
|
||||
dispatch(MixerState.setLoadedItemCue(player, secs));
|
||||
if (getState().settings.saveShowPlanChanges) {
|
||||
await api.setTimeslotItemCue(item.timeslotitemid, secs);
|
||||
|
@ -192,9 +198,17 @@ function TimingButtons({ id }: { id: number }) {
|
|||
}
|
||||
|
||||
export function Player({ id }: { id: number }) {
|
||||
// Define time remaining (secs) when the play icon should flash.
|
||||
const SECS_REMAINING_WARNING = 20;
|
||||
|
||||
// We want to force update the selector when we pass the SECS_REMAINING_WARNING barrier.
|
||||
const playerState = useSelector(
|
||||
(state: RootState) => state.mixer.players[id],
|
||||
(a, b) =>
|
||||
!(
|
||||
a.timeRemaining <= SECS_REMAINING_WARNING &&
|
||||
b.timeRemaining > SECS_REMAINING_WARNING
|
||||
) &&
|
||||
shallowEqual(
|
||||
omit(a, "timeCurrent", "timeRemaining"),
|
||||
omit(b, "timeCurrent", "timeRemaining")
|
||||
|
@ -222,11 +236,15 @@ export function Player({ id }: { id: number }) {
|
|||
}
|
||||
};
|
||||
|
||||
var duration: number = 0;
|
||||
let channelDuration = 0;
|
||||
let channelUnplayed = 0;
|
||||
const plan = useSelector((state: RootState) => state.showplan.plan);
|
||||
plan?.forEach((pItem) => {
|
||||
if (pItem.channel === id) {
|
||||
duration += HHMMTosec(pItem.length);
|
||||
channelDuration += HHMMTosec(pItem.length);
|
||||
if (!pItem.played) {
|
||||
channelUnplayed += HHMMTosec(pItem.length);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -239,6 +257,14 @@ export function Player({ id }: { id: number }) {
|
|||
}
|
||||
>
|
||||
<div className="card text-center">
|
||||
<div className="d-inline mx-1">
|
||||
<span className="float-left">
|
||||
Total: {secToHHMM(channelDuration)}
|
||||
</span>
|
||||
<span className="float-right">
|
||||
Unplayed: {secToHHMM(channelUnplayed)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="row m-0 p-1 card-header channelButtons hover-menu">
|
||||
<span className="hover-label">Channel Controls</span>
|
||||
<button
|
||||
|
@ -278,7 +304,6 @@ export function Player({ id }: { id: number }) {
|
|||
<FaRedo />
|
||||
Repeat {playerState.repeat}
|
||||
</button>
|
||||
<div>Total Time: {secToHHMM(duration)}</div>
|
||||
</div>
|
||||
{proMode && <ProModeButtons channel={id} />}
|
||||
<div className="card-body p-0">
|
||||
|
@ -319,7 +344,7 @@ export function Player({ id }: { id: number }) {
|
|||
onClick={() => dispatch(MixerState.play(id))}
|
||||
className={
|
||||
playerState.state === "playing"
|
||||
? playerState.timeRemaining <= 15
|
||||
? playerState.timeRemaining <= SECS_REMAINING_WARNING
|
||||
? "sp-state-playing sp-ending-soon"
|
||||
: "sp-state-playing"
|
||||
: ""
|
||||
|
|
|
@ -20,8 +20,14 @@ export default function ProModeButtons({ channel }: { channel: number }) {
|
|||
<>
|
||||
<div className="row m-0 p-1 card-header channelButtons proMode hover-menu">
|
||||
<span className="hover-label">Pro Mode™</span>
|
||||
<button className="mr-1 btn btn-warning" title="Trim">
|
||||
<FaTachometerAlt onClick={() => setActiveButton("trim")} />
|
||||
<button
|
||||
className="mr-1 btn btn-warning"
|
||||
title="Trim"
|
||||
onClick={() =>
|
||||
setActiveButton(activeButton === "trim" ? null : "trim")
|
||||
}
|
||||
>
|
||||
<FaTachometerAlt />
|
||||
</button>
|
||||
<button
|
||||
className={
|
||||
|
@ -46,9 +52,10 @@ export default function ProModeButtons({ channel }: { channel: number }) {
|
|||
max={12}
|
||||
step={0.2}
|
||||
value={trimVal.toFixed(1)}
|
||||
onChange={(e) =>
|
||||
dispatch(setChannelTrim(channel, parseFloat(e.target.value)))
|
||||
}
|
||||
onChange={(e) => {
|
||||
dispatch(setChannelTrim(channel, parseFloat(e.target.value)));
|
||||
e.target.blur(); // Stop dragging from disabling the keyboard triggers.
|
||||
}}
|
||||
/>
|
||||
<strong className="mt-2">{trimVal} dB</strong>
|
||||
</>
|
||||
|
|
|
@ -389,20 +389,22 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
|
|||
// Add support for reloading the show plan from the iFrames.
|
||||
// There is a similar listener in showplanner/ImporterModal.tsx to handle closing the iframe.
|
||||
useEffect(() => {
|
||||
window.addEventListener(
|
||||
"message",
|
||||
(event) => {
|
||||
if (!event.origin.includes("ury.org.uk")) {
|
||||
return;
|
||||
}
|
||||
if (event.data === "reload_showplan") {
|
||||
session.currentTimeslot !== null &&
|
||||
dispatch(getShowplan(session.currentTimeslot.timeslot_id));
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
});
|
||||
function reloadListener(event: MessageEvent) {
|
||||
if (!event.origin.includes("ury.org.uk")) {
|
||||
return;
|
||||
}
|
||||
if (event.data === "reload_showplan") {
|
||||
session.currentTimeslot !== null &&
|
||||
dispatch(getShowplan(session.currentTimeslot.timeslot_id));
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("message", reloadListener);
|
||||
return () => {
|
||||
window.removeEventListener("message", reloadListener);
|
||||
};
|
||||
}, [dispatch, session.currentTimeslot]);
|
||||
|
||||
if (showplan === null) {
|
||||
return (
|
||||
<LoadingDialogue
|
||||
|
|
Loading…
Reference in a new issue