feat(launcher): restore macOS default wallpaper + external-only apply fix
- electron_relay: add restore_macos_default_wallpaper() — uses run_osascript to find first .heic in /System/Library/Desktop Pictures/ (version-agnostic) - wallpaper cfg: Restore macOS Default button (native or edit_mode); clears applied-URL tracking so next configured URL re-applies correctly - wallpaper cfg: fix Apply Now / Save & Apply enabled when only external URL is filled; display target becomes 'external' to leave built-in unchanged Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -413,6 +413,38 @@ export async function set_wallpaper({
|
||||
return await native.set_wallpaper({ path, url, url_external, display, api_key, account_id });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the macOS default wallpaper on all displays.
|
||||
* Scans /System/Library/Desktop Pictures/ for the first .heic file — works across
|
||||
* all recent macOS versions without needing to know the version name.
|
||||
* No-op on non-macOS (Linux/Windows return success:false from run_osascript).
|
||||
*/
|
||||
export async function restore_macos_default_wallpaper(
|
||||
display: 'all' | 'primary' | 'external' = 'all'
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const display_target =
|
||||
display === 'primary'
|
||||
? 'tell desktop 1'
|
||||
: display === 'external'
|
||||
? 'tell desktop 2'
|
||||
: 'tell every desktop';
|
||||
|
||||
const script = `
|
||||
set pic_path to do shell script "ls '/System/Library/Desktop Pictures/'*.heic 2>/dev/null | head -1"
|
||||
if pic_path is "" then
|
||||
error "No default macOS wallpaper (.heic) found in /System/Library/Desktop Pictures/"
|
||||
end if
|
||||
tell application "System Events"
|
||||
${display_target}
|
||||
set picture to pic_path
|
||||
end tell
|
||||
end tell
|
||||
`.trim();
|
||||
|
||||
const result = await run_osascript(script);
|
||||
return result ?? { success: false, error: 'Native bridge not available' };
|
||||
}
|
||||
|
||||
export async function update_app(args: {
|
||||
source: 'url' | 'file';
|
||||
url?: string;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import * as native from '$lib/electron/electron_relay';
|
||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||
import { FlaskConical, Image, Monitor, Save, Zap } from '@lucide/svelte';
|
||||
import { FlaskConical, Image, Monitor, RotateCcw, Save, Zap } from '@lucide/svelte';
|
||||
|
||||
interface Props {
|
||||
on_expand?: () => void;
|
||||
@@ -23,6 +23,7 @@ let url_input = $state('');
|
||||
let url_external_input = $state('');
|
||||
let save_status = $state('');
|
||||
let apply_status = $state('');
|
||||
let restore_status = $state('');
|
||||
let last_device_id: string | null = null;
|
||||
|
||||
function get_native_device(): NativeDeviceLike | null {
|
||||
@@ -148,6 +149,20 @@ async function handle_apply() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handle_restore_default() {
|
||||
restore_status = 'Restoring...';
|
||||
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;
|
||||
restore_status = 'Restored ✓';
|
||||
} else {
|
||||
restore_status = `Error: ${(result as any)?.error ?? 'Unknown error'}`;
|
||||
}
|
||||
setTimeout(() => { if (restore_status.startsWith('Restored') || restore_status.startsWith('Error')) restore_status = ''; }, 4000);
|
||||
}
|
||||
|
||||
async function handle_save_and_apply() {
|
||||
await handle_save();
|
||||
if (save_status !== 'Save failed' && save_status !== 'No device loaded') {
|
||||
@@ -276,6 +291,16 @@ const section_description = $derived(
|
||||
Save & Apply
|
||||
</button>
|
||||
|
||||
<!-- Restore macOS default — safety valve for end-of-show cleanup -->
|
||||
{#if $ae_loc.is_native || $ae_loc.edit_mode}
|
||||
<button
|
||||
type="button"
|
||||
onclick={handle_restore_default}
|
||||
class="btn btn-sm preset-tonal-surface h-8 w-full text-[10px] opacity-60 hover:opacity-100">
|
||||
<RotateCcw size="0.8em" class="mr-1" /> Restore macOS Default
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if save_status}
|
||||
<div
|
||||
class="text-primary-500 text-center text-[9px] italic"
|
||||
@@ -292,5 +317,14 @@ const section_description = $derived(
|
||||
{apply_status}
|
||||
</div>
|
||||
{/if}
|
||||
{#if restore_status}
|
||||
<div
|
||||
class="text-[9px] italic text-center"
|
||||
class:text-success-500={restore_status.includes('✓')}
|
||||
class:text-primary-500={restore_status === 'Restoring...'}
|
||||
class:text-error-500={restore_status.includes('Error')}>
|
||||
{restore_status}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Launcher_Cfg_Section>
|
||||
|
||||
Reference in New Issue
Block a user