Add loading store to Navigator to keep track of loading state

This commit is contained in:
2024-08-09 13:47:10 +02:00
parent 69744e41a6
commit 12e23b3872
11 changed files with 51 additions and 86 deletions

View File

@@ -12,8 +12,8 @@ import { fs_path_url } from './FilesystemUtil.js';
import { branding_from_path } from './edit_window/Branding.js' import { branding_from_path } from './edit_window/Branding.js'
import Menu from './Menu.svelte'; import Menu from './Menu.svelte';
import { Navigator } from "./Navigator.js" import { Navigator } from "./Navigator.js"
import { writable } from 'svelte/store';
let loading = true
let file_viewer let file_viewer
let file_preview let file_preview
let toolbar let toolbar
@@ -24,9 +24,11 @@ let edit_window
let edit_visible = false let edit_visible = false
let view = "file" let view = "file"
const nav = new Navigator() const loading = writable(true)
const nav = new Navigator(true)
onMount(() => { onMount(() => {
nav.loading = loading
nav.open_node(window.initial_node, false) nav.open_node(window.initial_node, false)
// Subscribe to navigation updates. This function returns a deconstructor // Subscribe to navigation updates. This function returns a deconstructor
@@ -39,8 +41,7 @@ onMount(() => {
// Custom CSS rules for the whole viewer // Custom CSS rules for the whole viewer
document.documentElement.style = branding_from_path(nav.path) document.documentElement.style = branding_from_path(nav.path)
// Turn off loading spinner when the navigator is done loading.set(false)
loading = false
}) })
}) })
@@ -120,8 +121,6 @@ const search = async () => {
view = "search" view = "search"
} }
const loading_evt = e => loading = e.detail
</script> </script>
<svelte:window on:keydown={keydown} /> <svelte:window on:keydown={keydown} />
@@ -151,17 +150,12 @@ const loading_evt = e => loading = e.detail
bind:this={file_preview} bind:this={file_preview}
nav={nav} nav={nav}
edit_window={edit_window} edit_window={edit_window}
on:loading={loading_evt}
on:open_sibling={e => nav.open_sibling(e.detail)} on:open_sibling={e => nav.open_sibling(e.detail)}
on:download={download} on:download={download}
on:upload_picker={() => upload_widget.pick_files()} on:upload_picker={() => upload_widget.pick_files()}
/> />
{:else if view === "search"} {:else if view === "search"}
<SearchView <SearchView nav={nav} on:done={() => {view = "file"}} />
nav={nav}
on:loading={loading_evt}
on:done={() => {view = "file"}}
/>
{/if} {/if}
</div> </div>
</div> </div>
@@ -173,25 +167,13 @@ const loading_evt = e => loading = e.detail
style="display: none; width: 1px; height: 1px;"> style="display: none; width: 1px; height: 1px;">
</iframe> </iframe>
<DetailsWindow <DetailsWindow nav={nav} bind:visible={details_visible} />
nav={nav}
bind:visible={details_visible}
/>
<EditWindow <EditWindow nav={nav} bind:this={edit_window} bind:visible={edit_visible} />
nav={nav}
bind:this={edit_window}
bind:visible={edit_visible}
on:loading={loading_evt}
/>
<UploadWidget <UploadWidget nav={nav} bind:this={upload_widget} drop_upload />
nav={nav}
bind:this={upload_widget}
drop_upload
/>
<LoadingIndicator loading={$nav.loading || loading}/> <LoadingIndicator loading={$loading}/>
</div> </div>
<style> <style>

View File

