feat(stores): promote launcher_loc to Svelte 5 PersistedState
Creates ae_events_stores__launcher.svelte.ts with PersistedState keyed 'ae_launcher_loc', following the same pattern as badges, leads, and pres_mgmt. All 28 launcher component files migrated from $events_loc.launcher.* to launcher_loc.current.*. events_local_data_struct in ae_events_stores.ts now carries no sub-module objects — all four sub-modules (badges, launcher, leads, pres_mgmt) are authoritative in their own stores. Session state (events_sess.launcher) is unchanged. svelte-check: 0 errors, 0 warnings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,10 +9,7 @@ import type { Writable } from 'svelte/store';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
|
||||
import { badges_sess_defaults } from '$lib/stores/ae_events_stores__badges_defaults';
|
||||
import {
|
||||
launcher_loc_defaults,
|
||||
launcher_sess_defaults
|
||||
} from '$lib/stores/ae_events_stores__launcher_defaults';
|
||||
import { launcher_sess_defaults } from '$lib/stores/ae_events_stores__launcher_defaults';
|
||||
import { leads_sess_defaults } from '$lib/stores/ae_events_stores__leads_defaults';
|
||||
import { pres_mgmt_sess_defaults } from '$lib/stores/ae_events_stores__pres_mgmt_defaults';
|
||||
|
||||
@@ -63,8 +60,7 @@ const events_local_data_struct: key_val = {
|
||||
},
|
||||
|
||||
// Event Presentation Launcher — see ae_events_stores__launcher_defaults.ts
|
||||
// badges, leads, pres_mgmt have been promoted to their own PersistedState stores.
|
||||
launcher: launcher_loc_defaults
|
||||
// badges, leads, pres_mgmt, launcher have all been promoted to their own PersistedState stores.
|
||||
};
|
||||
|
||||
export const events_loc: Writable<key_val> = persisted(
|
||||
|
||||
9
src/lib/stores/ae_events_stores__launcher.svelte.ts
Normal file
9
src/lib/stores/ae_events_stores__launcher.svelte.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { PersistedState } from 'runed';
|
||||
import { launcher_loc_defaults } from './ae_events_stores__launcher_defaults';
|
||||
|
||||
export const launcher_loc = new PersistedState('ae_launcher_loc', launcher_loc_defaults, {
|
||||
serializer: {
|
||||
serialize: JSON.stringify,
|
||||
deserialize: (raw: string) => ({ ...launcher_loc_defaults, ...JSON.parse(raw) })
|
||||
}
|
||||
});
|
||||
@@ -5,7 +5,7 @@
|
||||
* Ensures background sync runs globally regardless of active tab.
|
||||
*/
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import Launcher_Background_Sync from './launcher_background_sync.svelte';
|
||||
|
||||
interface Props {
|
||||
@@ -20,8 +20,8 @@ let { children }: Props = $props();
|
||||
// design (default / onsite / native) — browser sessions are unaffected because
|
||||
// is_native is only ever true inside the Electron shell.
|
||||
$effect(() => {
|
||||
if ($ae_loc.is_native && $events_loc.launcher.app_mode !== 'native') {
|
||||
$events_loc.launcher.app_mode = 'native';
|
||||
if ($ae_loc.is_native && launcher_loc.current.app_mode !== 'native') {
|
||||
launcher_loc.current.app_mode = 'native';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import { Clock, GraduationCap, IdCard, LayoutGrid } from '@lucide/svelte';
|
||||
interface Props {
|
||||
@@ -30,22 +31,22 @@ const ORAL_PRESET = {
|
||||
// Detect current mode: if both iframe AND hide_menu are on, we're in poster mode.
|
||||
// Individual overrides are still possible via the checkboxes below.
|
||||
let is_poster_mode = $derived(
|
||||
$ae_loc.iframe === true && $events_loc.launcher.hide__launcher_menu === true
|
||||
$ae_loc.iframe === true && launcher_loc.current.hide__launcher_menu === true
|
||||
);
|
||||
|
||||
function apply_mode(mode: 'poster' | 'oral') {
|
||||
const preset = mode === 'poster' ? POSTER_PRESET : ORAL_PRESET;
|
||||
$ae_loc.iframe = preset.iframe;
|
||||
$events_loc.launcher.hide__launcher_menu = preset.hide__launcher_menu;
|
||||
$events_loc.launcher.hide__launcher_header = preset.hide__launcher_header;
|
||||
$events_loc.launcher.hide__launcher_footer = preset.hide__launcher_footer;
|
||||
launcher_loc.current.hide__launcher_menu = preset.hide__launcher_menu;
|
||||
launcher_loc.current.hide__launcher_header = preset.hide__launcher_header;
|
||||
launcher_loc.current.hide__launcher_footer = preset.hide__launcher_footer;
|
||||
|
||||
// Push to WS-connected remote devices when we're acting as a controller.
|
||||
// Only send when connected so the UI button doesn't silently no-op.
|
||||
if (
|
||||
$events_loc.launcher.ws_connect &&
|
||||
($events_loc.launcher.controller === 'local_push' ||
|
||||
$events_loc.launcher.controller === 'remote')
|
||||
launcher_loc.current.ws_connect &&
|
||||
(launcher_loc.current.controller === 'local_push' ||
|
||||
launcher_loc.current.controller === 'remote')
|
||||
) {
|
||||
$events_sess.launcher.controller_cmd = `ae_mode:${mode}`;
|
||||
$events_sess.launcher.controller_trigger_send = 'trigger';
|
||||
@@ -56,9 +57,9 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<Launcher_Cfg_Section
|
||||
title="Display & App Modes"
|
||||
icon={LayoutGrid}
|
||||
bind:state={$events_loc.launcher.section_state__app_modes}
|
||||
bind:state={launcher_loc.current.section_state__app_modes}
|
||||
{on_expand}
|
||||
description="Mode: {$events_loc.launcher.app_mode} | UI Layout">
|
||||
description="Mode: {launcher_loc.current.app_mode} | UI Layout">
|
||||
<!-- Content omitted for brevity, preserved in file -->
|
||||
<div class="col-span-full flex flex-col gap-3">
|
||||
<!-- 0. Oral / Poster Kiosk Mode Preset Toggle -->
|
||||
@@ -88,7 +89,7 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
Poster Kiosk
|
||||
</button>
|
||||
</div>
|
||||
{#if $events_loc.launcher.ws_connect && ($events_loc.launcher.controller === 'local_push' || $events_loc.launcher.controller === 'remote')}
|
||||
{#if launcher_loc.current.ws_connect && (launcher_loc.current.controller === 'local_push' || launcher_loc.current.controller === 'remote')}
|
||||
<p class="ml-1 text-[8px] italic opacity-40">
|
||||
Applies to all connected WS devices
|
||||
</p>
|
||||
@@ -103,31 +104,31 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<div class="bg-surface-500/5 grid grid-cols-3 gap-1 rounded-lg p-1">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => ($events_loc.launcher.app_mode = 'default')}
|
||||
onclick={() => (launcher_loc.current.app_mode = 'default')}
|
||||
class="btn btn-xs text-[9px] font-bold"
|
||||
class:preset-filled-primary={$events_loc.launcher
|
||||
class:preset-filled-primary={launcher_loc.current
|
||||
.app_mode === 'default'}
|
||||
class:preset-tonal-surface={$events_loc.launcher
|
||||
class:preset-tonal-surface={launcher_loc.current
|
||||
.app_mode !== 'default'}
|
||||
title="Default standard web browser (Chromium, Firefox, Safari based) launcher, for remote presenters and testing before being onsite">
|
||||
Web</button>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => ($events_loc.launcher.app_mode = 'native')}
|
||||
onclick={() => (launcher_loc.current.app_mode = 'native')}
|
||||
class="btn btn-xs text-[9px] font-bold"
|
||||
class:preset-filled-primary={$events_loc.launcher
|
||||
class:preset-filled-primary={launcher_loc.current
|
||||
.app_mode === 'native'}
|
||||
class:preset-tonal-surface={$events_loc.launcher
|
||||
class:preset-tonal-surface={launcher_loc.current
|
||||
.app_mode !== 'native'}
|
||||
title="Native Electron based app launcher, for onsite presenters in session rooms"
|
||||
>App</button>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => ($events_loc.launcher.app_mode = 'onsite')}
|
||||
onclick={() => (launcher_loc.current.app_mode = 'onsite')}
|
||||
class="btn btn-xs text-[9px] font-bold"
|
||||
class:preset-filled-primary={$events_loc.launcher
|
||||
class:preset-filled-primary={launcher_loc.current
|
||||
.app_mode === 'onsite'}
|
||||
class:preset-tonal-surface={$events_loc.launcher
|
||||
class:preset-tonal-surface={launcher_loc.current
|
||||
.app_mode !== 'onsite'}
|
||||
title="Customized onsite OS and web browser (Chromium or Firefox based) launcher, for onsite presenters in for practice and onsite backup"
|
||||
>Onsite</button>
|
||||
@@ -145,7 +146,7 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={
|
||||
$events_loc.launcher.hide__launcher_header
|
||||
launcher_loc.current.hide__launcher_header
|
||||
}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span class="group-hover:text-primary-500 text-xs"
|
||||
@@ -154,7 +155,7 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<label class="group flex cursor-pointer items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={$events_loc.launcher.hide__launcher_menu}
|
||||
bind:checked={launcher_loc.current.hide__launcher_menu}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span class="group-hover:text-primary-500 text-xs"
|
||||
>Hide Menu</span>
|
||||
@@ -163,7 +164,7 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={
|
||||
$events_loc.launcher.hide__launcher_footer
|
||||
launcher_loc.current.hide__launcher_footer
|
||||
}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span class="group-hover:text-primary-500 text-xs"
|
||||
@@ -173,7 +174,7 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={
|
||||
$events_loc.launcher.hide__session_datetimes
|
||||
launcher_loc.current.hide__session_datetimes
|
||||
}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span class="group-hover:text-primary-500 text-xs"
|
||||
@@ -186,18 +187,18 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
if ($events_loc.launcher.time_format == 'time_12_short') {
|
||||
$events_loc.launcher.time_format = 'time_short';
|
||||
$events_loc.launcher.time_hours = 24;
|
||||
if (launcher_loc.current.time_format == 'time_12_short') {
|
||||
launcher_loc.current.time_format = 'time_short';
|
||||
launcher_loc.current.time_hours = 24;
|
||||
} else {
|
||||
$events_loc.launcher.time_format = 'time_12_short';
|
||||
$events_loc.launcher.time_hours = 12;
|
||||
launcher_loc.current.time_format = 'time_12_short';
|
||||
launcher_loc.current.time_hours = 12;
|
||||
}
|
||||
}}
|
||||
class="btn btn-xs preset-tonal-surface w-full text-[10px]">
|
||||
<Clock size="0.85em" class="mr-1 opacity-50" />
|
||||
Clock Format:
|
||||
<strong>{$events_loc.launcher.time_hours}-hour</strong>
|
||||
<strong>{launcher_loc.current.time_hours}-hour</strong>
|
||||
</button>
|
||||
|
||||
<!-- 4. Advanced Toggles (Edit Mode Only) -->
|
||||
@@ -211,7 +212,7 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<label class="group flex cursor-pointer items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={$events_loc.launcher.hide__ws_element}
|
||||
bind:checked={launcher_loc.current.hide__ws_element}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span
|
||||
class="group-hover:text-primary-500 text-xs italic"
|
||||
@@ -221,7 +222,7 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={
|
||||
$events_loc.launcher.hide__modal_header_title
|
||||
launcher_loc.current.hide__modal_header_title
|
||||
}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span
|
||||
@@ -243,13 +244,13 @@ function apply_mode(mode: 'poster' | 'oral') {
|
||||
<label class="group flex cursor-pointer items-center gap-2 p-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={$events_loc.launcher.native_test_mode}
|
||||
bind:checked={launcher_loc.current.native_test_mode}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span class="group-hover:text-warning-500 text-xs italic">
|
||||
Native Test Mode
|
||||
</span>
|
||||
</label>
|
||||
{#if $events_loc.launcher.native_test_mode}
|
||||
{#if launcher_loc.current.native_test_mode}
|
||||
<p class="badge preset-tonal-warning ml-1 text-[8px] leading-tight italic">
|
||||
⚠ Active: Open buttons will simulate native launch and
|
||||
show a debug popup instead of running commands.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import {
|
||||
Gamepad2,
|
||||
@@ -24,9 +25,9 @@ const ws_connected = $derived(
|
||||
<Launcher_Cfg_Section
|
||||
title="Remote Controller"
|
||||
icon={Gamepad2}
|
||||
bind:state={$events_loc.launcher.section_state__controller}
|
||||
bind:state={launcher_loc.current.section_state__controller}
|
||||
{on_expand}
|
||||
description="Mode: {$events_loc.launcher?.controller} | WS: {ws_connected
|
||||
description="Mode: {launcher_loc.current?.controller} | WS: {ws_connected
|
||||
? 'Connected'
|
||||
: 'Offline'}">
|
||||
<!-- Content omitted for brevity, preserved in file -->
|
||||
@@ -55,7 +56,7 @@ const ws_connected = $derived(
|
||||
Controller Strategy
|
||||
</p>
|
||||
<select
|
||||
bind:value={$events_loc.launcher.controller}
|
||||
bind:value={launcher_loc.current.controller}
|
||||
class="select select-sm preset-tonal-surface h-8 text-xs">
|
||||
<option value="local">Local Only</option>
|
||||
<option value="remote">Remotely WS Controlled</option>
|
||||
@@ -68,18 +69,18 @@ const ws_connected = $derived(
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
if ($events_loc.launcher.ws_connect) {
|
||||
if (launcher_loc.current.ws_connect) {
|
||||
$events_sess.launcher.trigger__ws_disconnect = true;
|
||||
} else {
|
||||
$events_loc.launcher.ws_connect = true;
|
||||
launcher_loc.current.ws_connect = true;
|
||||
$events_sess.launcher.trigger__ws_connect = true;
|
||||
}
|
||||
$events_sess.launcher.controller_unlock_group_code = false;
|
||||
}}
|
||||
class="btn btn-sm text-[10px] font-bold transition-all"
|
||||
class:preset-tonal-error={$events_loc.launcher.ws_connect}
|
||||
class:preset-tonal-success={!$events_loc.launcher.ws_connect}>
|
||||
{#if $events_loc.launcher.ws_connect}
|
||||
class:preset-tonal-error={launcher_loc.current.ws_connect}
|
||||
class:preset-tonal-success={!launcher_loc.current.ws_connect}>
|
||||
{#if launcher_loc.current.ws_connect}
|
||||
<Unlink size="0.85em" class="mr-1" /> Disconnect
|
||||
{:else}
|
||||
<Link size="0.85em" class="mr-1" /> Connect Now
|
||||
@@ -107,7 +108,7 @@ const ws_connected = $derived(
|
||||
</p>
|
||||
<div class="flex gap-1">
|
||||
<input
|
||||
bind:value={$events_loc.launcher.controller_group_code}
|
||||
bind:value={launcher_loc.current.controller_group_code}
|
||||
placeholder="Group Code"
|
||||
class="input input-sm preset-tonal-surface h-7 grow font-mono text-[10px]"
|
||||
readonly={!$events_sess.launcher
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import { HeartPulse, RefreshCw } from '@lucide/svelte';
|
||||
interface Props {
|
||||
@@ -44,7 +45,7 @@ function get_usage_color(pct: number) {
|
||||
<Launcher_Cfg_Section
|
||||
title="System & Sync Health"
|
||||
icon={HeartPulse}
|
||||
bind:state={$events_loc.launcher.section_state__health}
|
||||
bind:state={launcher_loc.current.section_state__health}
|
||||
{on_expand}
|
||||
description="Heartbeat: {$events_sess.launcher.heartbeat_info
|
||||
.last_timestamp || 'Pending'}">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import {
|
||||
DEFAULT_LAUNCH_PROFILE_DEFS,
|
||||
resolve_launch_profile,
|
||||
@@ -268,7 +268,7 @@ async function reset_profile_delay(profile_name: string) {
|
||||
<Launcher_Cfg_Section
|
||||
title="Launch Timing"
|
||||
icon={Timer}
|
||||
bind:state={$events_loc.launcher.section_state__launch_timing}
|
||||
bind:state={launcher_loc.current.section_state__launch_timing}
|
||||
{on_expand}
|
||||
description="Per-profile post-open delay overrides">
|
||||
{#if $ae_loc.edit_mode && !$ae_loc.is_native}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import { cleanup_tmp_files } from '$lib/electron/electron_relay';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import { Bug, BugOff, Eraser, Eye, EyeOff, Wrench } from '@lucide/svelte';
|
||||
@@ -18,7 +18,7 @@ async function handle_cleanup_now() {
|
||||
cleanup_status = 'Error: Cache path not set.';
|
||||
return;
|
||||
}
|
||||
const max_age_hours = $events_loc.launcher.cleanup_tmp_max_age_hours ?? 24;
|
||||
const max_age_hours = launcher_loc.current.cleanup_tmp_max_age_hours ?? 24;
|
||||
cleanup_status = 'Cleaning...';
|
||||
const result = await cleanup_tmp_files({
|
||||
cache_root,
|
||||
@@ -80,7 +80,7 @@ function handle_reset_action(val: string) {
|
||||
<Launcher_Cfg_Section
|
||||
title="Local Reset & Actions"
|
||||
icon={Wrench}
|
||||
bind:state={$events_loc.launcher.section_state__local_actions}
|
||||
bind:state={launcher_loc.current.section_state__local_actions}
|
||||
{on_expand}
|
||||
description="Cache wiping and global menu toggles">
|
||||
<div class="col-span-full flex flex-col gap-3">
|
||||
@@ -154,7 +154,7 @@ function handle_reset_action(val: string) {
|
||||
min="1"
|
||||
max="168"
|
||||
bind:value={
|
||||
$events_loc.launcher.cleanup_tmp_max_age_hours
|
||||
launcher_loc.current.cleanup_tmp_max_age_hours
|
||||
}
|
||||
class="input input-sm preset-tonal-surface h-7 w-16 text-center text-xs"
|
||||
placeholder="24" />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ae_loc, ae_api, ae_sess } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import * as native from '$lib/electron/electron_relay';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import {
|
||||
@@ -98,7 +99,7 @@ let show_power_confirm = $state<{ action: string; label: string } | null>(null);
|
||||
<Launcher_Cfg_Section
|
||||
title="Native OS Management"
|
||||
icon={Code}
|
||||
bind:state={$events_loc.launcher.section_state__native_os}
|
||||
bind:state={launcher_loc.current.section_state__native_os}
|
||||
{on_expand}
|
||||
description="OS: {$ae_loc.native_device?.meta_json?.platform ||
|
||||
'...'} | Kiosk & Apps">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import { IdCard } from '@lucide/svelte';
|
||||
interface Props {
|
||||
@@ -12,9 +12,9 @@ let { on_expand }: Props = $props();
|
||||
<Launcher_Cfg_Section
|
||||
title="Poster Screen Saver"
|
||||
icon={IdCard}
|
||||
bind:state={$events_loc.launcher.section_state__screen_saver}
|
||||
bind:state={launcher_loc.current.section_state__screen_saver}
|
||||
{on_expand}
|
||||
description="Idle: {($events_loc.launcher.idle_timer / 60000).toFixed(
|
||||
description="Idle: {(launcher_loc.current.idle_timer / 60000).toFixed(
|
||||
1
|
||||
)}m | Auto-Posters">
|
||||
<!-- Content omitted for brevity, preserved in file -->
|
||||
@@ -32,7 +32,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
min={3000}
|
||||
bind:value={$events_loc.launcher.idle_timer}
|
||||
bind:value={launcher_loc.current.idle_timer}
|
||||
class="input input-sm preset-tonal-surface h-7 w-24 text-right text-[10px]" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
@@ -40,7 +40,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
min={500}
|
||||
bind:value={$events_loc.launcher.idle_cycle}
|
||||
bind:value={launcher_loc.current.idle_cycle}
|
||||
class="input input-sm preset-tonal-surface h-7 w-24 text-right text-[10px]" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
@@ -49,7 +49,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
min={750}
|
||||
bind:value={$events_loc.launcher.idle_loop_period}
|
||||
bind:value={launcher_loc.current.idle_loop_period}
|
||||
class="input input-sm preset-tonal-surface h-7 w-24 text-right text-[10px]" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,7 +61,7 @@ let { on_expand }: Props = $props();
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="opacity-60">Active Idle Timeout:</span>
|
||||
<span class="text-primary-500 font-bold"
|
||||
>{($events_loc.launcher.idle_timer / 60000).toFixed(1)} minutes</span>
|
||||
>{(launcher_loc.current.idle_timer / 60000).toFixed(1)} minutes</span>
|
||||
</div>
|
||||
<p class="text-[9px] italic opacity-40">
|
||||
The screen saver automatically rotates digital posters when
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import { CloudDownload, Pause, Play, RefreshCw } from '@lucide/svelte';
|
||||
interface Props {
|
||||
@@ -12,7 +13,7 @@ let { on_expand }: Props = $props();
|
||||
<Launcher_Cfg_Section
|
||||
title="Sync Engine & Timers"
|
||||
icon={RefreshCw}
|
||||
bind:state={$events_loc.launcher.section_state__sync_timers}
|
||||
bind:state={launcher_loc.current.section_state__sync_timers}
|
||||
{on_expand}
|
||||
description="Prefix: {$ae_loc.native_device?.hash_prefix_length ||
|
||||
2} | Loops: Active">
|
||||
@@ -21,19 +22,19 @@ let { on_expand }: Props = $props();
|
||||
<div
|
||||
class="border-surface-500/10 bg-surface-500/5 mb-2 flex items-center justify-between rounded border p-2">
|
||||
<span class="text-[10px] font-bold tracking-wider uppercase opacity-70">
|
||||
{$events_loc.launcher.sync_paused
|
||||
{launcher_loc.current.sync_paused
|
||||
? '⏸ Sync Paused'
|
||||
: '▶ Sync Active'}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() =>
|
||||
($events_loc.launcher.sync_paused =
|
||||
!$events_loc.launcher.sync_paused)}
|
||||
(launcher_loc.current.sync_paused =
|
||||
!launcher_loc.current.sync_paused)}
|
||||
class="btn btn-xs transition-all"
|
||||
class:preset-tonal-warning={$events_loc.launcher.sync_paused}
|
||||
class:preset-tonal-success={!$events_loc.launcher.sync_paused}>
|
||||
{#if $events_loc.launcher.sync_paused}
|
||||
class:preset-tonal-warning={launcher_loc.current.sync_paused}
|
||||
class:preset-tonal-success={!launcher_loc.current.sync_paused}>
|
||||
{#if launcher_loc.current.sync_paused}
|
||||
<Play size="0.85em" class="mr-1" /> Resume
|
||||
{:else}
|
||||
<Pause size="0.85em" class="mr-1" /> Pause
|
||||
@@ -51,7 +52,7 @@ let { on_expand }: Props = $props();
|
||||
Force Sync Location
|
||||
</button>
|
||||
|
||||
{#if $events_loc.launcher.sync_intervals}
|
||||
{#if launcher_loc.current.sync_intervals}
|
||||
<div class="grid grid-cols-1 gap-3">
|
||||
<!-- Technical Timers (Edit Mode Only) -->
|
||||
{#if $ae_loc.edit_mode}
|
||||
@@ -66,7 +67,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
bind:value={
|
||||
$events_loc.launcher.sync_intervals.event
|
||||
launcher_loc.current.sync_intervals.event
|
||||
}
|
||||
class="input input-sm preset-tonal-surface h-7 text-[10px]" />
|
||||
</div>
|
||||
@@ -76,7 +77,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
bind:value={
|
||||
$events_loc.launcher.sync_intervals.device
|
||||
launcher_loc.current.sync_intervals.device
|
||||
}
|
||||
class="input input-sm preset-tonal-surface h-7 text-[10px]" />
|
||||
</div>
|
||||
@@ -86,7 +87,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
bind:value={
|
||||
$events_loc.launcher.sync_intervals.location
|
||||
launcher_loc.current.sync_intervals.location
|
||||
}
|
||||
class="input input-sm preset-tonal-surface h-7 text-[10px]" />
|
||||
</div>
|
||||
@@ -96,7 +97,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
bind:value={
|
||||
$events_loc.launcher.sync_intervals.session
|
||||
launcher_loc.current.sync_intervals.session
|
||||
}
|
||||
class="input input-sm preset-tonal-surface h-7 text-[10px]" />
|
||||
</div>
|
||||
@@ -106,7 +107,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
bind:value={
|
||||
$events_loc.launcher.sync_intervals
|
||||
launcher_loc.current.sync_intervals
|
||||
.presentation
|
||||
}
|
||||
class="input input-sm preset-tonal-surface h-7 text-[10px]" />
|
||||
@@ -117,7 +118,7 @@ let { on_expand }: Props = $props();
|
||||
<input
|
||||
type="number"
|
||||
bind:value={
|
||||
$events_loc.launcher.sync_intervals
|
||||
launcher_loc.current.sync_intervals
|
||||
.presenter
|
||||
}
|
||||
class="input input-sm preset-tonal-surface h-7 text-[10px]" />
|
||||
@@ -161,7 +162,7 @@ let { on_expand }: Props = $props();
|
||||
<span>Event Sync:</span>
|
||||
<span
|
||||
>{(
|
||||
$events_loc.launcher.sync_intervals.event / 1000
|
||||
launcher_loc.current.sync_intervals.event / 1000
|
||||
).toFixed(1)}s</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -169,7 +170,7 @@ let { on_expand }: Props = $props();
|
||||
<span>Room Monitor:</span>
|
||||
<span
|
||||
>{(
|
||||
$events_loc.launcher.sync_intervals.location /
|
||||
launcher_loc.current.sync_intervals.location /
|
||||
1000
|
||||
).toFixed(1)}s</span>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
* for the Launcher Configuration overhaul.
|
||||
*/
|
||||
import { ae_loc, ae_api, ae_sess } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import {
|
||||
TriangleAlert,
|
||||
@@ -48,7 +49,7 @@ let show_confirm = $state(false);
|
||||
<Launcher_Cfg_Section
|
||||
title="Template Section"
|
||||
icon={Boxes}
|
||||
bind:state={$events_loc.launcher.section_state__template}
|
||||
bind:state={launcher_loc.current.section_state__template}
|
||||
{on_expand}
|
||||
description="Kitchen Sink Scaffold | Demo Only">
|
||||
<!-- A. TOP STATUS BAR (Optional) -->
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ae_loc, ae_api, ae_sess } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import * as native from '$lib/electron/electron_relay';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import { CloudDownload, LoaderCircle, Search, Wand2 } from '@lucide/svelte';
|
||||
@@ -55,7 +56,7 @@ async function handle_install() {
|
||||
<Launcher_Cfg_Section
|
||||
title="Application Updates"
|
||||
icon={CloudDownload}
|
||||
bind:state={$events_loc.launcher.section_state__updates}
|
||||
bind:state={launcher_loc.current.section_state__updates}
|
||||
{on_expand}
|
||||
description="v1.0.0 | Source: {update_source}">
|
||||
<!-- Content omitted for brevity, preserved in file -->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import * as native from '$lib/electron/electron_relay';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import { FlaskConical, Image, RotateCcw, Save, Zap } from '@lucide/svelte';
|
||||
@@ -150,8 +150,8 @@ async function handle_apply(): Promise<{ success: boolean; linux_test?: boolean
|
||||
linux_test_popup_open = true;
|
||||
return { success: true, linux_test: true };
|
||||
} else if (result?.success) {
|
||||
$events_loc.launcher.wallpaper_applied_url = url || null;
|
||||
$events_loc.launcher.wallpaper_applied_url_external = url_ext || null;
|
||||
launcher_loc.current.wallpaper_applied_url = url || null;
|
||||
launcher_loc.current.wallpaper_applied_url_external = url_ext || null;
|
||||
return { success: true };
|
||||
}
|
||||
return { success: false };
|
||||
@@ -181,8 +181,8 @@ async function handle_restore_default() {
|
||||
const result = await native.restore_macos_default_wallpaper('all');
|
||||
if (result?.success) {
|
||||
// Clear tracked applied URL so the next config URL re-applies correctly.
|
||||
$events_loc.launcher.wallpaper_applied_url = null;
|
||||
$events_loc.launcher.wallpaper_applied_url_external = null;
|
||||
launcher_loc.current.wallpaper_applied_url = null;
|
||||
launcher_loc.current.wallpaper_applied_url_external = null;
|
||||
set_status('Restored ✓');
|
||||
} else {
|
||||
set_status(`Restore failed: ${(result as { error?: string })?.error ?? 'Unknown'}`);
|
||||
@@ -192,7 +192,7 @@ async function handle_restore_default() {
|
||||
const configured_url = $derived(get_configured_wallpaper().url ?? '');
|
||||
const is_applied = $derived(
|
||||
!!url_input.trim() &&
|
||||
$events_loc.launcher.wallpaper_applied_url === url_input.trim()
|
||||
launcher_loc.current.wallpaper_applied_url === url_input.trim()
|
||||
);
|
||||
const section_description = $derived(
|
||||
configured_url
|
||||
@@ -206,7 +206,7 @@ const section_description = $derived(
|
||||
<Launcher_Cfg_Section
|
||||
title="Wallpaper"
|
||||
icon={Image}
|
||||
bind:state={$events_loc.launcher.section_state__wallpaper}
|
||||
bind:state={launcher_loc.current.section_state__wallpaper}
|
||||
{on_expand}
|
||||
description={section_description}>
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ import {
|
||||
events_trigger,
|
||||
events_trig
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
|
||||
import Launcher_cfg from '../launcher_cfg.svelte';
|
||||
@@ -82,63 +83,37 @@ $ae_sess.disable_sys_nav = true;
|
||||
$ae_sess.disable_sys_header = true;
|
||||
$ae_sess.disable_sys_footer = true;
|
||||
|
||||
if (!$events_loc?.launcher) {
|
||||
$events_loc.launcher = {
|
||||
app_mode: 'default',
|
||||
controller: 'local',
|
||||
controller_group_code: 'launcher-00',
|
||||
ws_connect: false,
|
||||
hide_drawer__cfg: true,
|
||||
hide_drawer__debug: true
|
||||
};
|
||||
}
|
||||
// WHY: The initialization block above only runs when launcher is completely absent.
|
||||
// If the user has an older persisted config (from before the Modal migration),
|
||||
// hide_drawer__cfg may be missing → undefined → !undefined = true → modal opens
|
||||
// on every load. Explicitly initialize it here to ensure it is always a boolean.
|
||||
if ($events_loc.launcher.hide_drawer__cfg === undefined) {
|
||||
$events_loc.launcher.hide_drawer__cfg = true;
|
||||
}
|
||||
// WHY: launcher_loc is a PersistedState store — always initialized with defaults.
|
||||
// No need for initialization guards; all fields have default values in launcher_loc_defaults.
|
||||
|
||||
let modal_cfg_open = $state(!$events_loc.launcher.hide_drawer__cfg);
|
||||
let modal_cfg_open = $state(!launcher_loc.current.hide_drawer__cfg);
|
||||
|
||||
// Sync store → modal: biohazard button writes hide_drawer__cfg = false to open.
|
||||
// Equality guard prevents spurious writes from unrelated $events_loc updates
|
||||
// (Svelte 4 whole-store subscription fires on every field write to the store).
|
||||
$effect(() => {
|
||||
const should_open = !$events_loc.launcher.hide_drawer__cfg;
|
||||
const should_open = !launcher_loc.current.hide_drawer__cfg;
|
||||
if (modal_cfg_open !== should_open) {
|
||||
modal_cfg_open = should_open;
|
||||
}
|
||||
});
|
||||
|
||||
// Sync modal → store: use events_loc.update() directly rather than $-syntax so
|
||||
// the write always reaches the persisted store's serialization. $-syntax writes
|
||||
// inside $effect contexts may be suppressed and not trigger localStorage persistence.
|
||||
// Sync modal → store: direct assignment to PersistedState triggers localStorage persistence.
|
||||
$effect(() => {
|
||||
const should_hide = !modal_cfg_open;
|
||||
events_loc.update((loc) => {
|
||||
if (loc.launcher) loc.launcher.hide_drawer__cfg = should_hide;
|
||||
return loc;
|
||||
});
|
||||
launcher_loc.current.hide_drawer__cfg = !modal_cfg_open;
|
||||
});
|
||||
|
||||
// Called by backdrop click. Writes to store immediately (don't rely on effect timing).
|
||||
function close_cfg() {
|
||||
modal_cfg_open = false;
|
||||
events_loc.update((loc) => {
|
||||
if (loc.launcher) loc.launcher.hide_drawer__cfg = true;
|
||||
return loc;
|
||||
});
|
||||
launcher_loc.current.hide_drawer__cfg = true;
|
||||
}
|
||||
|
||||
// Generate a stable per-device client ID on first load and persist it.
|
||||
// events_loc is backed by svelte-persisted-store (localStorage) so this
|
||||
// survives page reloads. Without this, client_id falls back to Date.now()
|
||||
// inside element_websocket — a new ID on every reload, which breaks
|
||||
// direct-target WS messages and doesn't match V3 Vision ID expectations.
|
||||
if (!$events_loc.launcher.controller_client_id) {
|
||||
$events_loc.launcher.controller_client_id = crypto.randomUUID();
|
||||
// launcher_loc is a PersistedState store (localStorage) so this survives
|
||||
// page reloads. Without this, client_id falls back to Date.now() inside
|
||||
// element_websocket — a new ID on every reload, which breaks direct-target
|
||||
// WS messages and doesn't match V3 Vision ID expectations.
|
||||
if (!launcher_loc.current.controller_client_id) {
|
||||
launcher_loc.current.controller_client_id = crypto.randomUUID();
|
||||
}
|
||||
|
||||
// Unified Selection Sync (Refactored 2026-02-11)
|
||||
@@ -198,19 +173,19 @@ $effect(() => {
|
||||
else if (param_iframe === 'false') $ae_loc.iframe = false;
|
||||
|
||||
if (param_launcher_menu === 'hide')
|
||||
$events_loc.launcher.hide__launcher_menu = true;
|
||||
launcher_loc.current.hide__launcher_menu = true;
|
||||
else if (param_launcher_menu === 'show')
|
||||
$events_loc.launcher.hide__launcher_menu = false;
|
||||
launcher_loc.current.hide__launcher_menu = false;
|
||||
|
||||
if (param_launcher_header === 'hide')
|
||||
$events_loc.launcher.hide__launcher_header = true;
|
||||
launcher_loc.current.hide__launcher_header = true;
|
||||
else if (param_launcher_header === 'show')
|
||||
$events_loc.launcher.hide__launcher_header = false;
|
||||
launcher_loc.current.hide__launcher_header = false;
|
||||
|
||||
if (param_launcher_footer === 'hide')
|
||||
$events_loc.launcher.hide__launcher_footer = true;
|
||||
launcher_loc.current.hide__launcher_footer = true;
|
||||
else if (param_launcher_footer === 'show')
|
||||
$events_loc.launcher.hide__launcher_footer = false;
|
||||
launcher_loc.current.hide__launcher_footer = false;
|
||||
});
|
||||
|
||||
// Strip launcher display params from the URL after applying them — same pattern
|
||||
@@ -422,7 +397,7 @@ function handle_ws_recv(ws_recv_status: any) {
|
||||
// V3 schema uses msg_type instead of type
|
||||
if (ws_recv_status.msg_type == 'cmd' && ws_recv_status.cmd) {
|
||||
let cmd = ws_recv_status.cmd;
|
||||
if ($events_loc.launcher.controller != 'remote') return;
|
||||
if (launcher_loc.current.controller != 'remote') return;
|
||||
|
||||
if (cmd.startsWith('ae_load:')) {
|
||||
let cmd_parts = cmd.split(':');
|
||||
@@ -508,14 +483,14 @@ function handle_ws_recv(ws_recv_status: any) {
|
||||
const mode_target = cmd.split(':')[1];
|
||||
if (mode_target === 'poster') {
|
||||
$ae_loc.iframe = true;
|
||||
$events_loc.launcher.hide__launcher_menu = true;
|
||||
$events_loc.launcher.hide__launcher_header = true;
|
||||
$events_loc.launcher.hide__launcher_footer = true;
|
||||
launcher_loc.current.hide__launcher_menu = true;
|
||||
launcher_loc.current.hide__launcher_header = true;
|
||||
launcher_loc.current.hide__launcher_footer = true;
|
||||
} else if (mode_target === 'oral') {
|
||||
$ae_loc.iframe = false;
|
||||
$events_loc.launcher.hide__launcher_menu = false;
|
||||
$events_loc.launcher.hide__launcher_header = false;
|
||||
$events_loc.launcher.hide__launcher_footer = false;
|
||||
launcher_loc.current.hide__launcher_menu = false;
|
||||
launcher_loc.current.hide__launcher_header = false;
|
||||
launcher_loc.current.hide__launcher_footer = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -547,16 +522,16 @@ $effect(() => {
|
||||
}
|
||||
});
|
||||
|
||||
if (!$events_loc.launcher.idle_timer)
|
||||
$events_loc.launcher.idle_timer = 5 * 60 * 1000;
|
||||
if (!$events_loc.launcher.idle_cycle)
|
||||
$events_loc.launcher.idle_cycle = 5 * 1000;
|
||||
if (!$events_loc.launcher.idle_loop_period)
|
||||
$events_loc.launcher.idle_loop_period = 3 * 60 * 1000;
|
||||
if (!launcher_loc.current.idle_timer)
|
||||
launcher_loc.current.idle_timer = 5 * 60 * 1000;
|
||||
if (!launcher_loc.current.idle_cycle)
|
||||
launcher_loc.current.idle_cycle = 5 * 1000;
|
||||
if (!launcher_loc.current.idle_loop_period)
|
||||
launcher_loc.current.idle_loop_period = 3 * 60 * 1000;
|
||||
|
||||
listen({
|
||||
timer: $events_loc.launcher.idle_timer,
|
||||
cycle: $events_loc.launcher.idle_cycle
|
||||
timer: launcher_loc.current.idle_timer,
|
||||
cycle: launcher_loc.current.idle_cycle
|
||||
});
|
||||
|
||||
let idle_timer_interval: any = $state();
|
||||
@@ -575,13 +550,13 @@ function handle_idle_client() {
|
||||
|
||||
idle_timer_interval = setInterval(
|
||||
() => {
|
||||
if ($events_loc.launcher.screen_saver_img_kv) {
|
||||
if (launcher_loc.current.screen_saver_img_kv) {
|
||||
const keys = Object.keys(
|
||||
$events_loc.launcher.screen_saver_img_kv
|
||||
launcher_loc.current.screen_saver_img_kv
|
||||
);
|
||||
const rand_index = Math.floor(Math.random() * keys.length);
|
||||
let event_file_obj =
|
||||
$events_loc.launcher.screen_saver_img_kv[
|
||||
launcher_loc.current.screen_saver_img_kv[
|
||||
keys[rand_index]
|
||||
];
|
||||
|
||||
@@ -598,7 +573,7 @@ function handle_idle_client() {
|
||||
}
|
||||
return false;
|
||||
},
|
||||
$events_loc.launcher.idle_loop_period ?? 2 * 60 * 1000
|
||||
launcher_loc.current.idle_loop_period ?? 2 * 60 * 1000
|
||||
);
|
||||
} else {
|
||||
saver_looping = false;
|
||||
@@ -636,8 +611,8 @@ $effect(() => {
|
||||
</svelte:head>
|
||||
|
||||
<div
|
||||
class:mt-12={!$events_loc.launcher.hide__launcher_header}
|
||||
class:mt-2={$events_loc.launcher.hide__launcher_header}
|
||||
class:mt-12={!launcher_loc.current.hide__launcher_header}
|
||||
class:mt-2={launcher_loc.current.hide__launcher_header}
|
||||
class="
|
||||
static
|
||||
m-auto
|
||||
@@ -651,7 +626,7 @@ $effect(() => {
|
||||
">
|
||||
<header
|
||||
id="Main-Header"
|
||||
class:hidden={$events_loc.launcher.hide__launcher_header}
|
||||
class:hidden={launcher_loc.current.hide__launcher_header}
|
||||
class="
|
||||
absolute
|
||||
top-0 right-0 left-0 z-20
|
||||
@@ -674,8 +649,8 @@ $effect(() => {
|
||||
type="button"
|
||||
class="hover:bg-surface-500/10 rounded px-2 py-1 transition-colors"
|
||||
onclick={() => {
|
||||
$events_loc.launcher.hide__launcher_menu =
|
||||
!$events_loc.launcher.hide__launcher_menu;
|
||||
launcher_loc.current.hide__launcher_menu =
|
||||
!launcher_loc.current.hide__launcher_menu;
|
||||
}}
|
||||
title="Toggle Launcher menu">
|
||||
<Satellite class="mx-1 inline-block text-base text-gray-500" />
|
||||
@@ -739,7 +714,7 @@ $effect(() => {
|
||||
|
||||
md:min-w-64 lg:min-w-72 dark:border-gray-700
|
||||
"
|
||||
class:hidden={$events_loc.launcher.hide__launcher_menu}>
|
||||
class:hidden={launcher_loc.current.hide__launcher_menu}>
|
||||
<Launcher_menu
|
||||
{lq__event_obj}
|
||||
{lq__event_event_file_obj_li}
|
||||
@@ -808,7 +783,7 @@ $effect(() => {
|
||||
|
||||
<footer
|
||||
id="Main-Footer"
|
||||
class:hidden={$events_loc.launcher.hide__launcher_footer}
|
||||
class:hidden={launcher_loc.current.hide__launcher_footer}
|
||||
class="
|
||||
absolute
|
||||
right-0 bottom-0 left-0 z-20
|
||||
@@ -868,7 +843,7 @@ $effect(() => {
|
||||
</span>
|
||||
|
||||
<span
|
||||
class:hidden={!$events_loc.launcher.ws_connect}
|
||||
class:hidden={!launcher_loc.current.ws_connect}
|
||||
class:preset-tonal-warning={$events_sess.launcher.ws_connect_status !=
|
||||
'connected'}
|
||||
class:preset-tonal-success={$events_sess.launcher.ws_connect_status ==
|
||||
@@ -918,7 +893,7 @@ $effect(() => {
|
||||
<span class="hidden sm:inline">
|
||||
<Clock size="1em" />
|
||||
</span>
|
||||
{#if $events_loc.launcher?.time_hours == 12}
|
||||
{#if launcher_loc.current?.time_hours == 12}
|
||||
{ae_util.iso_datetime_formatter($time, 'time_12_long')}
|
||||
{:else}
|
||||
{ae_util.iso_datetime_formatter($time, 'time_long')}
|
||||
@@ -929,7 +904,7 @@ $effect(() => {
|
||||
<div class="absolute top-0 left-0 z-20 text-center">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => ($events_loc.launcher.hide_drawer__cfg = false)}
|
||||
onclick={() => (launcher_loc.current.hide_drawer__cfg = false)}
|
||||
class="btn btn-sm preset-tonal-error hover:preset-filled-error-500 p-3 transition-colors duration-300"
|
||||
class:opacity-25={!$ae_loc.trusted_access}
|
||||
class:hover:opacity-75={!$ae_loc.trusted_access}>
|
||||
@@ -998,7 +973,7 @@ $effect(() => {
|
||||
easing: sineIn
|
||||
}
|
||||
}}
|
||||
bind:hidden={$events_loc.launcher.hide_drawer__debug}
|
||||
bind:hidden={launcher_loc.current.hide_drawer__debug}
|
||||
id="sidebar2">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<h2
|
||||
@@ -1007,7 +982,7 @@ $effect(() => {
|
||||
</h2>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => ($events_loc.launcher.hide_drawer__debug = true)}
|
||||
onclick={() => (launcher_loc.current.hide_drawer__debug = true)}
|
||||
class="mb-4 dark:text-white">
|
||||
<X size="1em" />
|
||||
<span class="hidden">Close Debug Drawer</span>
|
||||
@@ -1016,7 +991,7 @@ $effect(() => {
|
||||
|
||||
<div>
|
||||
<pre class="text-xs">
|
||||
{JSON.stringify($events_loc.launcher, null, 2)}
|
||||
{JSON.stringify(launcher_loc.current, null, 2)}
|
||||
</pre>
|
||||
<hr />
|
||||
<pre class="text-xs">
|
||||
@@ -1035,15 +1010,15 @@ $effect(() => {
|
||||
rounded-lg border-gray-200 bg-gray-500/90 text-gray-800
|
||||
shadow-md
|
||||
dark:divide-gray-700 dark:border-gray-700 dark:bg-gray-800/90 dark:text-gray-200
|
||||
{$events_loc.launcher.controller == 'remote' ? 'min-h-full' : ''}
|
||||
{launcher_loc.current.controller == 'remote' ? 'min-h-full' : ''}
|
||||
min-w-full
|
||||
"
|
||||
bodyClass="p-0 space-y-0 overflow-auto flex flex-col gap-1 items-center justify-center pb-14"
|
||||
headerClass={`fixed top-0 right-0 left-0 p-1 md:p-2 flex flex-row items-center ${$events_loc.launcher.controller == 'remote' ? 'hidden' : ''} bg-white dark:bg-gray-800 opacity-50 ${$events_loc.launcher.hide__modal_header_title ? 'justify-center' : 'justify-between'}`}
|
||||
headerClass={`fixed top-0 right-0 left-0 p-1 md:p-2 flex flex-row items-center ${launcher_loc.current.controller == 'remote' ? 'hidden' : ''} bg-white dark:bg-gray-800 opacity-50 ${launcher_loc.current.hide__modal_header_title ? 'justify-center' : 'justify-between'}`}
|
||||
footerClass="text-center hidden">
|
||||
{#snippet header()}
|
||||
<h3
|
||||
class:hidden={$events_loc.launcher.hide__modal_header_title}
|
||||
class:hidden={launcher_loc.current.hide__modal_header_title}
|
||||
class="text-lg font-semibold opacity-20 transition-all hover:opacity-100">
|
||||
{$events_sess.launcher?.modal__title ?? 'Digital Poster Display'}
|
||||
</h3>
|
||||
@@ -1084,7 +1059,7 @@ $effect(() => {
|
||||
modal_zoom_fit = !modal_zoom_fit;
|
||||
// Sync zoom state to the remote display when acting as controller.
|
||||
if (
|
||||
$events_loc.launcher.controller == 'local_push' &&
|
||||
launcher_loc.current.controller == 'local_push' &&
|
||||
$events_sess.launcher.ws_connect_status == 'connected'
|
||||
) {
|
||||
$events_sess.launcher.controller_cmd = `ae_zoom:${modal_zoom_fit ? 'fit' : 'zoom'}`;
|
||||
@@ -1117,7 +1092,7 @@ $effect(() => {
|
||||
bg-black/30
|
||||
p-1.5 backdrop-blur-sm
|
||||
"
|
||||
class:hidden={$events_loc.launcher.controller == 'remote'}>
|
||||
class:hidden={launcher_loc.current.controller == 'remote'}>
|
||||
<!-- Zoom / Fit toggle: accessibility accommodation — lets operators and general
|
||||
public zoom in to read details, pinch on mobile, or double-tap the image. -->
|
||||
<button
|
||||
@@ -1126,7 +1101,7 @@ $effect(() => {
|
||||
modal_zoom_fit = !modal_zoom_fit;
|
||||
// Sync zoom state to the remote display when acting as controller.
|
||||
if (
|
||||
$events_loc.launcher.controller == 'local_push' &&
|
||||
launcher_loc.current.controller == 'local_push' &&
|
||||
$events_sess.launcher.ws_connect_status == 'connected'
|
||||
) {
|
||||
$events_sess.launcher.controller_cmd = `ae_zoom:${modal_zoom_fit ? 'fit' : 'zoom'}`;
|
||||
@@ -1158,7 +1133,7 @@ $effect(() => {
|
||||
$events_sess.launcher.modal__event_file_obj = null;
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-error opacity-80 transition-all hover:opacity-100"
|
||||
class:hidden={$events_loc.launcher.controller != 'local_push' ||
|
||||
class:hidden={launcher_loc.current.controller != 'local_push' ||
|
||||
$events_sess.launcher.ws_connect_status != 'connected'}
|
||||
title="Close poster on this device and on the remote display (screensaver resumes)">
|
||||
<Monitor size="1em" class="mr-1" />
|
||||
@@ -1177,7 +1152,7 @@ $effect(() => {
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-surface border-surface-400/50 border opacity-80 transition-all hover:opacity-100"
|
||||
class:hidden={!$ae_loc.trusted_access &&
|
||||
($events_loc.launcher.controller != 'local_push' ||
|
||||
(launcher_loc.current.controller != 'local_push' ||
|
||||
$events_sess.launcher.ws_connect_status != 'connected')}
|
||||
title="Close poster on this device only — remote display keeps showing">
|
||||
<List size="1em" class="mr-1" />
|
||||
@@ -1186,24 +1161,24 @@ $effect(() => {
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{#if $events_loc.launcher.controller_group_code && $events_loc.launcher.ws_connect}
|
||||
{#if launcher_loc.current.controller_group_code && launcher_loc.current.ws_connect}
|
||||
<Element_websocket
|
||||
{log_lvl}
|
||||
bind:ws_connect={$events_loc.launcher.ws_connect}
|
||||
bind:ws_connect={launcher_loc.current.ws_connect}
|
||||
bind:ws_connect_status={$events_sess.launcher.ws_connect_status}
|
||||
ws_server={$ae_api.fqdn}
|
||||
api_key={$ae_api.api_secret_key}
|
||||
jwt={$ae_loc.jwt}
|
||||
bind:group_id={$events_loc.launcher.controller_group_code}
|
||||
bind:client_id={$events_loc.launcher.controller_client_id}
|
||||
bind:group_id={launcher_loc.current.controller_group_code}
|
||||
bind:client_id={launcher_loc.current.controller_client_id}
|
||||
bind:cmd={$events_sess.launcher.controller_cmd}
|
||||
bind:trigger_send={$events_sess.launcher.controller_trigger_send}
|
||||
bind:trigger_connect={$events_sess.launcher.trigger__ws_connect}
|
||||
bind:trigger_disconnect={$events_sess.launcher.trigger__ws_disconnect}
|
||||
bind:hide__ws_element={$events_loc.launcher.hide__ws_element}
|
||||
bind:hide__ws_form={$events_loc.launcher.hide__ws_form}
|
||||
bind:hide__ws_messages={$events_loc.launcher.hide__ws_messages}
|
||||
bind:hide__ws_commands={$events_loc.launcher.hide__ws_commands}
|
||||
bind:hide__ws_element={launcher_loc.current.hide__ws_element}
|
||||
bind:hide__ws_form={launcher_loc.current.hide__ws_form}
|
||||
bind:hide__ws_messages={launcher_loc.current.hide__ws_messages}
|
||||
bind:hide__ws_commands={launcher_loc.current.hide__ws_commands}
|
||||
bind:ws_conn_status={trigger_handle_ws_conn}
|
||||
bind:ws_recv_status={trigger_handle_ws_recv}
|
||||
bind:ws_sent_status={trigger_handle_ws_sent} />
|
||||
|
||||
@@ -11,7 +11,6 @@ let log_lvl: number = $state(0);
|
||||
import { untrack } from 'svelte';
|
||||
import { ae_loc, ae_sess, ae_api } from '$lib/stores/ae_stores';
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
@@ -47,23 +46,9 @@ $effect(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// Set localStorage defaults for launcher state
|
||||
if (!$events_loc.launcher) {
|
||||
$events_loc.launcher = {};
|
||||
$events_loc.launcher.slct = { event_id: null };
|
||||
$events_loc.launcher.show_content__session_code = true;
|
||||
$events_loc.launcher.show_content__presentation_code = true;
|
||||
$events_loc.launcher.show_content__presenter_code = true;
|
||||
}
|
||||
if (!$events_loc.launcher.slct) {
|
||||
$events_loc.launcher.slct = {
|
||||
event_id: null,
|
||||
event_location_id: null,
|
||||
event_session_id: null,
|
||||
event_presentation_id: null,
|
||||
event_presenter_id: null
|
||||
};
|
||||
}
|
||||
// WHY: launcher_loc is a PersistedState store — always initialized with defaults from
|
||||
// launcher_loc_defaults. No initialization guards needed; all fields (slct, show_content__*)
|
||||
// are already set to their default values on first load.
|
||||
|
||||
// Set session storage defaults
|
||||
if (!$events_sess.launcher) $events_sess.launcher = {};
|
||||
|
||||
@@ -7,10 +7,10 @@ import { ChevronDown, ChevronUp, Cpu, RefreshCw } from '@lucide/svelte';
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||
import {
|
||||
events_loc,
|
||||
events_slct,
|
||||
events_sess
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
@@ -50,8 +50,8 @@ async function apply_wallpaper_if_changed(device_other_json: unknown) {
|
||||
|
||||
const configured_url = wallpaper.url ?? '';
|
||||
const configured_url_external = wallpaper.url_external ?? '';
|
||||
const applied_url = $events_loc.launcher.wallpaper_applied_url ?? '';
|
||||
const applied_url_external = $events_loc.launcher.wallpaper_applied_url_external ?? '';
|
||||
const applied_url = launcher_loc.current.wallpaper_applied_url ?? '';
|
||||
const applied_url_external = launcher_loc.current.wallpaper_applied_url_external ?? '';
|
||||
|
||||
const url_changed = configured_url && configured_url !== applied_url;
|
||||
const ext_changed = configured_url_external !== applied_url_external;
|
||||
@@ -76,8 +76,8 @@ async function apply_wallpaper_if_changed(device_other_json: unknown) {
|
||||
// the cfg component popup can show the details when triggered manually.
|
||||
console.info('Sync: Wallpaper linux_test_mode — would have applied:', (result as any).would_run);
|
||||
} else if (result?.success) {
|
||||
$events_loc.launcher.wallpaper_applied_url = configured_url || null;
|
||||
$events_loc.launcher.wallpaper_applied_url_external = configured_url_external || null;
|
||||
launcher_loc.current.wallpaper_applied_url = configured_url || null;
|
||||
launcher_loc.current.wallpaper_applied_url_external = configured_url_external || null;
|
||||
if (log_lvl) console.log('Sync: Wallpaper applied.');
|
||||
} else {
|
||||
console.warn('Sync: Wallpaper apply failed.', (result as any)?.error);
|
||||
@@ -154,7 +154,7 @@ onMount(async () => {
|
||||
}
|
||||
|
||||
const dev = $ae_loc.native_device || {};
|
||||
const cfg = $events_loc.launcher.sync_intervals || {};
|
||||
const cfg = launcher_loc.current.sync_intervals || {};
|
||||
|
||||
// Load timings from persistent config, with fallbacks to device config or defaults.
|
||||
// Fallback values here must match the loop_info $state defaults above — keep in sync.
|
||||
@@ -228,7 +228,7 @@ onMount(async () => {
|
||||
const cache_root = $ae_loc.local_file_cache_path;
|
||||
if ($ae_loc.is_native && cache_root) {
|
||||
const max_age_hours =
|
||||
$events_loc.launcher.cleanup_tmp_max_age_hours ?? 24;
|
||||
launcher_loc.current.cleanup_tmp_max_age_hours ?? 24;
|
||||
cleanup_tmp_files({
|
||||
cache_root,
|
||||
max_age_minutes: max_age_hours * 60
|
||||
@@ -285,7 +285,7 @@ $effect(() => {
|
||||
* API Refresh: Event
|
||||
*/
|
||||
async function refresh_event_data() {
|
||||
if ($events_loc.launcher.sync_paused) return;
|
||||
if (launcher_loc.current.sync_paused) return;
|
||||
if (!$events_slct.event_id) return;
|
||||
try {
|
||||
await events_func.load_ae_obj_id__event({
|
||||
@@ -304,7 +304,7 @@ async function refresh_event_data() {
|
||||
* API Refresh: Sessions in Room
|
||||
*/
|
||||
async function refresh_session_data() {
|
||||
if ($events_loc.launcher.sync_paused) return;
|
||||
if (launcher_loc.current.sync_paused) return;
|
||||
const location_id = $events_slct.event_location_id;
|
||||
if (!location_id) return;
|
||||
try {
|
||||
@@ -328,7 +328,7 @@ async function refresh_session_data() {
|
||||
* API Refresh: Presentations for Selected Session
|
||||
*/
|
||||
async function refresh_presentation_data() {
|
||||
if ($events_loc.launcher.sync_paused) return;
|
||||
if (launcher_loc.current.sync_paused) return;
|
||||
const session_id = $events_slct.event_session_id;
|
||||
if (!session_id) return;
|
||||
try {
|
||||
@@ -350,7 +350,7 @@ async function refresh_presentation_data() {
|
||||
* API Refresh: Presenters for Selected Session
|
||||
*/
|
||||
async function refresh_presenter_data() {
|
||||
if ($events_loc.launcher.sync_paused) return;
|
||||
if (launcher_loc.current.sync_paused) return;
|
||||
const session_id = $events_slct.event_session_id;
|
||||
if (!session_id) return;
|
||||
try {
|
||||
@@ -370,7 +370,7 @@ async function refresh_presenter_data() {
|
||||
}
|
||||
|
||||
async function run_sync_cycle() {
|
||||
if ($events_loc.launcher.sync_paused) return;
|
||||
if (launcher_loc.current.sync_paused) return;
|
||||
const location_id = $events_slct.event_location_id;
|
||||
const cache_root = $ae_loc.local_file_cache_path;
|
||||
const prefix_len = $ae_loc.native_device?.hash_prefix_length || 2;
|
||||
@@ -454,7 +454,7 @@ async function run_sync_cycle() {
|
||||
// Re-check pause flag each iteration — a sync cycle can run for many
|
||||
// seconds if there are missing files, so we must honour a pause request
|
||||
// mid-loop rather than waiting for the entire batch to finish.
|
||||
if ($events_loc.launcher.sync_paused) break;
|
||||
if (launcher_loc.current.sync_paused) break;
|
||||
|
||||
if (!file_obj.hash_sha256) continue;
|
||||
if (sync_results[file_obj.event_file_id] === 'success') {
|
||||
@@ -602,7 +602,7 @@ async function run_device_heartbeat() {
|
||||
* Ensures we have latest room settings.
|
||||
*/
|
||||
async function refresh_location_config() {
|
||||
if ($events_loc.launcher.sync_paused) return;
|
||||
if (launcher_loc.current.sync_paused) return;
|
||||
const location_id = $events_slct.event_location_id;
|
||||
if (!location_id) return;
|
||||
|
||||
@@ -631,7 +631,7 @@ async function refresh_location_config() {
|
||||
* handled separately via inc_file_li=true in refresh_presenter_data (120s timer).
|
||||
*/
|
||||
async function refresh_current_session_files() {
|
||||
if ($events_loc.launcher.sync_paused) return;
|
||||
if (launcher_loc.current.sync_paused) return;
|
||||
const session_id = $events_slct.event_session_id;
|
||||
if (!session_id) return;
|
||||
try {
|
||||
@@ -688,7 +688,7 @@ async function force_location_sync() {
|
||||
<!-- Monitor Overlay: only shown in Native/App mode.
|
||||
Positioned bottom-left at bottom-20 to clear the debug π button (bottom-8 left-2)
|
||||
and the sys bar (bottom-12 right-2). Panel grows upward from the status chip. -->
|
||||
{#if $events_loc.launcher.app_mode === 'native' || $ae_loc.is_native}
|
||||
{#if launcher_loc.current.app_mode === 'native' || $ae_loc.is_native}
|
||||
<div
|
||||
class="pointer-events-none fixed bottom-15 left-2 z-10 flex flex-col items-start gap-2">
|
||||
{#if show_monitor}
|
||||
|
||||
@@ -16,12 +16,12 @@ import {
|
||||
time
|
||||
} from '$lib/stores/ae_stores';
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct,
|
||||
events_trigger,
|
||||
events_trig
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
|
||||
// Sub-components
|
||||
import Launcher_Cfg_Native_OS from './cfg_components/launcher_cfg_native_os.svelte';
|
||||
@@ -112,7 +112,7 @@ const TABS = [
|
||||
* Pinned sections are ignored and remain open.
|
||||
*/
|
||||
function handle_section_expand(current_key: string) {
|
||||
const launcher = $events_loc.launcher;
|
||||
const launcher = launcher_loc.current;
|
||||
Object.keys(launcher).forEach((key) => {
|
||||
if (
|
||||
key.startsWith('section_state__') &&
|
||||
@@ -123,7 +123,7 @@ function handle_section_expand(current_key: string) {
|
||||
}
|
||||
}
|
||||
});
|
||||
$events_loc.launcher = launcher; // Trigger store update
|
||||
launcher_loc.current = launcher; // Trigger store update
|
||||
}
|
||||
|
||||
const current_tab_info = $derived(TABS.find((t) => t.id === active_tab));
|
||||
@@ -172,7 +172,7 @@ const current_tab_info = $derived(TABS.find((t) => t.id === active_tab));
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => ($events_loc.launcher.hide_drawer__cfg = true)}
|
||||
onclick={() => (launcher_loc.current.hide_drawer__cfg = true)}
|
||||
class="btn btn-sm preset-tonal-surface hover:preset-filled-surface-500 justify-start gap-3 px-3 py-2 text-[10px] transition-all">
|
||||
<X size="1em" />
|
||||
<span>Close Settings</span>
|
||||
@@ -304,7 +304,7 @@ const current_tab_info = $derived(TABS.find((t) => t.id === active_tab));
|
||||
<button
|
||||
type="button"
|
||||
onclick={() =>
|
||||
($events_loc.launcher.hide_drawer__debug = false)}
|
||||
(launcher_loc.current.hide_drawer__debug = false)}
|
||||
class="btn btn-sm preset-tonal-warning hover:preset-filled-warning-500 w-full transition-all">
|
||||
<Bug size="1.2em" class="mr-2" />
|
||||
Open Debug Panel
|
||||
|
||||
@@ -58,10 +58,10 @@ import { api } from '$lib/api/api';
|
||||
import { ae_loc, ae_api, ae_sess, slct } from '$lib/stores/ae_stores';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import {
|
||||
AlertCircle,
|
||||
@@ -97,7 +97,7 @@ let open_in_os_loading: boolean = $state(false);
|
||||
|
||||
/** Reactive display override for this file — stored in $events_loc (localStorage) not in the backend. */
|
||||
const current_display_override = $derived.by(() => {
|
||||
const overrides = (($events_loc.launcher as Record<string, unknown>)?.file_display_overrides ?? {}) as Record<string, string>;
|
||||
const overrides = ((launcher_loc.current as Record<string, unknown>)?.file_display_overrides ?? {}) as Record<string, string>;
|
||||
return (overrides[event_file_id] ?? null) as 'extend' | 'mirror' | 'none' | null;
|
||||
});
|
||||
|
||||
@@ -128,7 +128,7 @@ let screen_saver_exts = ['jpg', 'png', 'PNG', 'webp'];
|
||||
* Resolves the LaunchProfile for a given file extension and optional per-file
|
||||
* display override. Checked in priority order:
|
||||
* 1. event_device.data_json.launch_profiles[profile] (API-driven, per-device)
|
||||
* 2. $events_loc.launcher.launch_profiles[profile] (local persistent override)
|
||||
* 2. launcher_loc.current.launch_profiles[profile] (local persistent override)
|
||||
* 3. DEFAULT_LAUNCH_PROFILES[profile/alias] (Svelte built-in defaults)
|
||||
* 4. DEFAULT_LAUNCH_PROFILES['default'] (catch-all)
|
||||
* Per-file display_override from event_file.cfg_json overrides display_mode only.
|
||||
@@ -142,10 +142,10 @@ function get_launch_profile(
|
||||
native_device?.other_json?.launcher?.launch_profiles ??
|
||||
native_device?.launch_profiles ??
|
||||
null;
|
||||
const local_profiles = ($events_loc as any).launcher?.launch_profiles ?? null;
|
||||
const local_profiles = launcher_loc.current?.launch_profiles ?? null;
|
||||
// Display override is stored per-device in $events_loc — not in the backend (event_file has no JSON column).
|
||||
// This is intentional: display mode is a room/device preference, not a global file property.
|
||||
const launcher_kv = $events_loc.launcher as Record<string, unknown>;
|
||||
const launcher_kv = launcher_loc.current as Record<string, unknown>;
|
||||
const file_display_overrides = (launcher_kv?.file_display_overrides ?? {}) as Record<string, string>;
|
||||
const display_override = (file_display_overrides[event_file_id] ?? null) as 'extend' | 'mirror' | 'none' | null;
|
||||
|
||||
@@ -172,9 +172,9 @@ function get_launch_profile(
|
||||
|
||||
onMount(() => {
|
||||
if (screen_saver_exts.includes(event_file_obj.extension)) {
|
||||
if (!$events_loc.launcher.screen_saver_img_kv)
|
||||
$events_loc.launcher.screen_saver_img_kv = {};
|
||||
$events_loc.launcher.screen_saver_img_kv[event_file_id] = {
|
||||
if (!launcher_loc.current.screen_saver_img_kv)
|
||||
launcher_loc.current.screen_saver_img_kv = {};
|
||||
launcher_loc.current.screen_saver_img_kv[event_file_id] = {
|
||||
...event_file_obj
|
||||
};
|
||||
}
|
||||
@@ -204,7 +204,7 @@ async function handle_open_file() {
|
||||
const url = event_file_obj.filename as string;
|
||||
|
||||
// Test mode: show debug popup instead of opening
|
||||
if ($events_loc.launcher.native_test_mode && $events_loc.launcher.app_mode === 'native') {
|
||||
if (launcher_loc.current.native_test_mode && launcher_loc.current.app_mode === 'native') {
|
||||
open_file_clicked = true;
|
||||
open_file_status = 'opening_file';
|
||||
const profile = get_launch_profile('url', event_file_obj);
|
||||
@@ -251,7 +251,7 @@ async function handle_open_file() {
|
||||
|
||||
open_file_status_message = `Opening ${event_file_obj.title || 'URL'}...`;
|
||||
|
||||
if ($ae_loc.is_native && $events_loc.launcher.app_mode === 'native') {
|
||||
if ($ae_loc.is_native && launcher_loc.current.app_mode === 'native') {
|
||||
// Native: open in Chrome for kiosk-style presentation; fall back to default browser
|
||||
const result = await native.open_external({ url, app: 'chrome' });
|
||||
if (!result?.success) {
|
||||
@@ -270,7 +270,7 @@ async function handle_open_file() {
|
||||
// 0. NATIVE TEST MODE — simulate full native flow, show debug popup instead of running commands
|
||||
// Active when native_test_mode toggle is on (regardless of is_native / app_mode).
|
||||
// Lets you preview the resolved profile, open command, and post-script from any device.
|
||||
if ($events_loc.launcher.native_test_mode && $events_loc.launcher.app_mode === 'native') {
|
||||
if (launcher_loc.current.native_test_mode && launcher_loc.current.app_mode === 'native') {
|
||||
open_file_clicked = true;
|
||||
open_file_status = 'checking_cache';
|
||||
open_file_status_message = 'Test Mode: simulating cache check...';
|
||||
@@ -305,7 +305,7 @@ async function handle_open_file() {
|
||||
}
|
||||
|
||||
// 1. NATIVE MODE (Electron)
|
||||
if ($ae_loc.is_native && $events_loc.launcher.app_mode === 'native') {
|
||||
if ($ae_loc.is_native && launcher_loc.current.app_mode === 'native') {
|
||||
const cache_root = $ae_loc.local_file_cache_path;
|
||||
const temp_root = $ae_loc.host_file_temp_path;
|
||||
|
||||
@@ -475,7 +475,7 @@ async function handle_open_file() {
|
||||
return true;
|
||||
}
|
||||
// 2. ONSITE MODE (Browser with Modified Extensions)
|
||||
else if ($events_loc.launcher.app_mode === 'onsite') {
|
||||
else if (launcher_loc.current.app_mode === 'onsite') {
|
||||
open_file_clicked = true;
|
||||
open_file_status = 'downloading_onsite';
|
||||
open_file_status_message = 'Downloading (Onsite Mode)...';
|
||||
@@ -525,7 +525,7 @@ async function handle_open_file() {
|
||||
log_lvl: 1
|
||||
});
|
||||
|
||||
if ($events_loc.launcher.controller == 'local_push') {
|
||||
if (launcher_loc.current.controller == 'local_push') {
|
||||
$events_sess.launcher.controller_cmd = `ae_download:hosted_file=${event_file_obj.hosted_file_id}:${event_file_obj.filename}:${event_file_obj.extension}`;
|
||||
$events_sess.launcher.controller_trigger_send = true;
|
||||
}
|
||||
@@ -561,7 +561,7 @@ function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
>*** {open_file_status_message ||
|
||||
'Please wait while this file downloads...'} ***</strong>
|
||||
</div>
|
||||
{#if $ae_loc.is_native && $events_loc.launcher.app_mode === 'native'}
|
||||
{#if $ae_loc.is_native && launcher_loc.current.app_mode === 'native'}
|
||||
{#if open_file_status === 'error'}
|
||||
<p class="text-red-400">Failed to open file.</p>
|
||||
{#if open_file_error_detail}
|
||||
@@ -597,7 +597,7 @@ function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
$events_slct.event_file_obj = event_file_obj;
|
||||
// Push the open command to the remote display when in local_push mode
|
||||
if (
|
||||
$events_loc.launcher.controller == 'local_push' &&
|
||||
launcher_loc.current.controller == 'local_push' &&
|
||||
$events_sess.launcher.ws_connect_status == 'connected'
|
||||
) {
|
||||
$events_sess.launcher.controller_cmd = `ae_open:event_file=${event_file_id}`;
|
||||
@@ -626,7 +626,7 @@ function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
hosted_file_id={event_file_id}
|
||||
hosted_file_obj={event_file_obj}
|
||||
require_auth={false}
|
||||
track_click_promise={!($ae_loc.is_native && $events_loc.launcher.app_mode === 'native')}
|
||||
track_click_promise={!($ae_loc.is_native && launcher_loc.current.app_mode === 'native')}
|
||||
classes="btn {btn_size} gap-1 justify-between min-w-full w-full max-w-96 preset-tonal-primary border border-primary-500"
|
||||
click={handle_open_file}>
|
||||
{#snippet label()}
|
||||
@@ -749,7 +749,7 @@ function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
onclick={() => {
|
||||
const cur = current_display_override;
|
||||
const next: 'extend' | 'mirror' | null = !cur ? 'extend' : cur === 'extend' ? 'mirror' : null;
|
||||
const launcher = $events_loc.launcher as Record<string, unknown>;
|
||||
const launcher = launcher_loc.current as Record<string, unknown>;
|
||||
const new_overrides = { ...((launcher?.file_display_overrides ?? {}) as Record<string, string>) };
|
||||
if (next === null) {
|
||||
delete new_overrides[event_file_id];
|
||||
|
||||
@@ -109,11 +109,11 @@ import {
|
||||
} from '$lib/stores/ae_stores';
|
||||
// import { db_events } from "$lib/ae_events/db_events";
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct,
|
||||
events_trigger
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
|
||||
import Event_launcher_file_cont from './launcher_file_cont.svelte';
|
||||
@@ -173,7 +173,7 @@ let ae_promises: key_val = $state({
|
||||
hide_created_on={true}
|
||||
hide_os={true}
|
||||
hide_size={true}
|
||||
show_internal_purpose_files={$events_loc.launcher.show_content__internal_files}
|
||||
show_internal_purpose_files={launcher_loc.current.show_content__internal_files}
|
||||
show_bak_download={$ae_loc.trusted_access &&
|
||||
$ae_loc.edit_mode}
|
||||
btn_size={'btn-sm'}
|
||||
@@ -216,7 +216,7 @@ let ae_promises: key_val = $state({
|
||||
hide_created_on={true}
|
||||
hide_os={true}
|
||||
hide_size={true}
|
||||
show_internal_purpose_files={$events_loc.launcher.show_content__internal_files}
|
||||
show_internal_purpose_files={launcher_loc.current.show_content__internal_files}
|
||||
show_bak_download={$ae_loc.trusted_access &&
|
||||
$ae_loc.edit_mode}
|
||||
btn_size={'btn-sm'}
|
||||
|
||||
@@ -9,7 +9,8 @@ let { lq__event_presentation_obj, session_type = '' }: Props = $props();
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import Event_launcher_file_cont from './launcher_file_cont.svelte';
|
||||
|
||||
@@ -60,7 +61,7 @@ let lq__event_file_obj_li = $derived(
|
||||
{#each $lq__event_file_obj_li as event_file_obj (event_file_obj.event_file_id)}
|
||||
<li
|
||||
class="flex flex-col flex-wrap items-center justify-start gap-1 md:flex-row"
|
||||
class:hidden={!$events_loc.launcher
|
||||
class:hidden={!launcher_loc.current
|
||||
.show_content__hidden_files && event_file_obj.hide}>
|
||||
<Event_launcher_file_cont
|
||||
event_file_id={event_file_obj.event_file_id}
|
||||
@@ -68,7 +69,7 @@ let lq__event_file_obj_li = $derived(
|
||||
hide_created_on={false}
|
||||
hide_meta={session_type == 'poster'}
|
||||
bind:show_internal_purpose_files={
|
||||
$events_loc.launcher.show_content__internal_files
|
||||
launcher_loc.current.show_content__internal_files
|
||||
}
|
||||
show_bak_download={$ae_loc.trusted_access}
|
||||
session_type={session_type || 'oral'}
|
||||
|
||||
@@ -24,11 +24,11 @@ import {
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct,
|
||||
events_trigger
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
// import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
|
||||
import Event_launcher_file_cont from './launcher_file_cont.svelte';
|
||||
@@ -90,14 +90,14 @@ let lq__event_file_obj_li = $derived(
|
||||
{#each $lq__event_file_obj_li as event_file_obj, index (event_file_obj.event_file_id)}
|
||||
<li
|
||||
class="flex flex-col flex-wrap items-center justify-start gap-1 md:flex-row"
|
||||
class:hidden={!$events_loc.launcher
|
||||
class:hidden={!launcher_loc.current
|
||||
.show_content__hidden_files && event_file_obj.hide}>
|
||||
<Event_launcher_file_cont
|
||||
event_file_id={event_file_obj.event_file_id}
|
||||
{event_file_obj}
|
||||
hide_created_on={false}
|
||||
bind:show_internal_purpose_files={
|
||||
$events_loc.launcher.show_content__internal_files
|
||||
launcher_loc.current.show_content__internal_files
|
||||
}
|
||||
show_bak_download={$ae_loc.trusted_access}
|
||||
session_type={session_type || 'oral'}
|
||||
|
||||
@@ -24,11 +24,11 @@ import {
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct,
|
||||
events_trigger
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
// import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
|
||||
import Event_launcher_file_cont from './launcher_file_cont.svelte';
|
||||
@@ -84,14 +84,14 @@ let lq__event_file_obj_li = $derived(
|
||||
{#each $lq__event_file_obj_li as event_file_obj, index (event_file_obj.event_file_id)}
|
||||
<li
|
||||
class="wrap gap flex flex-col items-center justify-center md:flex-row"
|
||||
class:hidden={!$events_loc.launcher
|
||||
class:hidden={!launcher_loc.current
|
||||
.show_content__hidden_files && event_file_obj.hide}>
|
||||
<Event_launcher_file_cont
|
||||
event_file_id={event_file_obj.event_file_id}
|
||||
{event_file_obj}
|
||||
hide_created_on={false}
|
||||
hide_meta={true}
|
||||
show_internal_purpose_files={$events_loc.launcher.show_content__internal_files}
|
||||
show_internal_purpose_files={launcher_loc.current.show_content__internal_files}
|
||||
show_bak_download={$ae_loc.trusted_access}
|
||||
session_type="poster"
|
||||
open_method="modal"
|
||||
|
||||
@@ -33,11 +33,11 @@ import {
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct,
|
||||
events_trigger
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import {
|
||||
TriangleAlert,
|
||||
@@ -198,23 +198,23 @@ let ae_promises: key_val = $state({});
|
||||
class="event_session_about flex flex-col items-stretch gap-0.5 border-b-2 border-gray-400 dark:border-gray-600">
|
||||
<h3
|
||||
class:hidden={!$lq__event_session_obj?.start_datetime ||
|
||||
$events_loc.launcher.hide__session_datetimes}
|
||||
launcher_loc.current.hide__session_datetimes}
|
||||
class="event_session_datetimes text-center text-sm">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
if (
|
||||
$events_loc.launcher.time_format ==
|
||||
launcher_loc.current.time_format ==
|
||||
'time_12_short'
|
||||
) {
|
||||
// $events_loc.launcher.datetime_format = 'datetime_long';
|
||||
$events_loc.launcher.time_format = 'time_short';
|
||||
$events_loc.launcher.time_hours = 24;
|
||||
// launcher_loc.current.datetime_format = 'datetime_long';
|
||||
launcher_loc.current.time_format = 'time_short';
|
||||
launcher_loc.current.time_hours = 24;
|
||||
} else {
|
||||
$events_loc.launcher.time_format =
|
||||
launcher_loc.current.time_format =
|
||||
'time_12_short';
|
||||
// $events_loc.launcher.datetime_format = 'datetime_12_long';
|
||||
$events_loc.launcher.time_hours = 12;
|
||||
// launcher_loc.current.datetime_format = 'datetime_12_long';
|
||||
launcher_loc.current.time_hours = 12;
|
||||
}
|
||||
}}>
|
||||
<strong
|
||||
@@ -231,13 +231,13 @@ let ae_promises: key_val = $state({});
|
||||
<strong
|
||||
>{ae_util.iso_datetime_formatter(
|
||||
$lq__event_session_obj.start_datetime,
|
||||
$events_loc.launcher.time_format
|
||||
launcher_loc.current.time_format
|
||||
)}</strong>
|
||||
<span class="font-normal">
|
||||
–
|
||||
{ae_util.iso_datetime_formatter(
|
||||
$lq__event_session_obj.end_datetime,
|
||||
$events_loc.launcher.time_format
|
||||
launcher_loc.current.time_format
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
@@ -248,7 +248,7 @@ let ae_promises: key_val = $state({});
|
||||
<!-- grow + line-clamp-2 = stable 2-line max; title provides full text for screen readers + hover -->
|
||||
<h2
|
||||
class="line-clamp-2 min-w-0 grow text-xl"
|
||||
title={`Name: ${$lq__event_session_obj.name}\nType: ${$lq__event_session_obj.type_code} \nCode: ${$lq__event_session_obj.code} \nID: ${$lq__event_session_obj.event_session_id} \nStart Date/Time: ${ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, 'week_long')} ${ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, $events_loc.launcher.time_format)} \nEnd Date/Time: ${ae_util.iso_datetime_formatter($lq__event_session_obj.end_datetime, $events_loc.launcher.time_format)}`}>
|
||||
title={`Name: ${$lq__event_session_obj.name}\nType: ${$lq__event_session_obj.type_code} \nCode: ${$lq__event_session_obj.code} \nID: ${$lq__event_session_obj.event_session_id} \nStart Date/Time: ${ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, 'week_long')} ${ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, launcher_loc.current.time_format)} \nEnd Date/Time: ${ae_util.iso_datetime_formatter($lq__event_session_obj.end_datetime, launcher_loc.current.time_format)}`}>
|
||||
{$lq__event_session_obj?.name}
|
||||
</h2>
|
||||
{#if $lq__event_session_obj?.code}
|
||||
@@ -292,7 +292,7 @@ let ae_promises: key_val = $state({});
|
||||
</span>
|
||||
</strong>
|
||||
</div>
|
||||
<!-- {#if $ae_loc.trusted_access || $events_loc.launcher.trusted_access}
|
||||
<!-- {#if $ae_loc.trusted_access || launcher_loc.current.trusted_access}
|
||||
<button type="button"
|
||||
type="button" class="ae_btn btn_outline_warning btn_xs" title="Upload updated or additional files"
|
||||
>
|
||||
@@ -304,14 +304,14 @@ let ae_promises: key_val = $state({});
|
||||
{#each $lq__event_file_obj_li as event_file_obj (event_file_obj.event_file_id)}
|
||||
<li
|
||||
class="flex flex-row flex-wrap items-center justify-center gap-1"
|
||||
class:hidden={!$events_loc.launcher
|
||||
class:hidden={!launcher_loc.current
|
||||
.show_content__hidden_files &&
|
||||
event_file_obj.hide}>
|
||||
<Event_launcher_file_cont
|
||||
event_file_id={event_file_obj.event_file_id}
|
||||
{event_file_obj}
|
||||
hide_created_on={true}
|
||||
show_internal_purpose_files={$events_loc.launcher
|
||||
show_internal_purpose_files={launcher_loc.current
|
||||
.show_content__internal_files}
|
||||
show_bak_download={$ae_loc.trusted_access &&
|
||||
$ae_loc.edit_mode}
|
||||
@@ -332,7 +332,7 @@ let ae_promises: key_val = $state({});
|
||||
.modal__event_file_obj
|
||||
} />
|
||||
|
||||
<!-- <Launcher_file_cont {event_file_obj} hide_created_on={false} show_bak_download={($ae_loc.trusted_access || $events_loc.launcher.trusted_access)} open_file_as={$lq__event_session_obj.type_code} poster_title={$lq__event_session_obj.title} /> -->
|
||||
<!-- <Launcher_file_cont {event_file_obj} hide_created_on={false} show_bak_download={($ae_loc.trusted_access || launcher_loc.current.trusted_access)} open_file_as={$lq__event_session_obj.type_code} poster_title={$lq__event_session_obj.title} /> -->
|
||||
|
||||
<!-- <a
|
||||
href="{$ae_api.base_url}/event/file/{event_file_obj.event_file_id}/download?filename={event_file_obj.filename}&key={$ae_api.account_id}"
|
||||
|
||||
@@ -25,7 +25,8 @@ let {
|
||||
import { liveQuery } from 'dexie';
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
|
||||
import Event_launcher_file_cont from './launcher_file_cont.svelte';
|
||||
import { Image, Images, LoaderCircle, User, Users } from '@lucide/svelte';
|
||||
@@ -142,14 +143,14 @@ let poster_count = $derived($lq__event_presentation_obj_li?.length ?? 0);
|
||||
<ul class="flex flex-row flex-wrap gap-2">
|
||||
{#each $lq__event_file_obj_li as event_file_obj (event_file_obj.event_file_id)}
|
||||
<li
|
||||
class:hidden={!$events_loc.launcher
|
||||
class:hidden={!launcher_loc.current
|
||||
.show_content__hidden_files &&
|
||||
event_file_obj.hide}>
|
||||
<Event_launcher_file_cont
|
||||
event_file_id={event_file_obj.event_file_id}
|
||||
{event_file_obj}
|
||||
hide_created_on={true}
|
||||
show_internal_purpose_files={$events_loc.launcher
|
||||
show_internal_purpose_files={launcher_loc.current
|
||||
.show_content__internal_files}
|
||||
show_bak_download={$ae_loc.trusted_access &&
|
||||
$ae_loc.edit_mode}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
import { Moon, Sun, Eye, EyeOff, Columns2, Copy, XCircle, Trash, Recycle } from '@lucide/svelte';
|
||||
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import * as native from '$lib/electron/electron_relay';
|
||||
|
||||
interface Props {
|
||||
@@ -37,11 +37,11 @@ let { log_lvl = $bindable(0) }: Props = $props();
|
||||
|
||||
// Persist display mode across reloads — reflects the last-set state, not hardware-queried state.
|
||||
let quick_display_mode = $state<'extend' | 'mirror'>(
|
||||
($events_loc.launcher as any)?.display_mode ?? 'extend'
|
||||
(launcher_loc.current as any)?.display_mode ?? 'extend'
|
||||
);
|
||||
|
||||
const is_native_launcher_mode = $derived(
|
||||
!!$ae_loc.is_native && $events_loc.launcher.app_mode === 'native'
|
||||
!!$ae_loc.is_native && launcher_loc.current.app_mode === 'native'
|
||||
);
|
||||
|
||||
async function toggle_display_mode() {
|
||||
@@ -50,11 +50,11 @@ async function toggle_display_mode() {
|
||||
const res = await native.set_display_layout({ mode: next });
|
||||
if (res?.success) {
|
||||
quick_display_mode = next;
|
||||
($events_loc.launcher as any).display_mode = next;
|
||||
(launcher_loc.current as any).display_mode = next;
|
||||
}
|
||||
} else {
|
||||
quick_display_mode = next;
|
||||
($events_loc.launcher as any).display_mode = next;
|
||||
(launcher_loc.current as any).display_mode = next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,25 +112,25 @@ function handle_reload_launcher() {
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
if ($events_loc.launcher.show_content__hidden_files) {
|
||||
$events_loc.launcher.show_content__hidden_files = false;
|
||||
$events_loc.launcher.show_content__internal_files = false;
|
||||
if (launcher_loc.current.show_content__hidden_files) {
|
||||
launcher_loc.current.show_content__hidden_files = false;
|
||||
launcher_loc.current.show_content__internal_files = false;
|
||||
} else {
|
||||
$events_loc.launcher.show_content__hidden_files = true;
|
||||
$events_loc.launcher.show_content__internal_files = true;
|
||||
launcher_loc.current.show_content__hidden_files = true;
|
||||
launcher_loc.current.show_content__internal_files = true;
|
||||
}
|
||||
}}
|
||||
class="btn btn-sm min-w-34 w-34 max-w-1/2 text-xs transition-all"
|
||||
class:preset-tonal-warning={$events_loc.launcher.show_content__hidden_files}
|
||||
class:hover:preset-filled-warning-500={$events_loc.launcher
|
||||
class:preset-tonal-warning={launcher_loc.current.show_content__hidden_files}
|
||||
class:hover:preset-filled-warning-500={launcher_loc.current
|
||||
.show_content__hidden_files}
|
||||
class:preset-tonal-tertiary={!$events_loc.launcher.show_content__hidden_files}
|
||||
class:hover:preset-filled-tertiary-500={!$events_loc.launcher
|
||||
class:preset-tonal-tertiary={!launcher_loc.current.show_content__hidden_files}
|
||||
class:hover:preset-filled-tertiary-500={!launcher_loc.current
|
||||
.show_content__hidden_files}
|
||||
title={$events_loc.launcher.show_content__hidden_files
|
||||
title={launcher_loc.current.show_content__hidden_files
|
||||
? 'Showing all files including hidden and draft. Tap to hide them again.'
|
||||
: 'Showing only public files. Tap to show all files including hidden and draft.'}>
|
||||
{#if $events_loc.launcher.show_content__hidden_files}
|
||||
{#if launcher_loc.current.show_content__hidden_files}
|
||||
<EyeOff size="0.85em" class="m-1" />
|
||||
Hide Files
|
||||
{:else}
|
||||
@@ -143,20 +143,20 @@ function handle_reload_launcher() {
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
$events_loc.launcher.show_content__hidden_sessions =
|
||||
!$events_loc.launcher.show_content__hidden_sessions;
|
||||
launcher_loc.current.show_content__hidden_sessions =
|
||||
!launcher_loc.current.show_content__hidden_sessions;
|
||||
}}
|
||||
class="btn btn-sm min-w-34 w-34 max-w-1/2 text-xs transition-all"
|
||||
class:preset-tonal-warning={$events_loc.launcher.show_content__hidden_sessions}
|
||||
class:hover:preset-filled-warning-500={$events_loc.launcher
|
||||
class:preset-tonal-warning={launcher_loc.current.show_content__hidden_sessions}
|
||||
class:hover:preset-filled-warning-500={launcher_loc.current
|
||||
.show_content__hidden_sessions}
|
||||
class:preset-tonal-tertiary={!$events_loc.launcher.show_content__hidden_sessions}
|
||||
class:hover:preset-filled-tertiary-500={!$events_loc.launcher
|
||||
class:preset-tonal-tertiary={!launcher_loc.current.show_content__hidden_sessions}
|
||||
class:hover:preset-filled-tertiary-500={!launcher_loc.current
|
||||
.show_content__hidden_sessions}
|
||||
title={$events_loc.launcher.show_content__hidden_sessions
|
||||
title={launcher_loc.current.show_content__hidden_sessions
|
||||
? 'Showing all sessions including cancelled and hidden. Tap to hide them again.'
|
||||
: 'Showing only active sessions. Tap to show all sessions including hidden and cancelled.'}>
|
||||
{#if $events_loc.launcher.show_content__hidden_sessions}
|
||||
{#if launcher_loc.current.show_content__hidden_sessions}
|
||||
<EyeOff size="0.85em" class="shrink-0" />
|
||||
Hide Sessions
|
||||
{:else}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* DATA FLOW:
|
||||
* lq__event_location_obj_li (Dexie liveQuery, passed from launcher_menu.svelte)
|
||||
* → rendered as <select> options
|
||||
* → onchange writes to $events_slct.event_location_id and $events_loc.launcher.slct
|
||||
* → onchange writes to $events_slct.event_location_id and launcher_loc.current.slct
|
||||
* → calls handle_load_ae_obj_li__event_session() to fetch sessions for the new room
|
||||
* → navigates to /launcher/{location_id} via goto()
|
||||
*
|
||||
@@ -68,11 +68,11 @@ import {
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct,
|
||||
events_trigger
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import { Check, LoaderCircle } from '@lucide/svelte';
|
||||
// export let slct_event_session_id: any;
|
||||
@@ -110,10 +110,10 @@ function handle_load_ae_obj_li__event_session(event_location_id: string) {
|
||||
inc_all_file_li: false, // Also include files under presentations and presenters as well?
|
||||
inc_presentation_li: true,
|
||||
inc_presenter_li: true,
|
||||
enabled: $events_loc.launcher.show_content__enabled_sessions
|
||||
enabled: launcher_loc.current.show_content__enabled_sessions
|
||||
? 'all'
|
||||
: 'enabled',
|
||||
hidden: $events_loc.launcher.show_content__hidden_sessions
|
||||
hidden: launcher_loc.current.show_content__hidden_sessions
|
||||
? 'all'
|
||||
: 'not_hidden',
|
||||
limit: 49,
|
||||
@@ -195,7 +195,7 @@ function handle_load_ae_obj_li__event_session(event_location_id: string) {
|
||||
if (slct_event_location_id) {
|
||||
loading__session_li_status = 'loading';
|
||||
|
||||
$events_loc.launcher.slct.event_location_id =
|
||||
launcher_loc.current.slct.event_location_id =
|
||||
slct_event_location_id;
|
||||
$events_slct.event_location_id = slct_event_location_id;
|
||||
|
||||
@@ -211,9 +211,9 @@ function handle_load_ae_obj_li__event_session(event_location_id: string) {
|
||||
// This will hide the selected session if the location is changed to false.
|
||||
// WARNING: This may need to be commented out later.
|
||||
// slct_event_session_id = null;
|
||||
$events_loc.launcher.slct.event_location_id = null;
|
||||
launcher_loc.current.slct.event_location_id = null;
|
||||
$events_slct.event_location_id = null;
|
||||
$events_loc.launcher.slct.event_session_id = null;
|
||||
launcher_loc.current.slct.event_session_id = null;
|
||||
$events_slct.event_session_id = null;
|
||||
|
||||
loading__session_li_status = 'finished';
|
||||
|
||||
@@ -84,11 +84,11 @@ import {
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
import {
|
||||
events_loc,
|
||||
events_sess,
|
||||
events_slct,
|
||||
events_trigger
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
|
||||
import {
|
||||
CalendarCheck,
|
||||
CalendarDays,
|
||||
@@ -141,7 +141,7 @@ $effect(() => {
|
||||
}
|
||||
|
||||
// 3. Remote Control Sync
|
||||
if ($events_loc.launcher.controller == 'local_push') {
|
||||
if (launcher_loc.current.controller == 'local_push') {
|
||||
$events_sess.launcher.controller_cmd = `ae_load:event_session=${event_session_id}`;
|
||||
$events_sess.launcher.controller_trigger_send = true;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ $effect(() => {
|
||||
"
|
||||
class:session-active={slct__event_session_id ===
|
||||
event_session_obj?.id}
|
||||
class:hidden={!$events_loc.launcher
|
||||
class:hidden={!launcher_loc.current
|
||||
.show_content__hidden_sessions &&
|
||||
(event_session_obj?.hide ||
|
||||
event_session_obj?.hide_event_launcher)}>
|
||||
@@ -263,7 +263,7 @@ $effect(() => {
|
||||
class:preset-tonal-secondary={slct__event_session_id != event_session_obj?.id}
|
||||
class:preset-outlined-secondary-200-800={slct__event_session_id != event_session_obj?.id}
|
||||
class:opacity-40={event_session_obj?.hide || event_session_obj?.hide_event_launcher}
|
||||
title={`Session: ${event_session_obj?.name}\nID: ${event_session_obj?.id} | ${ae_util.iso_datetime_formatter(event_session_obj?.start_datetime, $events_loc.launcher.time_format)}`}>
|
||||
title={`Session: ${event_session_obj?.name}\nID: ${event_session_obj?.id} | ${ae_util.iso_datetime_formatter(event_session_obj?.start_datetime, launcher_loc.current.time_format)}`}>
|
||||
<!-- Session row layout: [date column | session name]
|
||||
Date column is fixed-width (shrink-0) so name column always
|
||||
gets consistent space regardless of date string length.
|
||||
@@ -293,7 +293,7 @@ $effect(() => {
|
||||
<span class="text-xs">
|
||||
{ae_util.iso_datetime_formatter(
|
||||
event_session_obj?.start_datetime,
|
||||
$events_loc.launcher.time_format
|
||||
launcher_loc.current.time_format
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user