+1
-1
build-release.sh
+1
-1
build-release.sh
+2
-1
changelog
+2
-1
changelog
-1
src-tauri/src/frontend_calls/mod.rs
-1
src-tauri/src/frontend_calls/mod.rs
-11
src-tauri/src/frontend_calls/sync_photos.rs
-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
-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
-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
-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
-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
+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
-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 () => {