+15
-3
src-tauri/src/main.rs
+15
-3
src-tauri/src/main.rs
···
43
43
44
44
// Scans all files under the "Pictures/VRChat" path
45
45
// then sends the list of photos to the frontend
46
+
#[derive(Clone, serde::Serialize)]
47
+
struct PhotosLoadedResponse{
48
+
photos: Vec<path::PathBuf>,
49
+
size: usize
50
+
}
51
+
46
52
#[tauri::command]
47
53
fn load_photos(window: tauri::Window) {
48
54
thread::spawn(move || {
49
55
let base_dir = dirs::home_dir().unwrap().join("Pictures\\VRChat");
50
56
51
57
let mut photos: Vec<path::PathBuf> = Vec::new();
58
+
let mut size: usize = 0;
52
59
53
60
for folder in fs::read_dir(base_dir).unwrap() {
54
61
let f = folder.unwrap();
···
69
76
re2.is_match(p.file_name().to_str().unwrap())
70
77
{
71
78
let path = fname.to_path_buf().clone();
72
-
let path = path.strip_prefix(dirs::home_dir().unwrap().join("Pictures\\VRChat")).unwrap().to_path_buf();
79
+
let metadata = fs::metadata(&path).unwrap();
73
80
74
-
photos.push(path);
81
+
if metadata.is_file() {
82
+
size += metadata.len() as usize;
83
+
84
+
let path = path.strip_prefix(dirs::home_dir().unwrap().join("Pictures\\VRChat")).unwrap().to_path_buf();
85
+
photos.push(path);
86
+
}
75
87
}
76
88
}
77
89
}
78
90
}
79
91
}
80
92
81
-
window.emit("photos_loaded", photos).unwrap();
93
+
window.emit("photos_loaded", PhotosLoadedResponse{ photos, size }).unwrap();
82
94
});
83
95
}
84
96
+20
-3
src/Components/App.tsx
+20
-3
src/Components/App.tsx
···
20
20
let [ confirmationBoxText, setConfirmationBoxText ] = createSignal<string>('');
21
21
let confirmationBoxCallback = () => {}
22
22
23
+
let [ photoCount, setPhotoCount ] = createSignal(0);
24
+
let [ photoSize, setPhotoSize ] = createSignal(0);
25
+
23
26
let setConfirmationBox = ( text: string, cb: () => void ) => {
24
27
setConfirmationBoxText(text);
25
28
confirmationBoxCallback = cb;
···
138
141
return (
139
142
<div class="container">
140
143
<NavBar setLoadingType={setLoadingType} loggedIn={loggedIn} />
141
-
<PhotoList setCurrentPhotoView={setCurrentPhotoView} currentPhotoView={currentPhotoView} photoNavChoice={photoNavChoice} setPhotoNavChoice={setPhotoNavChoice} setConfirmationBox={setConfirmationBox} />
142
-
<PhotoViewer setPhotoNavChoice={setPhotoNavChoice} currentPhotoView={currentPhotoView} setCurrentPhotoView={setCurrentPhotoView} setConfirmationBox={setConfirmationBox} />
144
+
<PhotoList
145
+
setCurrentPhotoView={setCurrentPhotoView}
146
+
currentPhotoView={currentPhotoView}
147
+
photoNavChoice={photoNavChoice}
148
+
setPhotoNavChoice={setPhotoNavChoice}
149
+
setConfirmationBox={setConfirmationBox}
150
+
setPhotoCount={setPhotoCount}
151
+
setPhotoSize={setPhotoSize} />
143
152
144
-
<SettingsMenu />
153
+
<PhotoViewer
154
+
setPhotoNavChoice={setPhotoNavChoice}
155
+
currentPhotoView={currentPhotoView}
156
+
setCurrentPhotoView={setCurrentPhotoView}
157
+
setConfirmationBox={setConfirmationBox} />
158
+
159
+
<SettingsMenu
160
+
photoCount={photoCount}
161
+
photoSize={photoSize} />
145
162
146
163
<div class="copy-notif">Image Copied!</div>
147
164
+6
-1
src/Components/PhotoList.tsx
+6
-1
src/Components/PhotoList.tsx
···
11
11
12
12
class PhotoListProps{
13
13
setCurrentPhotoView!: ( view: any ) => any;
14
+
setPhotoCount!: ( value: any ) => any;
15
+
setPhotoSize!: ( value: any ) => any;
14
16
currentPhotoView!: () => any;
15
17
photoNavChoice!: () => string;
16
18
setPhotoNavChoice!: ( view: any ) => any;
···
317
319
invoke('load_photos')
318
320
319
321
listen('photos_loaded', ( event: any ) => {
320
-
let photoPaths = event.payload.reverse();
322
+
let photoPaths = event.payload.photos.reverse();
323
+
324
+
props.setPhotoCount(photoPaths.length);
325
+
props.setPhotoSize(event.payload.size);
321
326
322
327
photoPaths.forEach(( path: string ) => {
323
328
let photo = new Photo(path);
+10
-2
src/Components/SettingsMenu.tsx
+10
-2
src/Components/SettingsMenu.tsx
···
1
1
import { onMount } from "solid-js";
2
+
import { bytesToFormatted } from "../utils";
2
3
import anime from "animejs";
3
4
4
-
let SettingsMenu = () => {
5
+
class SettingsMenuProps{
6
+
photoCount!: () => number;
7
+
photoSize!: () => number;
8
+
}
9
+
10
+
let SettingsMenu = ( props: SettingsMenuProps ) => {
5
11
let sliderBar: HTMLElement;
6
12
let settingsContainer: HTMLElement;
7
13
let currentButton = 0;
···
130
136
<div class="settings">
131
137
<div class="settings-container" ref={( el ) => settingsContainer = el}>
132
138
<div class="settings-block">
133
-
<h1>Program Settings</h1>
139
+
<h1>Storage Settings</h1>
140
+
141
+
<p>{ props.photoCount() } Photos ({ bytesToFormatted(props.photoSize(), 0) })</p>
134
142
</div>
135
143
<div class="settings-block">
136
144
<h1>Account Settings</h1>
+15
src/utils.ts
+15
src/utils.ts
···
1
+
let fileSize = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB' ];
2
+
3
+
let bytesToFormatted = ( bytes: number, stage: number ): string => {
4
+
if(bytes >= 1000){
5
+
bytes = bytes / 1000;
6
+
7
+
if(fileSize[stage + 1])
8
+
return bytesToFormatted(bytes, stage + 1);
9
+
else
10
+
return bytes.toFixed(2) + fileSize[stage];
11
+
} else
12
+
return bytes.toFixed(2) + fileSize[stage];
13
+
}
14
+
15
+
export { bytesToFormatted };