Skip to content

Commit c18cef2

Browse files
committed
feat: screenshots backend stuff
1 parent 62de07e commit c18cef2

File tree

12 files changed

+140
-2
lines changed

12 files changed

+140
-2
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {invoke} from "@tauri-apps/api/core";
2+
3+
type Screenshot = {
4+
filename: string;
5+
creation_date: string;
6+
}
7+
8+
export async function getAllProfileScreenshots(path: string): Promise<Screenshot[]> {
9+
return await invoke('plugin:screenshots|get_all_profile_screenshots', { path })
10+
}

apps/app-frontend/src/pages/instance/Index.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ const tabs = computed(() => [
272272
label: 'Worlds',
273273
href: `${basePath.value}/worlds`,
274274
},
275+
{
276+
label: 'Screenshots',
277+
href: `${basePath.value}/screenshots`
278+
},
275279
{
276280
label: 'Logs',
277281
href: `${basePath.value}/logs`,
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<script setup lang="ts">
2+
import type {GameInstance} from "@/helpers/types";
3+
import type ContextMenu from "@/components/ui/ContextMenu.vue";
4+
import type {Version} from "@modrinth/utils";
5+
import {getAllProfileScreenshots} from "@/helpers/screenshots.ts";
6+
7+
const props = defineProps<{
8+
instance: GameInstance
9+
options: InstanceType<typeof ContextMenu> | null
10+
offline: boolean
11+
playing: boolean
12+
versions: Version[]
13+
installed: boolean
14+
}>()
15+
16+
const screenshots = await getAllProfileScreenshots(props.instance.path);
17+
</script>
18+
19+
<template>
20+
<div class="card">
21+
{{ screenshots }}
22+
</div>
23+
</template>

apps/app-frontend/src/pages/instance/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ import Overview from './Overview.vue'
33
import Worlds from './Worlds.vue'
44
import Mods from './Mods.vue'
55
import Logs from './Logs.vue'
6+
import Screenshots from "./Screenshots.vue"
67

7-
export { Index, Overview, Worlds, Mods, Logs }
8+
export { Index, Overview, Worlds, Mods, Logs, Screenshots }

apps/app-frontend/src/routes.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@ export default new createRouter({
132132
breadcrumb: [{ name: '?Instance', link: '/instance/{id}/' }, { name: 'Worlds' }],
133133
},
134134
},
135+
{
136+
path: 'screenshots',
137+
name: 'Screenshots',
138+
component: Instance.Screenshots,
139+
meta: {
140+
useRootContext: true,
141+
breadcrumb: [{ name: '?Instance', link: '/instance/{id}/' }, { name: 'Screenshots' }],
142+
},
143+
},
135144
{
136145
path: '',
137146
name: 'Mods',

apps/app/build.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,14 @@ fn main() {
264264
.default_permission(
265265
DefaultPermissionRule::AllowAllCommands,
266266
),
267+
)
268+
.plugin(
269+
"screenshots",
270+
InlinedPlugin::new()
271+
.commands(&["get_all_profile_screenshots"])
272+
.default_permission(
273+
DefaultPermissionRule::AllowAllCommands,
274+
),
267275
),
268276
)
269277
.expect("Failed to run tauri-build");

apps/app/capabilities/plugins.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"utils:default",
3737
"ads:default",
3838
"friends:default",
39-
"worlds:default"
39+
"worlds:default",
40+
"screenshots:default"
4041
]
4142
}

apps/app/src/api/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub mod ads;
2020
pub mod cache;
2121
pub mod friends;
2222
pub mod worlds;
23+
pub mod screenshots;
2324

2425
pub type Result<T> = std::result::Result<T, TheseusSerializableError>;
2526

apps/app/src/api/screenshots.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use tauri::{AppHandle, Runtime};
2+
use theseus::{screenshots};
3+
4+
pub fn init<R: Runtime>() -> tauri::plugin::TauriPlugin<R> {
5+
tauri::plugin::Builder::new("screenshots")
6+
.invoke_handler(tauri::generate_handler![
7+
get_all_profile_screenshots
8+
])
9+
.build()
10+
}
11+
12+
#[tauri::command]
13+
pub async fn get_all_profile_screenshots<R: Runtime>(
14+
app_handle: AppHandle<R>,
15+
path: &str,
16+
) -> crate::api::Result<Vec<screenshots::Screenshot>> {
17+
Ok(screenshots::get_all_profile_screenshots(path).await?)
18+
}

apps/app/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ fn main() {
260260
.plugin(api::ads::init())
261261
.plugin(api::friends::init())
262262
.plugin(api::worlds::init())
263+
.plugin(api::screenshots::init())
263264
.invoke_handler(tauri::generate_handler![
264265
initialize_state,
265266
is_dev,

packages/app-lib/src/api/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod profile;
1313
pub mod settings;
1414
pub mod tags;
1515
pub mod worlds;
16+
pub mod screenshots;
1617

1718
pub mod data {
1819
pub use crate::state::{
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::ffi::OsStr;
2+
use std::path::Path;
3+
use chrono::{DateTime, Utc};
4+
use serde::{Deserialize, Serialize};
5+
use tokio::fs::canonicalize;
6+
use crate::profile::get_full_path;
7+
use crate::util::io::{metadata, read_dir};
8+
9+
#[derive(Deserialize, Serialize, Debug, Clone)]
10+
pub struct Screenshot {
11+
pub path: String,
12+
pub creation_date: DateTime<Utc>
13+
}
14+
15+
pub async fn get_all_profile_screenshots(
16+
profile_path: &str,
17+
) -> crate::Result<Vec<Screenshot>> {
18+
get_all_screenshots_in_profile(&get_full_path(profile_path).await?)
19+
.await
20+
}
21+
22+
async fn get_all_screenshots_in_profile(
23+
profile_dir: &Path,
24+
) -> crate::Result<Vec<Screenshot>> {
25+
let screenshots_dir = profile_dir.join("screenshots");
26+
if metadata(&screenshots_dir).await.is_err() {
27+
return Ok(Vec::new());
28+
}
29+
30+
let mut dir = read_dir(&screenshots_dir).await?;
31+
let mut screenshots = Vec::new();
32+
33+
while let Some(entry) = dir.next_entry().await? {
34+
if !entry.file_type().await?.is_file() {
35+
continue;
36+
}
37+
38+
let path = entry.path();
39+
if path
40+
.extension()
41+
.and_then(OsStr::to_str)
42+
.map(|ext| ext.eq_ignore_ascii_case("png"))
43+
!= Some(true)
44+
{
45+
continue;
46+
}
47+
48+
let abs_path: std::path::PathBuf = canonicalize(&path).await?;
49+
let full_path = abs_path.to_string_lossy().into_owned();
50+
51+
let meta = entry.metadata().await?;
52+
let created_time = meta.created().unwrap_or(meta.modified()?);
53+
let creation_date = DateTime::<Utc>::from(created_time);
54+
55+
screenshots.push(Screenshot { path: full_path, creation_date });
56+
}
57+
58+
screenshots.sort_by_key(|s| s.creation_date);
59+
60+
Ok(screenshots)
61+
}

0 commit comments

Comments
 (0)