Skip to content

Commit

Permalink
🎵 Fixed slide play MIDI
Browse files Browse the repository at this point in the history
  • Loading branch information
vassbo committed Jun 23, 2024
1 parent a484076 commit 4b9f70d
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 124 deletions.
16 changes: 13 additions & 3 deletions src/frontend/components/actions/midi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import { updateOut } from "../helpers/showActions"
import { _show } from "../helpers/shows"
import { runAction } from "./actions"
import { newToast } from "../../utils/common"
import { loadShows } from "../helpers/setShow"

export function midiInListen() {
Object.entries(get(midiIn)).forEach(([id, action]: any) => {
action = convertOldMidiToNewAction(action)
console.log("LISTEN", action)
if (!action.midi) return

if (!action.shows?.length) {
Expand All @@ -22,15 +24,23 @@ export function midiInListen() {
return
}

action.shows.forEach((show) => {
if (!shows[show.id]) return
action.shows.forEach(async (show) => {
if (!get(shows)[show.id]) return

// find all slides in current show with this MIDI
await loadShows([show.id])

// check that current show actually has this MIDI receive action
let layouts: any[] = _show(show.id).layouts().get()
let found: boolean = false
layouts.forEach((layout) => {
layout.slides.forEach((slide) => {
if (slide.actions?.receiveMidi === id) found = true

if (slide.children) {
Object.values(slide.children).forEach((child: any) => {
if (child.actions?.receiveMidi === id) found = true
})
}
})
})

Expand Down
2 changes: 1 addition & 1 deletion src/frontend/components/context/loadItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const loadActions = {

let slideActions = [
{ id: "action", label: "midi.start_action", icon: "actions" },
{ id: "receiveMidi", label: "actions.play_on_midi", icon: "play" },
{ id: "receiveMidi", label: "actions.play_on_midi", icon: "play", enabled: currentActions?.receiveMidi || false },
"SEPERATOR",
{ id: "nextTimer", label: "preview.nextTimer", icon: "clock", enabled: Number(slideRef?.data?.nextTimer || 0) || false },
{ id: "loop", label: "preview.to_start", icon: "restart", enabled: slideRef?.data?.end || false },
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/components/context/menuClick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ function changeSlideAction(obj: any, id: string) {

history({ id: "SHOW_LAYOUT", newData: { key: "actions", data: actions, indexes: [layoutSlide] } })

let data: any = { id: midiId, mode: "slide_midi" } // , index: layoutSlide
let data: any = { id: midiId, index: layoutSlide, mode: "slide_midi" } // , index: layoutSlide

popupData.set(data)
activePopup.set("action")
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/components/drawer/bible/Scripture.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,8 @@
$: if (chaptersScrollElem && active && chapterId) setTimeout(() => scrollToActive(chaptersScrollElem))
$: if (versesScrollElem && active && activeVerses?.length < 5) setTimeout(() => scrollToActive(versesScrollElem))
function scrollToActive(scrollElem) {
if (!scrollElem) return
let selectedElemTop = scrollElem.querySelector(".active")?.offsetTop || 0
scrollElem.scrollTo(0, Math.max(0, selectedElemTop - 70))
}
Expand Down
23 changes: 14 additions & 9 deletions src/frontend/components/drawer/pages/Actions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
export let searchValue
console.log(searchValue)
function openMidi(id: string) {
popupData.set({ id })
function openMidi(id: string, mode: string = "") {
let data: any = { id }
if (mode) data.mode = mode
popupData.set(data)
activePopup.set("action")
}
Expand Down Expand Up @@ -46,16 +49,20 @@
<!-- WIP MIDI if slide action.action ... -->
<Button title={$dictionary.media?.play} on:click={() => runAction(action)} dark>
<span style="display: flex;align-items: center;width: 100%;">
{#if action.triggers === undefined}
<Icon id="slide" right />
{#if action.shows?.length}
<Icon id="slide" white right />
{:else if action.triggers.length !== 1}
<Icon id="actions" right />
{:else}
<Icon id={actionData[action.triggers[0]]?.icon || "actions"} right />
{/if}

<p style="width: 350px;" class:customActivation={action.customActivation || action.startupEnabled}>
{action.name}
{#if action.shows?.length}
<T id="actions.play_on_midi" />
{:else}
{action.name || ""}
{/if}

{#if action.midi}
({action.midi.input || ""})
Expand All @@ -73,13 +80,11 @@
{/if}
</span>

<!-- WIP MIDI remove this way shows midi action... -->
<p style="opacity: 0.5;font-style: italic;">{action.triggers === undefined ? action.shows.length : ""}</p>
<p style="opacity: 0.5;font-style: italic;">{action.shows?.length > 1 ? action.shows.length : ""}</p>
</Button>
</SelectElem>

<!-- WIP MIDI , !!action.shows?.length -->
<Button title={$dictionary.timer?.edit} on:click={() => openMidi(action.id)}>
<Button title={$dictionary.timer?.edit} on:click={() => openMidi(action.id, action.shows?.length ? "slide_midi" : "")}>
<Icon id="edit" />
</Button>
<Button title={$dictionary.actions?.delete} on:click={() => deleteMidi(action.id)}>
Expand Down
10 changes: 7 additions & 3 deletions src/frontend/components/main/popups/Action.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
let action: any = { name: "", triggers: [] }
let actionMidi: API_midi = { type: "noteon", values: { note: 0, velocity: mode === "slide" ? 0 : -1, channel: 1 }, defaultValues: true }
let loaded: boolean = false
onMount(setAction)
function setAction() {
if (!id) {
Expand All @@ -50,6 +51,8 @@
}
if (mode === "slide_midi") action.midiEnabled = true
loaded = true
}
// saveSlide(true)
Expand Down Expand Up @@ -109,7 +112,6 @@
if (e.detail.actionValue) {
if (!action.actionValues) action.actionValues = {}
action.actionValues[actionId] = e.detail.actionValue
saveAction()
return
}
Expand Down Expand Up @@ -156,7 +158,8 @@
// WIP MIDI remove unused / empty actions from slide
$: if (action) saveAction()
function saveAction() {
if (!action.name) return
if (!loaded) return
if (mode !== "slide_midi" && mode !== "slide" && mode !== "template" && !action.name) return
if (action.midiEnabled && !action.midi) action.midi = actionMidi
Expand All @@ -178,11 +181,12 @@
} else if (mode !== "slide") {
midiIn.update((a) => {
if (mode === "slide_midi") {
// WIP MIDI this should show up in the "Actions" tab
let shows = a[id]?.shows || []
let showId = $popupData.index === undefined ? "" : $activeShow?.id || ""
if (showId && !shows.find((a) => a.id === showId)) shows.push({ id: showId })
action.shows = shows
if (action.midi?.defaultValues) delete action.midi.defaultValues
}
a[id] = clone(action)
Expand Down
197 changes: 99 additions & 98 deletions src/frontend/components/main/popups/EditEvent.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@
}
// set show when selected
$: console.log(actionData, $popupData)
$: if ($popupData.showId) setTimeout(setShow, 100)
function setShow() {
editEvent = $popupData.event
Expand All @@ -256,119 +255,121 @@
}
</script>

{#if selectedType === "event"}
<div style="min-width: 45vw;min-height: 50vh;">
{#if selectedType === "event"}
<CombinedInput textWidth={30}>
<p><T id="calendar.time" /></p>
<div class="alignRight">
<Checkbox checked={editEvent.time} on:change={(e) => check(e, "time")} />
</div>
</CombinedInput>
{/if}

<!-- TODO: update totime if fromtime is newer -->
<CombinedInput textWidth={30}>
<p><T id="calendar.time" /></p>
<div class="alignRight">
<Checkbox checked={editEvent.time} on:change={(e) => check(e, "time")} />
<p><T id="timer.from" /></p>
<div style="display: flex;">
<input style="flex: 2;" type="date" title={$dictionary.calendar?.from_date} bind:value={editEvent.isoFrom} />
<input style="flex: 1;" type="time" title={$dictionary.calendar?.from_time} bind:value={editEvent.fromTime} on:change={() => updateTime("from")} disabled={!editEvent.time} />
</div>
</CombinedInput>
{/if}

<!-- TODO: update totime if fromtime is newer -->
<CombinedInput textWidth={30}>
<p><T id="timer.from" /></p>
<div style="display: flex;">
<input style="flex: 2;" type="date" title={$dictionary.calendar?.from_date} bind:value={editEvent.isoFrom} />
<input style="flex: 1;" type="time" title={$dictionary.calendar?.from_time} bind:value={editEvent.fromTime} on:change={() => updateTime("from")} disabled={!editEvent.time} />
</div>
</CombinedInput>
{#if selectedType === "event"}
{#if selectedType === "event"}
<CombinedInput textWidth={30}>
<p><T id="timer.to" /></p>
<div style="display: flex;">
<input style="flex: 2;" type="date" title={$dictionary.calendar?.to_date} bind:value={editEvent.isoTo} />
<input style="flex: 1;" type="time" title={$dictionary.calendar?.to_time} bind:value={editEvent.toTime} on:change={() => updateTime("to")} disabled={!editEvent.time} />
</div>
</CombinedInput>
{/if}

<CombinedInput textWidth={30}>
<p><T id="timer.to" /></p>
<div style="display: flex;">
<input style="flex: 2;" type="date" title={$dictionary.calendar?.to_date} bind:value={editEvent.isoTo} />
<input style="flex: 1;" type="time" title={$dictionary.calendar?.to_time} bind:value={editEvent.toTime} on:change={() => updateTime("to")} disabled={!editEvent.time} />
<p><T id="calendar.repeat" /></p>
<div class="alignRight">
<Checkbox disabled={editEvent.group} checked={editEvent.repeat} on:change={(e) => check(e, "repeat")} />
</div>
</CombinedInput>
{/if}

<CombinedInput textWidth={30}>
<p><T id="calendar.repeat" /></p>
<div class="alignRight">
<Checkbox disabled={editEvent.group} checked={editEvent.repeat} on:change={(e) => check(e, "repeat")} />
</div>
</CombinedInput>

{#if editEvent.repeat}
<CombinedInput textWidth={30}>
<div style="display: flex;">
<span style="display: flex;align-items: center;padding: 0 10px;"><T id="calendar.repeat_every" /></span>
<NumberInput disabled={!!editEvent.group} style="width: 50px;" value={editEvent.repeatData.count} min={1} buttons={false} on:change={(e) => (editEvent.repeatData.count = e.detail)} />
<Dropdown disabled={!!editEvent.group} style="width: 100px;" options={repeats} value={repeats.find((a) => a.id === editEvent.repeatData.type)?.name || ""} on:click={(e) => (editEvent.repeatData.type = e.detail.id)} />
<!-- TODO: select weekdays? -->
<!-- {#if selectedRepeat.id === "week"}
{#if editEvent.repeat}
<CombinedInput textWidth={30}>
<div style="display: flex;">
<span style="display: flex;align-items: center;padding: 0 10px;"><T id="calendar.repeat_every" /></span>
<NumberInput disabled={!!editEvent.group} style="width: 50px;" value={editEvent.repeatData.count} min={1} buttons={false} on:change={(e) => (editEvent.repeatData.count = e.detail)} />
<Dropdown disabled={!!editEvent.group} style="width: 100px;" options={repeats} value={repeats.find((a) => a.id === editEvent.repeatData.type)?.name || ""} on:click={(e) => (editEvent.repeatData.type = e.detail.id)} />
<!-- TODO: select weekdays? -->
<!-- {#if selectedRepeat.id === "week"}
<span style="display: flex;align-items: center;padding: 0 10px;"><T id="calendar.repeat_on" /></span>
<Dropdown style="width: 100px;" options={weekdays} value={selectedWeekday.name} on:click={(e) => (selectedWeekday = e.detail)} />
{/if} -->
<span style="display: flex;align-items: center;padding: 0 10px;"><T id="calendar.repeat_until" /></span>
<Dropdown disabled={!!editEvent.group} style="width: 130px;" options={endings} value={endings.find((a) => a.id === editEvent.repeatData.ending)?.name || ""} on:click={(e) => (editEvent.repeatData.ending = e.detail.id)} />

{#if editEvent.repeatData.ending === "date"}
<input disabled={!!editEvent.group} type="date" bind:value={editEvent.repeatData.endingDate} />
{:else if editEvent.repeatData.ending === "after"}
<NumberInput disabled={!!editEvent.group} style="width: 50px;" value={editEvent.repeatData.afterRepeats} min={1} buttons={false} on:change={(e) => (editEvent.repeatData.afterRepeats = e.detail)} />
<span style="display: flex;align-items: center;padding: 0 10px;"><T id="calendar.ending_times" /></span>
{/if}
</div>
</CombinedInput>
{/if}

{#if selectedType === "event"}
<CombinedInput textWidth={30} style="margin-top: 10px;">
<p>
<Icon id="edit" size={1.2} right />
<T id="calendar.name" />
</p>
<TextInput value={editEvent.name} style="width: 50%;" on:input={(e) => inputChange(e, "name")} />
</CombinedInput>

<CombinedInput textWidth={30}>
<p>
<Icon id="theme" size={1.2} right />
<T id="calendar.color" />
</p>
<Color value={editEvent.color} on:input={(e) => (editEvent.color = e.detail)} style="width: 50%;" />
</CombinedInput>

<CombinedInput textWidth={30}>
<p>
<Icon id="location" size={1.2} right />
<T id="calendar.location" />
</p>
<TextInput value={editEvent.location || ""} style="width: 50%;" on:input={(e) => inputChange(e, "location")} />
</CombinedInput>
<span style="display: flex;align-items: center;padding: 0 10px;"><T id="calendar.repeat_until" /></span>
<Dropdown disabled={!!editEvent.group} style="width: 130px;" options={endings} value={endings.find((a) => a.id === editEvent.repeatData.ending)?.name || ""} on:click={(e) => (editEvent.repeatData.ending = e.detail.id)} />

{#if editEvent.repeatData.ending === "date"}
<input disabled={!!editEvent.group} type="date" bind:value={editEvent.repeatData.endingDate} />
{:else if editEvent.repeatData.ending === "after"}
<NumberInput disabled={!!editEvent.group} style="width: 50px;" value={editEvent.repeatData.afterRepeats} min={1} buttons={false} on:change={(e) => (editEvent.repeatData.afterRepeats = e.detail)} />
<span style="display: flex;align-items: center;padding: 0 10px;"><T id="calendar.ending_times" /></span>
{/if}
</div>
</CombinedInput>
{/if}

{#if selectedType === "event"}
<CombinedInput textWidth={30} style="margin-top: 10px;">
<p>
<Icon id="edit" size={1.2} right />
<T id="calendar.name" />
</p>
<TextInput value={editEvent.name} style="width: 50%;" on:input={(e) => inputChange(e, "name")} />
</CombinedInput>

<CombinedInput textWidth={30}>
<p>
<Icon id="theme" size={1.2} right />
<T id="calendar.color" />
</p>
<Color value={editEvent.color} on:input={(e) => (editEvent.color = e.detail)} style="width: 50%;" />
</CombinedInput>

<CombinedInput textWidth={30}>
<p>
<Icon id="location" size={1.2} right />
<T id="calendar.location" />
</p>
<TextInput value={editEvent.location || ""} style="width: 50%;" on:input={(e) => inputChange(e, "location")} />
</CombinedInput>

<CombinedInput textWidth={30}>
<p>
<Icon id="notes" size={1.2} right />
<T id="calendar.notes" />
</p>
<TextInput value={editEvent.notes || ""} style="width: 50%;" on:input={(e) => inputChange(e, "notes")} />
</CombinedInput>
{:else if selectedType === "action"}
<br />
{#key actionData}
<CreateAction actionId={actionData?.id || ""} actionValue={actionData?.data || {}} on:change={changeAction} />
{/key}
{/if}

<CombinedInput textWidth={30}>
<p>
<Icon id="notes" size={1.2} right />
<T id="calendar.notes" />
</p>
<TextInput value={editEvent.notes || ""} style="width: 50%;" on:input={(e) => inputChange(e, "notes")} />
</CombinedInput>
{:else if selectedType === "action"}
<br />
{#key actionData}
<CreateAction actionId={actionData?.id || ""} actionValue={actionData?.data || {}} on:change={changeAction} />
{/key}
{/if}

<br />

<CombinedInput>
<Button style="width: 100%;" on:click={save} disabled={selectedType === "event" ? !editEvent.name?.length || stored === JSON.stringify(editEvent) : selectedType === "action" ? !actionData : true} dark center>
<Icon id="save" right />
<T id="actions.save" />
</Button>
</CombinedInput>
{#if editEvent.group}

<CombinedInput>
<Button style="width: 100%;" on:click={saveAll} disabled={selectedType === "event" ? !editEvent.name?.length || stored === JSON.stringify(editEvent) : selectedType === "action" ? !actionData : true} dark center>
<Button style="width: 100%;" on:click={save} disabled={selectedType === "event" ? !editEvent.name?.length || stored === JSON.stringify(editEvent) : selectedType === "action" ? !actionData : true} dark center>
<Icon id="save" right />
<T id="calendar.save_all" />
<T id="actions.save" />
</Button>
</CombinedInput>
{/if}
{#if editEvent.group}
<CombinedInput>
<Button style="width: 100%;" on:click={saveAll} disabled={selectedType === "event" ? !editEvent.name?.length || stored === JSON.stringify(editEvent) : selectedType === "action" ? !actionData : true} dark center>
<Icon id="save" right />
<T id="calendar.save_all" />
</Button>
</CombinedInput>
{/if}
</div>

<style>
input[type="date"],
Expand Down
Loading

0 comments on commit 4b9f70d

Please sign in to comment.