Skip to content

Commit

Permalink
✨ UI enhancements
Browse files Browse the repository at this point in the history
- Group templates
- Slide template can update without a show template
- You can now delete files synced to drive
- Fixed caret resetting when line is removed
- Bug fixes
  • Loading branch information
vassbo committed Jun 25, 2024
1 parent b2c67ae commit 9150c26
Show file tree
Hide file tree
Showing 44 changed files with 279 additions and 103 deletions.
7 changes: 5 additions & 2 deletions public/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@
"slide": "Clear slide",
"overlays": "Clear overlays",
"audio": "Clear audio",
"nextTimer": "Clear next slide timer"
"nextTimer": "Clear next slide timer",
"drawing": "Clear drawing"
},
"remove": {
"background": "Remove background",
Expand Down Expand Up @@ -509,7 +510,7 @@
"add_color": "Add color",
"format": "Format",
"find_replace": "Find and replace text",
"cut_in_half": "Cut in half",
"cut_in_half": "Split in two",
"find": "Find",
"replace": "Replace",
"case_sensitive": "Case sensitive",
Expand Down Expand Up @@ -580,6 +581,7 @@
"activate_slide_clicked": "Activate on slide click",
"activate_video_starting": "Activate when video is starting",
"activate_video_ending": "Activate when video is ending",
"activate_timer_ending": "Activate when timer is ending",
"activate_scripture_start": "Activate when scripture is started",
"activate_show_created": "Activate when show is created"
},
Expand Down Expand Up @@ -939,6 +941,7 @@
"full_colors": "Full slide group colors",
"auto_output": "Activate output screen on startup",
"hide_cursor_in_output": "Hide cursor in output",
"clear_media_when_finished": "Clear media when finished",
"disable_presenter_controller_keys": "Disable presenter controller keys",
"default_project_name": "Default project name",
"audio_fade_duration": "Audio fade duration",
Expand Down
39 changes: 33 additions & 6 deletions src/electron/cloud/drive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from "path"
import { isProd, toApp } from ".."
import { STORE } from "../../types/Channels"
import { stores } from "../data/store"
import { checkShowsFolder, dataFolderNames, deleteFile, getDataFolder, getFileStats, loadShows, readFile, writeFile } from "../utils/files"
import { checkShowsFolder, dataFolderNames, deleteFile, doesPathExist, getDataFolder, getFileStats, loadShows, readFile, writeFile } from "../utils/files"
import { trimShow } from "../utils/responses"

let driveClient: any = null
Expand Down Expand Up @@ -169,6 +169,7 @@ const SHOWS_CONTENT = "SHOWS_CONTENT"
const storesToSave = ["EVENTS", "OVERLAYS", "PROJECTS", "SYNCED_SETTINGS", "STAGE_SHOWS", "TEMPLATES", "THEMES", "MEDIA"]
// don't upload: settings.json, config.json, cache.json, history.json

export let currentlyDeletedShows: string[] = []
export async function syncDataDrive(data: any) {
let files = await listFiles(20, "'" + data.mainFolderId + "' in parents")
if (files === null) return { error: "Error: Could not get files! Have you shared a folder with the service account?" }
Expand Down Expand Up @@ -371,8 +372,36 @@ export async function syncDataDrive(data: any) {
}
}

