diff --git a/Cargo.lock b/Cargo.lock index 3d9390b..e4a52eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4858,6 +4858,8 @@ version = "0.1.0" dependencies = [ "authdb", "http 1.1.0", + "mime 0.3.17", + "mime_guess 2.0.5", "serde 1.0.210", "serde_json", "tokio", diff --git a/visions/server/Cargo.toml b/visions/server/Cargo.toml index 6105d04..d0f2f14 100644 --- a/visions/server/Cargo.toml +++ b/visions/server/Cargo.toml @@ -12,3 +12,5 @@ serde_json = { version = "*" } serde = { version = "1" } tokio = { version = "1", features = [ "full" ] } warp = { version = "0.3" } +mime_guess = "2.0.5" +mime = "0.3.17" diff --git a/visions/server/src/core.rs b/visions/server/src/core.rs index 1caa675..62ec39f 100644 --- a/visions/server/src/core.rs +++ b/visions/server/src/core.rs @@ -1,21 +1,58 @@ -use std::sync::{Arc, RwLock}; +use std::{ + io::Read, + path::PathBuf, + sync::{Arc, RwLock}, +}; #[derive(Debug)] pub enum AppError { - JsonError(serde_json::Error) + JsonError(serde_json::Error), } +#[derive(Clone, Debug)] +pub struct AppState { + pub image_base: PathBuf, +} #[derive(Clone, Debug)] -pub struct AppState {} - -#[derive(Clone, Debug)] -pub struct Core(Arc>); +pub struct Core(pub Arc>); impl Core { pub fn new() -> Self { - Self(Arc::new(RwLock::new(AppState {}))) + Self(Arc::new(RwLock::new(AppState { + image_base: PathBuf::from("/home/savanni/Pictures"), + }))) + } + + pub fn get_file(&self, file_name: String) -> Vec { + let mut full_path = self.0.read().unwrap().image_base.clone(); + full_path.push(&file_name); + + println!("path: {:?}", full_path); + + let mut content: Vec = Vec::new(); + let mut file = std::fs::File::open(&full_path).unwrap(); + file.read_to_end(&mut content).unwrap(); + content + } + + pub fn available_images(&self) -> Vec { + std::fs::read_dir(&self.0.read().unwrap().image_base) + .unwrap() + .filter_map(|entry| match entry { + Ok(entry_) => match mime_guess::from_path(entry_.path()).first() { + Some(mime) if mime.type_() == mime::IMAGE => Some( + entry_ + .path() + .file_name() + .and_then(|filename| filename.to_str()) + .and_then(|filename| Some(filename.to_owned())) + .unwrap(), + ), + _ => None, + }, + Err(_) => None, + }) + .collect() } } - - diff --git a/visions/server/src/handlers.rs b/visions/server/src/handlers.rs index fabedb5..b7f8641 100644 --- a/visions/server/src/handlers.rs +++ b/visions/server/src/handlers.rs @@ -4,6 +4,8 @@ use authdb::{AuthDB, AuthToken}; use http::{response::Response, status::StatusCode, Error}; use serde::{Deserialize, Serialize}; +use crate::core::Core; + pub async fn handle_auth( auth_ctx: &AuthDB, auth_token: AuthToken, @@ -37,17 +39,6 @@ pub fn handle_playing_field() -> PlayArea { } } -pub fn handle_file(file_name: String) -> Vec { - let mut full_path = PathBuf::new(); - full_path.push("/home"); - full_path.push("savanni"); - full_path.push("Pictures"); - full_path.push(&file_name); - - println!("path: {:?}", full_path); - - let mut content: Vec = Vec::new(); - let mut file = std::fs::File::open(&full_path).unwrap(); - file.read_to_end(&mut content).unwrap(); - content +pub fn handle_file(core: Core, file_name: String) -> Vec { + core.get_file(file_name) } diff --git a/visions/server/src/main.rs b/visions/server/src/main.rs index 2f309a4..f31abd2 100644 --- a/visions/server/src/main.rs +++ b/visions/server/src/main.rs @@ -93,22 +93,39 @@ async fn handle_rejection(err: warp::Rejection) -> Result { - return { backgroundImage: "su-pearl.png" }; + return { backgroundImage: "trans-ferris.jpg" }; + } + + async availableImages(): Promise { + const url = new URL(this.base); + url.pathname = `/api/v1/image`; + return fetch(url).then((response) => response.json()); } } diff --git a/visions/ui/src/components/PlayingField/PlayingField.tsx b/visions/ui/src/components/PlayingField/PlayingField.tsx index a15f1d5..37cd1c9 100644 --- a/visions/ui/src/components/PlayingField/PlayingField.tsx +++ b/visions/ui/src/components/PlayingField/PlayingField.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react'; import { Client, PlayingField } from '../../client'; +import { ThumbnailComponent } from '../Thumbnail'; import './PlayingField.css'; interface PlayingFieldProps { @@ -12,9 +13,16 @@ export const PlayingFieldComponent = ({ client }: PlayingFieldProps) => { client.playingField().then((field) => setField(field)); }, [client]); + const [images, setImages] = useState([]); + useEffect(() => { + client.availableImages().then((images) => setImages(images)); + }, [client]); + const backgroundUrl = field && client.imageUrl(field.backgroundImage); return (
-
Left Panel
+
+ {images.map((imageName) => )} +
{backgroundUrl && playing field}
Right Panel
) diff --git a/visions/ui/src/components/Thumbnail.css b/visions/ui/src/components/Thumbnail.css new file mode 100644 index 0000000..b0fef9e --- /dev/null +++ b/visions/ui/src/components/Thumbnail.css @@ -0,0 +1,4 @@ +.thumbnail > img { + max-width: 300px; + max-height: 300px; +} diff --git a/visions/ui/src/components/Thumbnail.tsx b/visions/ui/src/components/Thumbnail.tsx new file mode 100644 index 0000000..390995b --- /dev/null +++ b/visions/ui/src/components/Thumbnail.tsx @@ -0,0 +1,11 @@ +import React, { useEffect, useState } from 'react'; +import { Client } from '../client'; +import './Thumbnail.css'; + +interface ThumbnailProps { + client: Client + imageId: string +} + +export const ThumbnailComponent = ({ client, imageId }: ThumbnailProps) => + (
)