@@ -13,9 +13,7 @@ export class Navigator {
// Initialized will be set to true when the first file or directory is loaded // Initialized will be set to true when the first file or directory is loaded
initialized = false initialized = false
shuffle = false shuffle = false
loading = false
// Whether navigation events should update the browser history // Whether navigation events should update the browser history
history_enabled = true history_enabled = true
@@ -36,6 +34,15 @@ export class Navigator {
} }
} }
// If you set the loading property to a boolean writable store the navigator
// will use it to publish its loading states
loading = null
set_loading(b) {
if (this.loading !== null && this.loading.set !== undefined) {
this.loading.set(b)
}
}
// The Navigator acts as a svelte store. This allows for DOM reactivity. // The Navigator acts as a svelte store. This allows for DOM reactivity.
// This works by implementing the store contract: // This works by implementing the store contract:
// https://svelte.dev/docs/svelte-components#script-4-prefix-stores-with-$-to-access-their-values // https://svelte.dev/docs/svelte-components#script-4-prefix-stores-with-$-to-access-their-values
@@ -57,10 +64,10 @@ export class Navigator {
path = "/" + path path = "/" + path
} }
this.loading = true
console.debug("Navigating to path", path, push_history) console.debug("Navigating to path", path, push_history)
try { try {
this.set_loading(true)
const resp = await fs_get_node(path) const resp = await fs_get_node(path)
this.open_node(resp, push_history) this.open_node(resp, push_history)
} catch (err) { } catch (err) {
@@ -77,7 +84,7 @@ export class Navigator {
alert("Error: " + err) alert("Error: " + err)
} }
} finally { } finally {
this.loading = false this.set_loading(false)
} }
} }
@@ -132,9 +139,6 @@ export class Navigator {
for (let i = 0; i < this.subscribers.length; i++) { for (let i = 0; i < this.subscribers.length; i++) {
this.subscribers[i](this) this.subscribers[i](this)
} }
// Remove spinner
this.loading = false
} }
// These are used to navigate forward and backward within a directory (using // These are used to navigate forward and backward within a directory (using
@@ -174,16 +178,17 @@ export class Navigator {
return return
} }
this.loading = true
let siblings let siblings
try { try {
this.set_loading(true)
siblings = await this.get_siblings() siblings = await this.get_siblings()
} catch (err) { } catch (err) {
console.error(err) console.error(err)
alert(err) alert(err)
this.loading = false
return return
} finally {
this.set_loading(false)
} }
let next_sibling = null let next_sibling = null
@@ -218,10 +223,9 @@ export class Navigator {
// If we found a sibling we open it // If we found a sibling we open it
if (next_sibling !== null) { if (next_sibling !== null) {
console.debug("Opening sibling", next_sibling.path) console.debug("Opening sibling", next_sibling.path)
this.navigate(next_sibling.path, true) await this.navigate(next_sibling.path, true)
} else { } else {
console.debug("No siblings found") console.debug("No siblings found")
this.loading = false
} }
} }
} }

View File

