Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UI for configuring the demos directory #35

Merged
merged 16 commits into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
120 changes: 119 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ tauri = { version = "^1.3", features = ["api-all"] }
log = "^0.4"
bitbuffer = "0.10.9"
trash = "3.0.0"
steamlocate = "1.1.0"
steamid-ng = "1.0.0"
num-traits = "0.2.15"
num-derive = "0.3.3"
Expand Down
23 changes: 23 additions & 0 deletions src-tauri/src/commands/files.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use serde::Serialize;
use steamlocate::SteamDir;
use tauri::State;

use crate::AppState;

#[derive(Clone, Debug, Serialize)]
pub enum TF2DirError {
/// Could not find Steam installed on the current system
SteamNotFound,
/// Found Steam, but could not find TF2 within the Steam installation directory
Tf2NotFound,
}

#[tauri::command]
pub fn get_tf2_dir(_state: State<'_, AppState>) -> Result<String, TF2DirError> {
const TF2_ID: u32 = 440;

let mut steam_dir = SteamDir::locate().ok_or(TF2DirError::SteamNotFound)?;
let tf2_dir = steam_dir.app(&TF2_ID).ok_or(TF2DirError::Tf2NotFound)?;

Ok(String::from(tf2_dir.path.to_string_lossy()))
}
1 change: 1 addition & 0 deletions src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod demos;
pub mod files;
pub mod rcon;
1 change: 1 addition & 0 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ fn main() {
commands::demos::rename_demo,
commands::demos::set_demo_events,
commands::demos::set_demo_tags,
commands::files::get_tf2_dir,
commands::rcon::init_rcon,
commands::rcon::send_command,
])
Expand Down
11 changes: 10 additions & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@
},
"tauri": {
"allowlist": {
"all": true
"all": true,
"path": {
"all": true
},
"fs": {
"all": true,
"scope": [
"**"
]
}
Comment on lines +16 to +24
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required so the tauri fs API has access to read files

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really? I thought "all": true enables everything.

I intend to reduce the allowed scopes before release, but I believe that with the current settings everything is allowed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tauri was raising permissions errors on file reads without adding this. Maybe "all" only applies to top-level permissions within the scope?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's odd, but I suppose you're right.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it sufficient to specify the scope?

},
"bundle": {
"active": true,
Expand Down
4 changes: 4 additions & 0 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export async function getDemoDetails(demoPath: string) {
});
}

export async function getTf2Dir() {
return invoke<string>("get_tf2_dir");
}

export async function initRcon(password: string) {
return invoke<void>("init_rcon", { password });
}
Expand Down
28 changes: 26 additions & 2 deletions src/views/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import BottomBar from "./BottomBar";
import { NavbarPortal, NavbarButton } from "../../AppShell";
import { getDemosInDirectory } from "../../api";
import { Async, Fill } from "../../components";
import useStore from "../../hooks/useStore";
import { getDefaultDemosDir } from "../settings/storage";

const PADDING_SIZE = 16;

Expand Down Expand Up @@ -192,10 +194,28 @@ function MainView({ demos }: { demos: Demo[] }) {
}

export default function HomeViewAsyncWrapper() {
const [storedDemoPath, setStoredDemoPath] = useStore("demoPath");

if (storedDemoPath === undefined) {
// Used as fallback in case the user hasn't configured the demos directory yet
getDefaultDemosDir()
.then(dir => {
if (storedDemoPath === undefined) {
Narcha marked this conversation as resolved.
Show resolved Hide resolved
setStoredDemoPath(dir);
}
return dir;
})
.catch(_err => {
// Failed to get the default directory. At this point, there's nothing reasonable
// we can do other than alert the user and prompt them to set the directory themselves
return;
});
}

return (
<Async
promiseFn={getDemosInDirectory}
args={["/home/rasmus/steamapps-common/Team Fortress 2/tf/demos"]}
args={[storedDemoPath ?? ""]}
loading={
<Fill>
<Loader size="lg" variant="dots" />
Expand All @@ -204,7 +224,11 @@ export default function HomeViewAsyncWrapper() {
error={(error) => (
<Fill>
<Alert color="red">
An error occured while loading this demo directory: {String(error)}
An error occurred while scanning for demo files. Is the demo storage
directory set?
<div>
Error: {String(error)}
</div>
</Alert>
</Fill>
)}
Expand Down
60 changes: 55 additions & 5 deletions src/views/settings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,62 @@
import { Link } from "react-router-dom";
import useStore from "../../hooks/useStore";
import { Button, createStyles, ScrollArea, TextInput } from "@mantine/core";
import { open as dialogOpen } from "@tauri-apps/api/dialog";

const useStyles = createStyles({
root: {
margin: "12px",
display: "flex",
flexDirection: "column",
gap: "8px",
height: "100%"
},
row: {
display: "flex",
flexDirection: "row",
gap: "8px",
},
rowLabel: {
width: 160,
fontSize: "16pt",
},
});

export default function SettingsView() {
const [demoPath, setDemoPath] = useStore("demoPath");

const { classes } = useStyles();

return (
<div>
<div className={classes.root}>
<h1>Settings</h1>
<div>
<Link to="/">Back</Link>
</div>

<ScrollArea>
<span className={classes.row}>
<span className={classes.rowLabel}>
<label>Demos Folder</label>
</span>
<Button
onClick={() => {
dialogOpen({
directory: true,
defaultPath: demoPath,
title: "Select Demo Storage Folder",
})
.then((value) => {
if (value !== null && value !== "") {
// Don't set the path if the user cancelled the dialog
setDemoPath(value as string);
}
return;
})
.catch((error) => console.error(error));
}}
>
Select a folder...
</Button>
<TextInput value={demoPath ?? ""} disabled={true}></TextInput>
</span>
</ScrollArea>
</div>
);
}
15 changes: 15 additions & 0 deletions src/views/settings/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { homeDir, join } from "@tauri-apps/api/path";
import { getTf2Dir } from "../../api";

/**
* Gets the default platform-specific demo file storage directory, assuming Steam and TF2 are installed on the local
* machine. Falls back to the user's home directory if neither is found.
*/
export async function getDefaultDemosDir(): Promise<string> {
const userHomeDir = await homeDir();

// Try getting the TF2 game directory, falling back to the user home directory if it couldn't be found
return await getTf2Dir()
.then((tf2Dir) => join(tf2Dir, "tf", "demos"))
.catch((_error) => userHomeDir);
}