if ((newest === "cloud" || data.method === "download") && cloudContent) allShows[id] = driveContent[id]
else if (localContent) {
if ((newest === "cloud" || data.method === "download") && cloudContent) {
// deleted locally
if (currentlyDeletedShows.includes(id)) {
allShows[id] = { deleted: true, name: driveContent[id]?.name || "" }

delete shows[id]
uploadCount++
if (DEBUG) console.log("Show has been deleted from cloud:", driveContent[id]?.name || "")

return
}

allShows[id] = driveContent[id]

// if a show is deleted, synced and undone it can't be restored unless a duplicate is created with new ID!
// but it can be restored when deleted before it's synced
// deleted in cloud
if (driveContent[id].deleted === true) {
let p: string = path.join(showsPath, name)
if (doesPathExist(p)) {
deleteFile(p)
downloadCount++
if (DEBUG) console.log("Show has been deleted locally:", driveContent[id]?.name || "")
}

delete shows[id]

return
}
} else if (localContent) {
try {
allShows[id] = JSON.parse(localContent)[1]
} catch (err) {
Expand All @@ -383,9 +412,6 @@ export async function syncDataDrive(data: any) {

if (cloudContent && localContent === cloudContent) return

// TODO: deleted files are not deleted in cloud
// popup: found some show files not in the cloud: sync(upload) or delete

// "download" show
if (cloudContent && (newest === "cloud" || data.method === "download") && data.method !== "upload") {
let newName = (show?.name || id) + ".show"
Expand Down Expand Up @@ -434,6 +460,7 @@ export async function syncDataDrive(data: any) {
if (DEBUG) console.log("Drive shows:", Object.keys(allShows).length)
let file = createFile(data.mainFolderId, { type: "json", name }, JSON.stringify(allShows))
let response = await uploadFile(file, driveFileId)
currentlyDeletedShows = []

if (response?.status != 200) {
changes.push({ type: "show", action: "upload_failed", name })
Expand Down
5 changes: 5 additions & 0 deletions src/electron/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { stopMidi } from "./utils/midi"
import { catchErrors, loadScripture, loadShow, receiveMain, renameShows, saveRecording, startImport } from "./utils/responses"
import { loadingOptions, mainOptions } from "./utils/windowOptions"
import { startExport } from "./data/export"
import { currentlyDeletedShows } from "./cloud/drive"

// ----- STARTUP -----

Expand Down Expand Up @@ -325,8 +326,12 @@ function save(data: any) {
if (data.deletedShows) data.deletedShows.forEach(deleteShow)
function deleteShow({ name, id }: any) {
if (!name || data.showsCache[id]) return

let p: string = path.join(data.path, (name || id) + ".show")
deleteFile(p)

// update cloud
currentlyDeletedShows.push(id)
}

// SAVED
Expand Down
6 changes: 4 additions & 2 deletions src/electron/output/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ function createOutputWindow(options: any, id: string, name: string) {
window.setSkipTaskbar(options.skipTaskbar) // hide from taskbar
if (isMac) window.minimize() // hide on mac

if (options.alwaysOnTop) window.setAlwaysOnTop(true, "pop-up-menu", 1)
window.once("show", () => {
if (options.alwaysOnTop) window?.setAlwaysOnTop(true, "pop-up-menu", 1)
})
// window.setVisibleOnAllWorkspaces(true)

loadWindowContent(window, true)
Expand Down Expand Up @@ -245,7 +247,7 @@ const setValues: any = {
window.setBackgroundColor(value ? "#00000000" : "#000000")
},
alwaysOnTop: (value: boolean, window: BrowserWindow) => {
window.setAlwaysOnTop(value)
window.setAlwaysOnTop(value, "pop-up-menu", 1)
window.setResizable(!value)
window.setSkipTaskbar(value)
},
Expand Down
8 changes: 7 additions & 1 deletion src/frontend/components/context/ContextItem.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { activeProject, activeRecording, activeShow, events, forceClock, media, os, overlays, redoHistory, scriptures, selected, shows, stageShows, undoHistory } from "../../stores"
import { activeProject, activeRecording, activeShow, events, forceClock, media, os, overlays, redoHistory, scriptures, selected, shows, slidesOptions, stageShows, undoHistory } from "../../stores"
import Icon from "../helpers/Icon.svelte"
import { _show } from "../helpers/shows"
import T from "../helpers/T.svelte"
Expand All @@ -15,6 +15,12 @@
let enabled: boolean = menu?.enabled ? true : false
const conditions: any = {
// slide views
view_grid: () => ($slidesOptions.mode === "grid" ? (enabled = true) : ""),
view_simple: () => ($slidesOptions.mode === "simple" ? (enabled = true) : ""),
view_list: () => ($slidesOptions.mode === "list" ? (enabled = true) : ""),
view_lyrics: () => ($slidesOptions.mode === "lyrics" ? (enabled = true) : ""),
view_text: () => ($slidesOptions.mode === "text" ? (enabled = true) : ""),
private: () => {
if (!$shows[$selected.data[0]?.id]?.private) return
enabled = $shows[$selected.data[0].id].private
Expand Down
6 changes: 3 additions & 3 deletions src/frontend/components/draw/DrawSettings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@
</div>

{#if $drawTool === "paint"}
<Button style="flex: 1;" on:click={() => update("clear", true)} dark center>
<Icon id="clear" right />
<T id="clear.all" />
<Button style="flex: 1;padding: 10px;" on:click={() => update("clear", true)} dark center>
<Icon id="clear" size={2} right />
<T id="clear.drawing" />
</Button>
{/if}

Expand Down
9 changes: 5 additions & 4 deletions src/frontend/components/drawer/Drawer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@
<section class="drawer" style="height: {height}px">
<div class="top context #drawer_top" on:mousedown={mousedown} on:click={click}>
<span class="tabs">
{#each tabs as tab}
{#each tabs as tab, i}
{#if $drawerTabsData[tab.id]?.enabled !== false}
<Button id={tab.id} on:click={() => openDrawerTab(tab)} active={$activeDrawerTab === tab.id} class="context #drawer_top" title={$labelsDisabled ? $dictionary[tab.name.split(".")[0]]?.[tab.name.split(".")[1]] : ""}>
<Button id={tab.id} on:click={() => openDrawerTab(tab)} active={$activeDrawerTab === tab.id} class="context #drawer_top" title="{$dictionary[tab.name.split('.')[0]]?.[tab.name.split('.')[1]]} [Ctrl+{i + 1}]">
<Icon id={tab.icon} size={1.3} />
{#if !$labelsDisabled}
<span><T id={tab.name} /></span>
Expand All @@ -165,8 +165,9 @@
</span>
<input bind:this={searchElem} class:hidden={!searchActive && !searchValue.length} class="search edit" type="text" placeholder={$dictionary.main?.search} bind:value={searchValue} on:input={search} use:selectTextOnFocus />
{#if !searchActive && !searchValue.length}
<Button on:click={() => (searchActive = true)} title={$dictionary.main?.search}>
<Icon id="search" size={1.3} white />
<Button on:click={() => (searchActive = true)} title="{$dictionary.main?.search} [Ctrl+F]" bold={false}>
<Icon id="search" size={1.3} white right={!$labelsDisabled} />
{#if !$labelsDisabled}<p style="opacity: 0.8;"><T id="main.search" /></p>{/if}
</Button>
{/if}
</div>
Expand Down
20 changes: 15 additions & 5 deletions src/frontend/components/drawer/bible/Scripture.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,8 @@
searchInBible(e)
}
let previousSearch: string = ""
let cachedSearches: number = 0
async function searchInBible(e: any) {
contentSearch = e.target?.value || ""
contentSearchActive = false
Expand All @@ -463,12 +465,18 @@
let matches: any[] = []
let extraMatches: any[] = []
if (bible.api) {
let searchValue = formatText(contentSearch)
// if new search includes previous search, then just search through previously filtered data
// Bible.API will only give a fixed result, so search that again when "cachedSearches" is more than 5
if (previousSearch && searchValue.includes(previousSearch) && (!bible.api || cachedSearches < 5)) {
matches = contentSearchMatches.filter((a) => a.text.includes(searchValue))
cachedSearches++
} else if (bible.api) {
let searchResult: any = await searchBibleAPI(active, contentSearch)
matches = searchResult?.verses?.map((a) => ({ book: a.bookId, chapter: a.chapterId, verse: a.reference.slice(a.reference.indexOf(":") + 1), reference: a.reference, text: a.text, api: true }))
} else {
let allBooks: any[] = books[firstBibleId]
let searchValue = formatText(contentSearch)
allBooks.forEach((book, bookIndex) => {
book.chapters.forEach((chapter, chapterIndex) => {
chapter.verses.forEach((verse) => {
Expand All @@ -483,16 +491,17 @@
})
})
})
}
function formatText(text: string) {
return text.toLowerCase().replace(/[`!*()-?;:'",.]/gi, "")
}
function formatText(text: string) {
return text.toLowerCase().replace(/[`!*()-?;:'",.]/gi, "")
}
matches.push(...extraMatches)
contentSearchMatches = matches
contentSearchActive = true
previousSearch = searchValue
if (!tempCache[firstBibleId]) tempCache[firstBibleId] = {}
tempCache[firstBibleId][contentSearch] = matches
Expand Down Expand Up @@ -650,6 +659,7 @@
if (!e.ctrlKey && !e.metaKey) return
if (e.key === "r") {
if (!outputIsScripture) return
e.preventDefault()
playOrClearScripture(true)
return
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/components/drawer/bible/scripture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export function getSlides({ bibles, sorted }) {
if (get(scriptureSettings).redJesus) {
let jesusWords: any[] = []
let jesusStart = text.indexOf('<span class="wj"')
if (jesusStart < 0) jesusStart = text.indexOf("<red")

while (jesusStart > -1) {
let jesusEnd = 0
Expand All @@ -178,6 +179,7 @@ export function getSlides({ bibles, sorted }) {
if (jesusEnd) {
jesusWords.push([jesusStart, jesusEnd])
jesusStart = text.indexOf('<span class="wj"', jesusEnd)
if (jesusStart < 0) jesusStart = text.indexOf("<red", jesusEnd)
} else {
jesusWords.push([jesusStart, text.length])
jesusStart = -1
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/components/drawer/info/ScriptureInfo.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
update("customText", customText)
}
$: containsJesusWords = Object.values(bibles?.[0]?.verses || {})?.find((text: any) => text?.includes('<span class="wj"'))
$: containsJesusWords = Object.values(bibles?.[0]?.verses || {})?.find((text: any) => text?.includes('<span class="wj"') || text?.includes("<red"))
</script>

<svelte:window on:keydown={keydown} />
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/components/drawer/pages/Actions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<div class="action">
<SelectElem id="action" data={action} style="display: flex;flex: 1;" draggable>
<!-- WIP MIDI if slide action.action ... -->
<Button title={$dictionary.media?.play} on:click={() => (action.shows?.length ? receivedMidi({ id: action.id, bypass: true }) : runAction(action))} dark>
<Button style={action.enabled === false ? "opacity: 0.6;" : ""} title={$dictionary.media?.play} on:click={() => (action.shows?.length ? receivedMidi({ id: action.id, bypass: true }) : runAction(action))} dark>
<span style="display: flex;align-items: center;width: 100%;">
{#if action.shows?.length}
<Icon id="slide" white right />
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/components/drawer/pages/TemplateSlide.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
export let edit: boolean = false
let lines: [string, number][] = []
let mouse: any = null
let newStyles: any = {}
export let newStyles: any = {}
$: active = $activeEdit.items
$: currentStyle = $styles[$outputs[getActiveOutputs()[0]].style || ""] || {}
Expand Down
8 changes: 7 additions & 1 deletion src/frontend/components/edit/EditTools.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@
if (active === "text") {
// get current text style
let style = item?.lines?.[0].text?.[0].style || item?.style
// don't style scripture verses
let normalText = item?.lines?.[0].text?.filter((a) => !a.customType) || []
let style = normalText[0]?.style || item?.style
let extraKeys = {
auto: item?.auto,
specialStyle: item?.specialStyle,
Expand Down Expand Up @@ -170,7 +172,11 @@
if (!a.text) return
return a.text.map((a: any) => {
// don't style scripture verses
if (a.customType) return a
a.style = style
return a
})
})
Expand Down
4 changes: 3 additions & 1 deletion src/frontend/components/edit/editbox/Editbox.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import type { Item } from "../../../../types/Show"
import { activeEdit, activeShow, os, showsCache, variables } from "../../../stores"
import { activeEdit, activeShow, openToolsTab, os, showsCache, variables } from "../../../stores"
import { deleteAction } from "../../helpers/clipboard"
import EditboxLines from "./EditboxLines.svelte"
import EditboxOther from "./EditboxOther.svelte"
Expand All @@ -25,6 +25,8 @@
export let mouse: any = {}
function mousedown(e: any) {
if (e.target.closest(".chords") || e.target.closest(".editTools")) return
if (!e.target.closest(".line") && !e.target.closest(".square")) openToolsTab.set("text")
let rightClick: boolean = e.buttons === 2 || ($os.platform === "darwin" && e.ctrlKey)
activeEdit.update((ae) => {
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/components/edit/editbox/EditboxHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export class EditboxHelper {

let style = a.style ? 'style="' + a.style + '"' : ""

html += `<span ${plain ? "" : style} data-chords='${JSON.stringify(textChords)}'>` + (a.value.replaceAll("\n", "<br>") || "<br>") + "</span>"
html += `<span class="${a.customType ? "custom" : ""}" ${plain ? "" : style} data-chords='${JSON.stringify(textChords)}'>` + (a.value.replaceAll("\n", "<br>") || "<br>") + "</span>"
})
html += "</div>"
})
Expand Down
20 changes: 13 additions & 7 deletions src/frontend/components/edit/editbox/EditboxLines.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -359,18 +359,24 @@
caret = { line: i, pos: 0 }
}
})
// set to end (if backspace)
if (!caret && (item.lines || []).length > newLines.length) {
// WIP if line in middle is deleted, the caret is still moved to the last line... (get the last used line here)
caret = { line: newLines.length - 1, pos: getLineText(newLines[newLines.length - 1]).length }
}
}
if (caret) {
item.lines = newLines
setTimeout(() => {
getStyle()
if (newLines.length > 1) {
// set caret position back
setTimeout(() => {
setCaret(textElem, caret)
}, 10)
}
if (newLines.length < 1) return
// set caret position back
setTimeout(() => {
setCaret(textElem, caret)
}, 10)
}, 10)
}
Expand Down Expand Up @@ -486,7 +492,7 @@
opacity: 0;
overflow: hidden;
}
.edit:not(.invisible).autoSize :global(span) {
.edit:not(.invisible).autoSize :global(span:not(.custom)) {
font-size: var(--auto-size) !important;
}
Expand Down
Loading

0 comments on commit 9150c26

Please sign in to comment.