@@ -32,8 +32,9 @@ const search = async (limit = 10) => {
error = "" error = ""
last_searched_term = search_term last_searched_term = search_term
last_limit = limit last_limit = limit
searching = true searching = true
dispatch("loading", true) nav.set_loading(true)
try { try {
search_results = await fs_search(nav.base.path, search_term, limit) search_results = await fs_search(nav.base.path, search_term, limit)
@@ -47,7 +48,7 @@ const search = async (limit = 10) => {
} }
searching = false searching = false
dispatch("loading", false) nav.set_loading(false)
// It's possible that the user entered another letter while we were // It's possible that the user entered another letter while we were
// performing the search reqeust. If this happens we run the search function // performing the search reqeust. If this happens we run the search function

View File

@@ -1,14 +1,11 @@
<script> <script>
import { fs_rename, fs_update } from "../FilesystemAPI"; import { fs_rename, fs_update } from "../FilesystemAPI";
import Modal from "../../util/Modal.svelte"; import Modal from "../../util/Modal.svelte";
import { createEventDispatcher } from "svelte";
import BrandingOptions from "./BrandingOptions.svelte"; import BrandingOptions from "./BrandingOptions.svelte";
import { branding_from_node } from "./Branding"; import { branding_from_node } from "./Branding";
import FileOptions from "./FileOptions.svelte"; import FileOptions from "./FileOptions.svelte";
import SharingOptions from "./SharingOptions.svelte"; import SharingOptions from "./SharingOptions.svelte";
let dispatch = createEventDispatcher()
export let nav export let nav
let file = { let file = {
path: "", path: "",
@@ -78,7 +75,7 @@ const save = async (keep_editing = false) => {
let new_file let new_file
try { try {
dispatch("loading", true) nav.set_loading(true)
let opts = {shared: shared} let opts = {shared: shared}
opts.branding_enabled = branding_enabled ? "true" : "" opts.branding_enabled = branding_enabled ? "true" : ""
@@ -113,7 +110,7 @@ const save = async (keep_editing = false) => {
} }
return return
} finally { } finally {
dispatch("loading", false) nav.set_loading(false)
} }
if (open_after_edit) { if (open_after_edit) {
@@ -154,7 +151,6 @@ const save = async (keep_editing = false) => {
bind:new_name bind:new_name
bind:visible bind:visible
bind:open_after_edit bind:open_after_edit
on:loading
/> />
{:else if tab === "share"} {:else if tab === "share"}
<SharingOptions <SharingOptions

View File

@@ -1,10 +1,8 @@
<script> <script>
import { createEventDispatcher } from "svelte";
import Button from "../../layout/Button.svelte"; import Button from "../../layout/Button.svelte";
import { fs_delete_all } from "../FilesystemAPI"; import { fs_delete_all } from "../FilesystemAPI";
import PathLink from "../util/PathLink.svelte"; import PathLink from "../util/PathLink.svelte";
let dispatch = createEventDispatcher()
export let nav export let nav
export let file = {} export let file = {}
export let new_name export let new_name
@@ -17,14 +15,14 @@ const delete_file = async e => {
e.preventDefault() e.preventDefault()
try { try {
dispatch("loading", true) nav.set_loading(true)
await fs_delete_all(file.path) await fs_delete_all(file.path)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
alert(err) alert(err)
return return
} finally { } finally {
dispatch("loading", false) nac.set_loading(false)
} }
if (open_after_edit) { if (open_after_edit) {

View File

@@ -1,8 +1,7 @@
<script> <script>
import { onMount, createEventDispatcher } from "svelte"; import { onMount } from "svelte";
import { fs_mkdir } from "../FilesystemAPI.js"; import { fs_mkdir } from "../FilesystemAPI.js";
import Button from "../../layout/Button.svelte"; import Button from "../../layout/Button.svelte";
let dispatch = createEventDispatcher()
export let nav; export let nav;
@@ -10,16 +9,15 @@ let name_input;
let new_dir_name = "" let new_dir_name = ""
let error_msg = "" let error_msg = ""
let create_dir = async () => { let create_dir = async () => {
dispatch("loading", true)
let form = new FormData() let form = new FormData()
form.append("type", "dir") form.append("type", "dir")
try { try {
nav.set_loading(true)
await fs_mkdir(nav.base.path+"/"+new_dir_name) await fs_mkdir(nav.base.path+"/"+new_dir_name)
new_dir_name = "" // Clear input field new_dir_name = "" // Clear input field
error_msg = "" // Clear error msg error_msg = "" // Clear error msg
dispatch("done") nav.reload()
} catch (err) { } catch (err) {
if (err.value && err.value === "node_already_exists") { if (err.value && err.value === "node_already_exists") {
error_msg = "A directory with this name already exists" error_msg = "A directory with this name already exists"
@@ -27,7 +25,7 @@ let create_dir = async () => {
error_msg = "Server returned an error: "+err error_msg = "Server returned an error: "+err
} }
} finally { } finally {
dispatch("loading", false) nav.set_loading(false)
} }
} }

View File

@@ -1,21 +1,16 @@
<script> <script>
import { createEventDispatcher } from "svelte";
import FilePicker from "../../file_viewer/FilePicker.svelte"; import FilePicker from "../../file_viewer/FilePicker.svelte";
import { fs_import } from "../FilesystemAPI"; import { fs_import } from "../FilesystemAPI";
let dispatch = createEventDispatcher()
export let nav export let nav
let file_picker let file_picker
export const open = () => file_picker.open() export const open = () => file_picker.open()
const import_files = async files => { const import_files = async files => {
dispatch("loading", true) nav.set_loading(true)
console.log(files)
let fileids = [] let fileids = []
files.forEach(file => { files.forEach(file => {
fileids.push(file.id) fileids.push(file.id)
}) })
@@ -31,10 +26,9 @@ const import_files = async files => {
} }
return return
} finally { } finally {
dispatch("reload") nav.reload()
} }
} }
</script> </script>
<FilePicker <FilePicker

View File

@@ -97,7 +97,7 @@ const delete_selected = async () => {
return return
} }
dispatch("loading", true) nav.set_loading(true)
try { try {
// Save all promises with deletion requests in an array // Save all promises with deletion requests in an array
@@ -219,7 +219,7 @@ const move_start = () => {
} }
const move_here = async () => { const move_here = async () => {
dispatch("loading", true) nav.set_loading(true)
let target_dir = nav.base.path + "/" let target_dir = nav.base.path + "/"
@@ -338,7 +338,7 @@ onMount(() => {
{/if} {/if}
{#if creating_dir} {#if creating_dir}
<CreateDirectory nav={nav} on:done={() => nav.reload()} on:loading /> <CreateDirectory nav={nav} />
{/if} {/if}
{#if $nav.base.path === "/me"} {#if $nav.base.path === "/me"}
@@ -386,12 +386,7 @@ onMount(() => {
{/if} {/if}
</div> </div>
<FileImporter <FileImporter nav={nav} bind:this={file_importer} />
nav={nav}
bind:this={file_importer}
on:loading
on:reload={() => nav.reload()}
/>
<style> <style>
.container { .container {

View File

@@ -52,7 +52,7 @@ export const toggle_playback = () => {
<Spinner></Spinner> <Spinner></Spinner>
</div> </div>
{:else if viewer_type === "dir"} {:else if viewer_type === "dir"}
<FileManager nav={nav} edit_window={edit_window} on:loading on:upload_picker> <FileManager nav={nav} edit_window={edit_window} on:upload_picker>
<CustomBanner path={$nav.path}/> <CustomBanner path={$nav.path}/>
</FileManager> </FileManager>
{:else if viewer_type === "audio"} {:else if viewer_type === "audio"}
@@ -70,11 +70,11 @@ export const toggle_playback = () => {
<CustomBanner path={$nav.path}/> <CustomBanner path={$nav.path}/>
</Text> </Text>
{:else if viewer_type === "torrent"} {:else if viewer_type === "torrent"}
<Torrent nav={nav} bind:this={viewer} on:loading on:download> <Torrent nav={nav} bind:this={viewer} on:download>
<CustomBanner path={$nav.path}/> <CustomBanner path={$nav.path}/>
</Torrent> </Torrent>
{:else if viewer_type === "zip"} {:else if viewer_type === "zip"}
<Zip nav={nav} bind:this={viewer} on:loading on:download> <Zip nav={nav} bind:this={viewer} on:download>
<CustomBanner path={$nav.path}/> <CustomBanner path={$nav.path}/>
</Zip> </Zip>
{:else} {:else}

View File

@@ -15,9 +15,8 @@ export let nav
let status = "loading" let status = "loading"
export const update = async () => { export const update = async () => {
dispatch("loading", true)
try { try {
nav.set_loading(true)
let resp = await fetch(fs_path_url(nav.base.path)+"?torrent_info") let resp = await fetch(fs_path_url(nav.base.path)+"?torrent_info")
if (resp.status >= 400) { if (resp.status >= 400) {
@@ -44,9 +43,9 @@ export const update = async () => {
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} finally { } finally {
dispatch("loading", false) nav.set_loading(false)
}
status = "finished" status = "finished"
}
} }
let torrent = { let torrent = {

View File

@@ -21,8 +21,6 @@ let comp_ratio = 0
let archive_type = "" let archive_type = ""
export const update = async () => { export const update = async () => {
dispatch("loading", true)
if (nav.base.file_type === "application/zip") { if (nav.base.file_type === "application/zip") {
archive_type = "zip" archive_type = "zip"
} else if (nav.base.file_type === "application/x-7z-compressed") { } else if (nav.base.file_type === "application/x-7z-compressed") {
@@ -30,6 +28,7 @@ export const update = async () => {
} }
try { try {
nav.set_loading(true)
let resp = await fetch(fs_path_url(nav.base.path)+"?zip_info") let resp = await fetch(fs_path_url(nav.base.path)+"?zip_info")
if (resp.status >= 400) { if (resp.status >= 400) {
@@ -51,10 +50,9 @@ export const update = async () => {
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} finally { } finally {
dispatch("loading", false) nav.set_loading(false)
}
status = "finished" status = "finished"
}
} }
const recursive_set_url = (parent_path, file) => { const recursive_set_url = (parent_path, file) => {