A photo manager for VRChat.

remove all sync stuff

phaz.uk d3a9148d bc3c46ef

verified
Changed files
+132 -476
src
src-tauri
+1 -1
build-release.sh
··· 1 1 #!/bin/bash 2 2 3 - VERSION=0.2.5 3 + VERSION=0.2.6 4 4 5 5 # Linux builds 6 6 NO_STRIP=true pnpm tauri build
+2 -1
changelog
··· 106 106 v0.2.6: 107 107 - Fixed photos not being loaded if they're too low resolution 108 108 - Added close to tray toggle 109 - - Fixed "Open in folder" not selecting files on linux 109 + - Fixed "Open in folder" not selecting files on linux 110 + - Remove all sync stuff
-1
src-tauri/src/frontend_calls/mod.rs
··· 10 10 pub mod open_folder; 11 11 pub mod open_url; 12 12 pub mod start_with_win; 13 - pub mod sync_photos; 14 13 pub mod copy_image;
-11
src-tauri/src/frontend_calls/sync_photos.rs
··· 1 - use crate::photosync; 2 - use crate::util::get_photo_path::get_photo_path; 3 - use std::thread; 4 - 5 - // On requested sync the photos to the cloud 6 - #[tauri::command] 7 - pub fn sync_photos(token: String, window: tauri::Window) { 8 - thread::spawn(move || { 9 - photosync::sync_photos(token, get_photo_path(), window); 10 - }); 11 - }
-4
src-tauri/src/main.rs
··· 1 1 #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 2 2 3 3 mod frontend_calls; 4 - mod photosync; 5 4 mod pngmeta; 6 5 mod util; 7 6 mod worldscraper; ··· 19 18 use tauri_plugin_deep_link::DeepLinkExt; 20 19 21 20 use crate::frontend_calls::config::get_config_value_string; 22 - 23 - // TODO: Linux support 24 21 25 22 fn main() { 26 23 #[cfg(target_os = "linux")] ··· 205 202 start_with_win::start_with_win, 206 203 get_user_photos_path::get_user_photos_path, 207 204 change_final_path::change_final_path, 208 - sync_photos::sync_photos, 209 205 util::get_version::get_version, 210 206 config::set_config_value_string, 211 207 config::get_config_value_string,
-261
src-tauri/src/photosync.rs
··· 1 - use regex::Regex; 2 - use reqwest; 3 - use serde::Serialize; 4 - use serde_json::{Error, Value}; 5 - use std::{fs, io::Write, path, time::Duration}; 6 - use tauri::Emitter; 7 - 8 - #[derive(Clone, Serialize)] 9 - struct PhotoUploadMeta { 10 - photos_uploading: usize, 11 - photos_total: usize, 12 - } 13 - 14 - pub fn sync_photos(token: String, path: path::PathBuf, window: tauri::Window) { 15 - let sync_lock_path = dirs::config_dir() 16 - .unwrap() 17 - .join("PhazeDev/VRChatPhotoManager/.sync_lock"); 18 - 19 - match fs::metadata(&sync_lock_path) { 20 - Ok(_) => { 21 - return; 22 - } 23 - Err(_) => {} 24 - } 25 - 26 - fs::write(&sync_lock_path, "Currently Syncing").unwrap(); 27 - 28 - match fs::metadata(&path) { 29 - Ok(_) => {} 30 - Err(_) => { 31 - fs::create_dir(&path).unwrap(); 32 - } 33 - }; 34 - 35 - let mut photos: Vec<String> = Vec::new(); 36 - 37 - for folder in fs::read_dir(&path).unwrap() { 38 - let f = folder.unwrap(); 39 - 40 - if f.metadata().unwrap().is_dir() { 41 - match fs::read_dir(f.path()) { 42 - Ok(dir) => { 43 - for photo in dir { 44 - let p = photo.unwrap(); 45 - 46 - let re1 = Regex::new(r"(?m)VRChat_[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}.[0-9]{3}_[0-9]{4}x[0-9]{4}.png").unwrap(); 47 - let re2 = Regex::new( 48 - r"(?m)VRChat_[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}.[0-9]{3}_[0-9]{4}x[0-9]{4}_wrld_[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}.png").unwrap(); 49 - 50 - if re1.is_match(p.file_name().to_str().unwrap()) 51 - || re2.is_match(p.file_name().to_str().unwrap()) 52 - { 53 - photos.push(p.file_name().into_string().unwrap()); 54 - } 55 - } 56 - } 57 - Err(_) => {} 58 - } 59 - } 60 - } 61 - 62 - let body = reqwest::blocking::get(format!( 63 - "https://photos-cdn.phazed.xyz/api/v1/photos/exists?token={}", 64 - &token 65 - )) 66 - .unwrap() 67 - .text() 68 - .unwrap(); 69 - 70 - let body: Value = serde_json::from_str(&body).unwrap(); 71 - 72 - let mut photos_to_upload: Vec<String> = Vec::new(); 73 - let uploaded_photos = body["files"].as_array().unwrap(); 74 - 75 - let photos_len = photos.len(); 76 - 77 - for photo in &photos { 78 - let mut found_photo = false; 79 - 80 - for uploaded_photo in uploaded_photos { 81 - if photo == uploaded_photo.as_str().unwrap() { 82 - found_photo = true; 83 - break; 84 - } 85 - } 86 - 87 - if !found_photo { 88 - photos_to_upload.push(photo.clone()); 89 - } 90 - } 91 - 92 - window 93 - .emit( 94 - "photos-upload-meta", 95 - PhotoUploadMeta { 96 - photos_uploading: photos_to_upload.len(), 97 - photos_total: photos_len, 98 - }, 99 - ) 100 - .unwrap(); 101 - 102 - let mut photos_left = photos_to_upload.len(); 103 - 104 - let client = reqwest::blocking::Client::new(); 105 - 106 - loop { 107 - match photos_to_upload.pop() { 108 - Some(photo) => { 109 - let folder_name = photo.clone().replace("VRChat_", ""); 110 - let mut folder_name = folder_name.split("-"); 111 - let folder_name = format!( 112 - "{}-{}", 113 - folder_name.nth(0).unwrap(), 114 - folder_name.nth(0).unwrap() 115 - ); 116 - 117 - let full_path = format!("{}\\{}\\{}", path.to_str().unwrap(), folder_name, photo); 118 - let file = fs::File::open(full_path); 119 - 120 - match file { 121 - Ok(file) => { 122 - let res = client 123 - .put(format!( 124 - "https://photos-cdn.phazed.xyz/api/v1/photos?token={}", 125 - &token 126 - )) 127 - .header("Content-Type", "image/png") 128 - .header("filename", photo) 129 - .body(file) 130 - .timeout(Duration::from_secs(120)) 131 - .send() 132 - .unwrap() 133 - .text() 134 - .unwrap(); 135 - 136 - let res: Result<Value, Error> = serde_json::from_str(&res); 137 - 138 - match res { 139 - Ok(res) => { 140 - if !res["ok"].as_bool().unwrap() { 141 - println!("Failed to upload: {}", res["error"].as_str().unwrap()); 142 - 143 - window 144 - .emit("sync-failed", res["error"].as_str().unwrap()) 145 - .unwrap(); 146 - 147 - break; 148 - } 149 - } 150 - Err(err) => { 151 - dbg!(err); 152 - } 153 - } 154 - } 155 - Err(_) => {} 156 - } 157 - 158 - photos_left -= 1; 159 - window 160 - .emit( 161 - "photos-upload-meta", 162 - PhotoUploadMeta { 163 - photos_uploading: photos_left, 164 - photos_total: photos_len, 165 - }, 166 - ) 167 - .unwrap(); 168 - } 169 - None => { 170 - break; 171 - } 172 - } 173 - } 174 - 175 - println!("Finished Uploading."); 176 - let mut photos_to_download: Vec<String> = Vec::new(); 177 - 178 - for photo in uploaded_photos { 179 - let mut found_photo = false; 180 - let photo = photo.as_str().unwrap().to_string(); 181 - 182 - for uploaded_photo in &photos { 183 - if &photo == uploaded_photo { 184 - found_photo = true; 185 - break; 186 - } 187 - } 188 - 189 - if !found_photo { 190 - photos_to_download.push(photo); 191 - } 192 - } 193 - 194 - photos_to_download.reverse(); 195 - 196 - let photos_len = photos_to_download.len(); 197 - let mut photos_left = photos_to_download.len(); 198 - 199 - loop { 200 - match photos_to_download.pop() { 201 - Some(photo) => { 202 - let folder_name = photo.clone().replace("VRChat_", ""); 203 - let mut folder_name = folder_name.split("-"); 204 - let folder_name = format!( 205 - "{}-{}", 206 - folder_name.nth(0).unwrap(), 207 - folder_name.nth(0).unwrap() 208 - ); 209 - 210 - let full_path = format!("{}/{}/{}", path.to_str().unwrap(), folder_name, photo); 211 - 212 - let res = client 213 - .get(format!( 214 - "https://photos-cdn.phazed.xyz/api/v1/photos?token={}&photo={}", 215 - &token, &photo 216 - )) 217 - .timeout(Duration::from_secs(120)) 218 - .send() 219 - .unwrap() 220 - .bytes(); 221 - 222 - match res { 223 - Ok(res) => { 224 - let folder_path = format!("{}/{}", path.to_str().unwrap(), folder_name); 225 - match fs::metadata(&folder_path) { 226 - Ok(_) => {} 227 - Err(_) => { 228 - fs::create_dir(folder_path).unwrap(); 229 - } 230 - } 231 - 232 - let mut file = fs::File::create(full_path).unwrap(); 233 - file.write_all(&res).unwrap(); 234 - } 235 - Err(err) => { 236 - dbg!(err); 237 - } 238 - } 239 - 240 - photos_left -= 1; 241 - window 242 - .emit( 243 - "photos-download-meta", 244 - PhotoUploadMeta { 245 - photos_uploading: photos_left, 246 - photos_total: photos_len, 247 - }, 248 - ) 249 - .unwrap(); 250 - } 251 - None => { 252 - break; 253 - } 254 - } 255 - } 256 - 257 - println!("Finished Downloading."); 258 - 259 - fs::remove_file(&sync_lock_path).unwrap(); 260 - window.emit("sync-finished", "h").unwrap(); 261 - }
-6
src-tauri/src/util/handle_uri_proto.rs
··· 33 33 return; 34 34 } 35 35 36 - // TODO: Only accept files that are in the vrchat photos folder 37 - // Slightly more complex than originally thought, need to find a way to cache the VRC photos path 38 - // since i need to be able to load lots of photos very quickly. This shouldn't be a security issue 39 - // because tauri should only let the frontend of VRCPhotoManager read files throught this. Only 40 - // becomes a potential issue if the frontend gets modified or there's an issue with tauri. 41 - 42 36 #[cfg(windows)] 43 37 let path = uri.path().split_at(1).1; 44 38
-56
src/Components/Managers/SyncManager.tsx
··· 1 - import { invoke } from "@tauri-apps/api/core"; 2 - import { listen } from "@tauri-apps/api/event"; 3 - import { Accessor, createSignal, Setter } from "solid-js"; 4 - 5 - export class SyncManager{ 6 - private _setIsSyncing: Setter<boolean>; 7 - private _setSyncPhotoTotal: Setter<number>; 8 - private _setSyncPhotoTransfers: Setter<number>; 9 - private _setSyncType: Setter<string>; 10 - private _setSyncError: Setter<string>; 11 - 12 - public IsSyncing: Accessor<boolean>; 13 - public SyncPhotoTotal: Accessor<number>; 14 - public SyncPhotoTransfers: Accessor<number> 15 - public SyncType: Accessor<string>; 16 - public SyncError: Accessor<string>; 17 - 18 - constructor(){ 19 - [ this.IsSyncing, this._setIsSyncing ] = createSignal(false); 20 - [ this.SyncPhotoTotal, this._setSyncPhotoTotal ] = createSignal(-1); 21 - [ this.SyncPhotoTransfers, this._setSyncPhotoTransfers ] = createSignal(-1); 22 - [ this.SyncType, this._setSyncType ] = createSignal(""); 23 - [ this.SyncError, this._setSyncError ] = createSignal(""); 24 - 25 - listen('photos-upload-meta', ( e: any ) => { 26 - this._setIsSyncing(true); 27 - this._setSyncPhotoTotal(e.payload.photos_total); 28 - this._setSyncPhotoTransfers(e.payload.photos_total - e.payload.photos_uploading); 29 - this._setSyncType('Upload'); 30 - 31 - console.log(e.payload) 32 - }) 33 - 34 - listen('photos-download-meta', ( e: any ) => { 35 - this._setIsSyncing(true); 36 - this._setSyncPhotoTotal(e.payload.photos_total); 37 - this._setSyncPhotoTransfers(e.payload.photos_total - e.payload.photos_uploading); 38 - this._setSyncType('Download'); 39 - 40 - console.log(e.payload) 41 - }) 42 - 43 - listen('sync-finished', () => { 44 - this._setIsSyncing(false); 45 - }) 46 - 47 - listen('sync-failed', ( e: any ) => { 48 - this._setSyncError(e.payload); 49 - }) 50 - } 51 - 52 - public async TriggerSync(){ 53 - this._setIsSyncing(true); 54 - invoke('sync_photos', { token: (await invoke('get_config_value_string', { key: 'token' })) }); 55 - } 56 - }
+129 -132
src/Components/SettingsMenu.tsx
··· 5 5 import { animate, utils } from "animejs"; 6 6 7 7 let SettingsMenu = () => { 8 - let sliderBar: HTMLElement; 8 + // let sliderBar: HTMLElement; 9 9 let settingsContainer: HTMLElement; 10 - let currentButton = 0; 11 - let lastClickedButton = -1; 10 + // let currentButton = 0; 11 + // let lastClickedButton = -1; 12 12 let finalPathConfirm: HTMLElement; 13 13 let finalPathInput: HTMLElement; 14 14 let finalPathData: string; ··· 42 42 animate('.settings', { background: 'rgba(0, 0, 0, 0)', easing: 'linear', duration: 100 }); 43 43 } 44 44 45 - let sliderMouseDown = false; 46 - let mouseStartX = 0; 45 + // let sliderMouseDown = false; 46 + // let mouseStartX = 0; 47 47 48 - let width = window.innerWidth; 49 - let buttons = [ 370, 680 ]; 48 + // let width = window.innerWidth; 49 + // let buttons = [ 370, 680 ]; 50 50 51 - let sliderPos = width / 2 - buttons[currentButton]; 52 - let sliderScale = width / (buttons[1] - buttons[0]); 51 + // let sliderPos = width / 2 - buttons[currentButton]; 52 + // let sliderScale = width / (buttons[1] - buttons[0]); 53 53 54 - let render = () => { 55 - requestAnimationFrame(render); 54 + // let render = () => { 55 + // requestAnimationFrame(render); 56 56 57 - if(!sliderMouseDown){ 58 - sliderPos = sliderPos + (width / 2 - buttons[currentButton] - sliderPos) * 0.25; 59 - utils.set(sliderBar, { translateX: sliderPos }); 57 + // if(!sliderMouseDown){ 58 + // sliderPos = sliderPos + (width / 2 - buttons[currentButton] - sliderPos) * 0.25; 59 + // utils.set(sliderBar, { translateX: sliderPos }); 60 60 61 - settingsContainer.style.left = (sliderPos - (width / 2 - buttons[0])) * sliderScale + 'px'; 62 - } 63 - } 61 + // settingsContainer.style.left = (sliderPos - (width / 2 - buttons[0])) * sliderScale + 'px'; 62 + // } 63 + // } 64 64 65 - render(); 66 - utils.set(sliderBar, { translateX: sliderPos }); 65 + // render(); 66 + // utils.set(sliderBar, { translateX: sliderPos }); 67 67 68 - sliderBar.addEventListener('touchstart', ( e: TouchEvent ) => { 69 - sliderMouseDown = true; 70 - mouseStartX = e.touches[0].clientX; 71 - }) 68 + // sliderBar.addEventListener('touchstart', ( e: TouchEvent ) => { 69 + // sliderMouseDown = true; 70 + // mouseStartX = e.touches[0].clientX; 71 + // }) 72 72 73 - window.addEventListener('touchmove', ( e: TouchEvent ) => { 74 - if(sliderMouseDown){ 75 - utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) }); 76 - settingsContainer.style.left = (sliderPos - (mouseStartX - e.touches[0].clientX) - (width / 2 - buttons[0])) * sliderScale + 'px'; 77 - } 78 - }) 73 + // window.addEventListener('touchmove', ( e: TouchEvent ) => { 74 + // if(sliderMouseDown){ 75 + // utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) }); 76 + // settingsContainer.style.left = (sliderPos - (mouseStartX - e.touches[0].clientX) - (width / 2 - buttons[0])) * sliderScale + 'px'; 77 + // } 78 + // }) 79 79 80 - window.addEventListener('keyup', closeWithKey); 80 + // window.addEventListener('keyup', closeWithKey); 81 81 82 - window.addEventListener('touchend', ( e: TouchEvent ) => { 83 - if(sliderMouseDown){ 84 - sliderPos = sliderPos - (mouseStartX - e.touches[0].clientX); 82 + // window.addEventListener('touchend', ( e: TouchEvent ) => { 83 + // if(sliderMouseDown){ 84 + // sliderPos = sliderPos - (mouseStartX - e.touches[0].clientX); 85 85 86 - utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) }); 87 - sliderMouseDown = false; 86 + // utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) }); 87 + // sliderMouseDown = false; 88 88 89 - if(Math.abs(mouseStartX - e.touches[0].clientX) > 50){ 90 - let shortestDistance = 0; 91 - let selectedButton = -1; 89 + // if(Math.abs(mouseStartX - e.touches[0].clientX) > 50){ 90 + // let shortestDistance = 0; 91 + // let selectedButton = -1; 92 92 93 - buttons.forEach(( pos, indx ) => { 94 - let dis = Math.abs(sliderPos - (width / 2 - pos)); 93 + // buttons.forEach(( pos, indx ) => { 94 + // let dis = Math.abs(sliderPos - (width / 2 - pos)); 95 95 96 - if(selectedButton === -1){ 97 - shortestDistance = dis; 98 - selectedButton = indx; 99 - } else if(shortestDistance > dis){ 100 - shortestDistance = dis; 101 - selectedButton = indx; 102 - } 103 - }) 96 + // if(selectedButton === -1){ 97 + // shortestDistance = dis; 98 + // selectedButton = indx; 99 + // } else if(shortestDistance > dis){ 100 + // shortestDistance = dis; 101 + // selectedButton = indx; 102 + // } 103 + // }) 104 104 105 - currentButton = selectedButton; 106 - } else if(lastClickedButton != -1){ 107 - currentButton = lastClickedButton; 108 - lastClickedButton = -1 109 - } 110 - } 111 - }) 105 + // currentButton = selectedButton; 106 + // } else if(lastClickedButton != -1){ 107 + // currentButton = lastClickedButton; 108 + // lastClickedButton = -1 109 + // } 110 + // } 111 + // }) 112 112 113 - sliderBar.addEventListener('mousedown', ( e: MouseEvent ) => { 114 - sliderMouseDown = true; 115 - mouseStartX = e.clientX; 116 - }); 113 + // sliderBar.addEventListener('mousedown', ( e: MouseEvent ) => { 114 + // sliderMouseDown = true; 115 + // mouseStartX = e.clientX; 116 + // }); 117 117 118 - window.addEventListener('mousemove', ( e: MouseEvent ) => { 119 - if(sliderMouseDown){ 120 - utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) }); 121 - settingsContainer.style.left = sliderPos - (mouseStartX - e.clientX) + 'px'; 122 - settingsContainer.style.left = (sliderPos - (mouseStartX - e.clientX) - (width / 2 - buttons[0])) * sliderScale + 'px'; 123 - } 124 - }) 118 + // window.addEventListener('mousemove', ( e: MouseEvent ) => { 119 + // if(sliderMouseDown){ 120 + // utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) }); 121 + // settingsContainer.style.left = sliderPos - (mouseStartX - e.clientX) + 'px'; 122 + // settingsContainer.style.left = (sliderPos - (mouseStartX - e.clientX) - (width / 2 - buttons[0])) * sliderScale + 'px'; 123 + // } 124 + // }) 125 125 126 - window.addEventListener('mouseup', ( e: MouseEvent ) => { 127 - if(sliderMouseDown){ 128 - sliderPos = sliderPos - (mouseStartX - e.clientX); 126 + // window.addEventListener('mouseup', ( e: MouseEvent ) => { 127 + // if(sliderMouseDown){ 128 + // sliderPos = sliderPos - (mouseStartX - e.clientX); 129 129 130 - utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) }); 131 - sliderMouseDown = false; 130 + // utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) }); 131 + // sliderMouseDown = false; 132 132 133 - if(Math.abs(mouseStartX - e.clientX) > 50){ 134 - let shortestDistance = 0; 135 - let selectedButton = -1; 133 + // if(Math.abs(mouseStartX - e.clientX) > 50){ 134 + // let shortestDistance = 0; 135 + // let selectedButton = -1; 136 136 137 - buttons.forEach(( pos, indx ) => { 138 - let dis = Math.abs(sliderPos - (width / 2 - pos)); 137 + // buttons.forEach(( pos, indx ) => { 138 + // let dis = Math.abs(sliderPos - (width / 2 - pos)); 139 139 140 - if(selectedButton === -1){ 141 - shortestDistance = dis; 142 - selectedButton = indx; 143 - } else if(shortestDistance > dis){ 144 - shortestDistance = dis; 145 - selectedButton = indx; 146 - } 147 - }) 140 + // if(selectedButton === -1){ 141 + // shortestDistance = dis; 142 + // selectedButton = indx; 143 + // } else if(shortestDistance > dis){ 144 + // shortestDistance = dis; 145 + // selectedButton = indx; 146 + // } 147 + // }) 148 148 149 - currentButton = selectedButton; 150 - } else if(lastClickedButton != -1){ 151 - currentButton = lastClickedButton; 152 - lastClickedButton = -1 153 - } 154 - } 155 - }) 149 + // currentButton = selectedButton; 150 + // } else if(lastClickedButton != -1){ 151 + // currentButton = lastClickedButton; 152 + // lastClickedButton = -1 153 + // } 154 + // } 155 + // }) 156 156 157 - window.addEventListener('resize', () => { 158 - width = window.innerWidth; 159 - sliderPos = width / 2 - buttons[currentButton]; 160 - sliderScale = width / (buttons[1] - buttons[0]); 157 + // window.addEventListener('resize', () => { 158 + // width = window.innerWidth; 159 + // sliderPos = width / 2 - buttons[currentButton]; 160 + // sliderScale = width / (buttons[1] - buttons[0]); 161 161 162 - utils.set(sliderBar, { translateX: sliderPos }); 163 - }) 162 + // utils.set(sliderBar, { translateX: sliderPos }); 163 + // }) 164 164 165 - sliderBar.addEventListener('wheel', ( e: WheelEvent ) => { 166 - if(e.deltaY > 0){ 167 - if(buttons[currentButton + 1]) 168 - currentButton++; 169 - } else{ 170 - if(buttons[currentButton - 1]) 171 - currentButton--; 172 - } 173 - }) 165 + // sliderBar.addEventListener('wheel', ( e: WheelEvent ) => { 166 + // if(e.deltaY > 0){ 167 + // if(buttons[currentButton + 1]) 168 + // currentButton++; 169 + // } else{ 170 + // if(buttons[currentButton - 1]) 171 + // currentButton--; 172 + // } 173 + // }) 174 174 }) 175 175 176 176 onCleanup(() => { ··· 220 220 </label> 221 221 </div> 222 222 223 + <div class="selector"> 224 + <input type="checkbox" id="minimise-on-close-check" ref={async ( el ) => { 225 + el.checked = await invoke('get_config_value_string', { key: 'minimise-on-close' }) === "false" ? false : true; 226 + }} onChange={( el ) => { 227 + if(el.target.checked){ 228 + invoke('set_config_value_string', { key: 'minimise-on-close', value: 'true' }); 229 + } else{ 230 + invoke('set_config_value_string', { key: 'minimise-on-close', value: 'false' }); 231 + } 232 + }} /> 233 + Close to tray 234 + 235 + <label for="minimise-on-close-check"> 236 + <div class="selection-box"> 237 + <div class="icon-small" style={{ margin: '0', display: 'inline-flex' }}> 238 + <img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img> 239 + </div> 240 + </div> 241 + </label> 242 + </div> 243 + 223 244 <Show when={window.OS === 'windows'}> 224 245 <div class="selector"> 225 246 <input type="checkbox" id="start-with-win-check" ref={async ( el ) => { ··· 272 293 </label> 273 294 </div> 274 295 275 - <div class="selector"> 276 - <input type="checkbox" id="minimise-on-close-check" ref={async ( el ) => { 277 - el.checked = await invoke('get_config_value_string', { key: 'minimise-on-close' }) === "false" ? false : true; 278 - }} onChange={( el ) => { 279 - if(el.target.checked){ 280 - invoke('set_config_value_string', { key: 'minimise-on-close', value: 'true' }); 281 - } else{ 282 - invoke('set_config_value_string', { key: 'minimise-on-close', value: 'false' }); 283 - } 284 - }} /> 285 - Close to tray 286 - 287 - <label for="minimise-on-close-check"> 288 - <div class="selection-box"> 289 - <div class="icon-small" style={{ margin: '0', display: 'inline-flex' }}> 290 - <img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img> 291 - </div> 292 - </div> 293 - </label> 294 - </div> 295 - 296 296 <br /> 297 297 <p> 298 298 VRChat Photo Path: ··· 350 350 <br /> 351 351 <p>VRChat Photo Manager supports photos with extra metadata provided by VRCX.</p> 352 352 </div> 353 - <div class="settings-block"> 354 - <p>WIP</p> 355 - </div> 356 353 </div> 357 354 358 - <div class="slide-bar-tri"></div> 355 + {/* <div class="slide-bar-tri"></div> 359 356 <div class="slide-bar"> 360 357 <div class="inner-slide-bar" ref={( el ) => sliderBar = el}> 361 358 <div class="slider-dot"></div> ··· 373 370 <div class="slider-dot"></div> 374 371 <div class="slider-dot"></div> 375 372 </div> 376 - </div> 373 + </div> */} 377 374 </div> 378 375 ) 379 376 }
-3
src/index.tsx
··· 9 9 PhotoViewerManager: PhotoViewerManager; 10 10 WorldCacheManager: WorldCacheManager; 11 11 PhotoListRenderingManager: PhotoListRenderingManager; 12 - SyncManager: SyncManager; 13 12 ViewManager: ViewManager; 14 13 15 14 CloseAllPopups: (() => void)[]; ··· 41 40 import { PhotoViewerManager } from "./Components/Managers/PhotoViewerManager"; 42 41 import { WorldCacheManager } from "./Components/Managers/WorldCacheManager"; 43 42 import { PhotoListRenderingManager } from "./Components/Managers/PhotoListRenderingManager"; 44 - import { SyncManager } from "./Components/Managers/SyncManager"; 45 43 import { ViewManager } from "./Components/Managers/ViewManager"; 46 44 47 45 window.LoadingManager = new LoadingManager(); ··· 50 48 window.PhotoViewerManager = new PhotoViewerManager(); 51 49 window.WorldCacheManager = new WorldCacheManager(); 52 50 window.PhotoListRenderingManager = new PhotoListRenderingManager(); 53 - window.SyncManager = new SyncManager(); 54 51 window.ViewManager = new ViewManager(); 55 52 56 53 (async () => {