A photo manager for VRChat.

add update prompt

phaz.uk a2d26546 b9839947

verified
Changed files
+29 -59
public
src
src-tauri
+3 -2
changelog
··· 109 - Fixed scroll to top button not animating out 110 - Fixed scroll to top button being ontop of filters menu 111 - Fixed photo ordering 112 - - Fixed automatic updates 113 - Fixed broken legacy named photos 114 - Fixed photos being loaded with the wrong resolution 115 116 - Added support for multilayer photos 117 - Added close to tray toggle 118 119 - - Remove all sync stuff
··· 109 - Fixed scroll to top button not animating out 110 - Fixed scroll to top button being ontop of filters menu 111 - Fixed photo ordering 112 - Fixed broken legacy named photos 113 - Fixed photos being loaded with the wrong resolution 114 115 - Added support for multilayer photos 116 - Added close to tray toggle 117 + - Added update available prompt 118 119 + - Remove all sync stuff 120 + - Removed automatic updates
+1
public/icon/download-solid-full.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path fill="#fff" d="M352 96C352 78.3 337.7 64 320 64C302.3 64 288 78.3 288 96L288 306.7L246.6 265.3C234.1 252.8 213.8 252.8 201.3 265.3C188.8 277.8 188.8 298.1 201.3 310.6L297.3 406.6C309.8 419.1 330.1 419.1 342.6 406.6L438.6 310.6C451.1 298.1 451.1 277.8 438.6 265.3C426.1 252.8 405.8 252.8 393.3 265.3L352 306.7L352 96zM160 384C124.7 384 96 412.7 96 448L96 480C96 515.3 124.7 544 160 544L480 544C515.3 544 544 515.3 544 480L544 448C544 412.7 515.3 384 480 384L433.1 384L376.5 440.6C345.3 471.8 294.6 471.8 263.4 440.6L206.9 384L160 384zM464 440C477.3 440 488 450.7 488 464C488 477.3 477.3 488 464 488C450.7 488 440 477.3 440 464C440 450.7 450.7 440 464 440z"/></svg>
-54
src-tauri/gen/schemas/windows-schema.json
··· 2433 "markdownDescription": "Denies the unminimize command without any pre-configured scope." 2434 }, 2435 { 2436 - "description": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`", 2437 - "type": "string", 2438 - "const": "deep-link:default", 2439 - "markdownDescription": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`" 2440 - }, 2441 - { 2442 - "description": "Enables the get_current command without any pre-configured scope.", 2443 - "type": "string", 2444 - "const": "deep-link:allow-get-current", 2445 - "markdownDescription": "Enables the get_current command without any pre-configured scope." 2446 - }, 2447 - { 2448 - "description": "Enables the is_registered command without any pre-configured scope.", 2449 - "type": "string", 2450 - "const": "deep-link:allow-is-registered", 2451 - "markdownDescription": "Enables the is_registered command without any pre-configured scope." 2452 - }, 2453 - { 2454 - "description": "Enables the register command without any pre-configured scope.", 2455 - "type": "string", 2456 - "const": "deep-link:allow-register", 2457 - "markdownDescription": "Enables the register command without any pre-configured scope." 2458 - }, 2459 - { 2460 - "description": "Enables the unregister command without any pre-configured scope.", 2461 - "type": "string", 2462 - "const": "deep-link:allow-unregister", 2463 - "markdownDescription": "Enables the unregister command without any pre-configured scope." 2464 - }, 2465 - { 2466 - "description": "Denies the get_current command without any pre-configured scope.", 2467 - "type": "string", 2468 - "const": "deep-link:deny-get-current", 2469 - "markdownDescription": "Denies the get_current command without any pre-configured scope." 2470 - }, 2471 - { 2472 - "description": "Denies the is_registered command without any pre-configured scope.", 2473 - "type": "string", 2474 - "const": "deep-link:deny-is-registered", 2475 - "markdownDescription": "Denies the is_registered command without any pre-configured scope." 2476 - }, 2477 - { 2478 - "description": "Denies the register command without any pre-configured scope.", 2479 - "type": "string", 2480 - "const": "deep-link:deny-register", 2481 - "markdownDescription": "Denies the register command without any pre-configured scope." 2482 - }, 2483 - { 2484 - "description": "Denies the unregister command without any pre-configured scope.", 2485 - "type": "string", 2486 - "const": "deep-link:deny-unregister", 2487 - "markdownDescription": "Denies the unregister command without any pre-configured scope." 2488 - }, 2489 - { 2490 "description": "This permission set configures what kind of\nfetch operations are available from the http plugin.\n\nThis enables all fetch operations but does not\nallow explicitly any origins to be fetched. This needs to\nbe manually configured before usage.\n\n#### Granted Permissions\n\nAll fetch operations are enabled.\n\n\n#### This default permission set includes:\n\n- `allow-fetch`\n- `allow-fetch-cancel`\n- `allow-fetch-read-body`\n- `allow-fetch-send`", 2491 "type": "string", 2492 "const": "http:default",
··· 2433 "markdownDescription": "Denies the unminimize command without any pre-configured scope." 2434 }, 2435 { 2436 "description": "This permission set configures what kind of\nfetch operations are available from the http plugin.\n\nThis enables all fetch operations but does not\nallow explicitly any origins to be fetched. This needs to\nbe manually configured before usage.\n\n#### Granted Permissions\n\nAll fetch operations are enabled.\n\n\n#### This default permission set includes:\n\n- `allow-fetch`\n- `allow-fetch-cancel`\n- `allow-fetch-read-body`\n- `allow-fetch-send`", 2437 "type": "string", 2438 "const": "http:default",
+1 -1
src-tauri/tauri.conf.json
··· 23 }, 24 "app": { 25 "security": { 26 - "csp": "connect-src ipc: http://ipc.localhost" 27 }, 28 "windows": [ 29 {
··· 23 }, 24 "app": { 25 "security": { 26 + "csp": "connect-src https://api.github.com ipc: http://ipc.localhost" 27 }, 28 "windows": [ 29 {
+23 -1
src/Components/PhotoList.tsx
··· 1 - import { onCleanup, onMount } from "solid-js"; 2 import { listen } from '@tauri-apps/api/event'; 3 import { Window } from "@tauri-apps/api/window"; 4 ··· 28 let quitRender: boolean = true; 29 30 let currentPopup = ListPopup.NONE; 31 32 Window.getCurrent().isVisible().then(visible => { 33 quitRender = !visible; ··· 158 }); 159 160 onMount(() => { 161 ctx = photoContainer.getContext('2d')!; 162 163 window.PhotoManager.Load(); ··· 258 </div> 259 <div class="icon-label">Settings</div> 260 </div> 261 </div> 262 263 <canvas class="photo-container" ref={( el ) => photoContainer = el}></canvas>
··· 1 + import { createSignal, onCleanup, onMount, Show } from "solid-js"; 2 import { listen } from '@tauri-apps/api/event'; 3 import { Window } from "@tauri-apps/api/window"; 4 ··· 28 let quitRender: boolean = true; 29 30 let currentPopup = ListPopup.NONE; 31 + 32 + let [ updateAvailable, setUpdateAvailable ] = createSignal(false); 33 34 Window.getCurrent().isVisible().then(visible => { 35 quitRender = !visible; ··· 160 }); 161 162 onMount(() => { 163 + // Update Stuff 164 + fetch('https://api.github.com/repos/phaze-the-dumb/VRChat-Photo-Manager/releases/latest') 165 + .then(data => data.json()) 166 + .then(async data => { 167 + let currentVersion = await invoke('get_version'); 168 + setUpdateAvailable(data.tag_name !== currentVersion); 169 + }) 170 + 171 + // Other Stuff 172 ctx = photoContainer.getContext('2d')!; 173 174 window.PhotoManager.Load(); ··· 269 </div> 270 <div class="icon-label">Settings</div> 271 </div> 272 + 273 + <Show when={updateAvailable()}> 274 + <div> 275 + <div onClick={() => { 276 + invoke('open_url', { url: 'https://github.com/phaze-the-dumb/VRChat-Photo-Manager/releases/latest' }); 277 + }} class="icon"> 278 + <img draggable="false" style={{ width: "20px", height: "20px" }} src="/icon/download-solid-full.svg"></img> 279 + </div> 280 + <div class="icon-label">Update Available</div> 281 + </div> 282 + </Show> 283 </div> 284 285 <canvas class="photo-container" ref={( el ) => photoContainer = el}></canvas>
+1 -1
src/Components/PhotoViewer.tsx
··· 1 import { For, Show, createEffect, onCleanup, onMount } from "solid-js"; 2 import { invoke } from '@tauri-apps/api/core'; 3 import { WorldCache } from "./Structs/WorldCache"; 4 - import { animate, createSpring, JSAnimation, utils } from "animejs"; 5 6 let PhotoViewer = () => { 7 let viewer: HTMLElement;
··· 1 import { For, Show, createEffect, onCleanup, onMount } from "solid-js"; 2 import { invoke } from '@tauri-apps/api/core'; 3 import { WorldCache } from "./Structs/WorldCache"; 4 + import { animate, JSAnimation, utils } from "animejs"; 5 6 let PhotoViewer = () => { 7 let viewer: HTMLElement;