use crate::error_template::{AppError, ErrorTemplate}; use cfg_if::*; use leptos::*; use leptos_meta::*; use leptos_router::*; cfg_if! { if #[cfg(feature="ssr")]{ use surrealdb::sql::Thing; use surrealdb::Surreal; use surrealdb::engine::remote::ws::Ws; use surrealdb::opt::auth::Root; } } #[component] pub fn App() -> impl IntoView { // Provides context that manages stylesheets, titles, meta tags, etc. provide_meta_context(); view! { // sets the document title // content for this welcome page <Router fallback=|| { let mut outside_errors = Errors::default(); outside_errors.insert_with_default_key(AppError::NotFound); view! { <ErrorTemplate outside_errors/> }.into_view() }> <main> <Routes> <Route path="/" view=Home/> </Routes> </main> </Router> } } #[component] fn Home() -> impl IntoView { use leptos::html::Div; use leptos_use::*; let (size, set_size) = create_signal(1.); let (page, set_page) = create_signal(0); //let res = create_local_resource(page, get_pics2); let (all, set_all) = create_signal(Vec::<PicStruct>::new()); let res = create_local_resource( move || (page.get(), size.get()), move |d| get_pics2(d.0, d.1), ); let el = create_node_ref::<Div>(); let _ = use_infinite_scroll_with_options( el, move |_| async move { if !res.loading().get() && res().is_some() { set_page.update(|page| *page += 1); } res.and_then(move |_| { set_all.update(|dat| dat.extend(res().unwrap().unwrap())); }); /*if !res.loading().get() { set_page.update(|page| *page += 1); } else if res().is_some() { set_all.update(|dat| dat.extend(res().unwrap().unwrap())); // println!("{:?}", all().len()) }*/ }, UseInfiniteScrollOptions::default().distance(10.0), ); view! { <h1>"Home"</h1> <div> <input on:input=move |ev| { set_size(event_target_value(&ev).parse::<f64>().unwrap()); } prop:value=size type="range" min="0.5" max="2" step="0.5" value="1" /> </div> <div class="main overflow-y-auto max-h-300" node_ref=el> <For each=move || all.get() key=|state| state.key.clone() let:child> <Pic width=child.width height=child.height scale=size url=child.url/> </For> </div> <div class="w-full"> <p class="text-center">{move || page()}</p> </div> } } use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct PicStruct { key: String, width: i32, height: i32, url: String, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] struct Wallpaper { file_name: String, info: String, date_added: String, height: u64, width: u64, path: String, thumbs: Vec<String>, } #[derive(Debug, Serialize)] struct Name<'a> { first: &'a str, last: &'a str, } #[derive(Debug, Serialize)] struct Person<'a> { title: &'a str, name: Name<'a>, marketing: bool, } #[derive(Debug, Serialize)] struct Responsibility { marketing: bool, } #[derive(Debug, Deserialize)] struct Record { #[allow(dead_code)] id: i32, } use std::env; #[server(GetPics, "/api")] pub async fn get_pics2(page: i32, size: f64) -> Result<Vec<PicStruct>, ServerFnError> { use image::GenericImageView; use imageinfo::ImageInfo; use std::fs; use std::path::PathBuf; let query = " SELECT * FROM wallpapers LIMIT 10; "; let db = Surreal::new::<Ws>("127.0.0.1:8000") .await .expect("Couldnt connect to db server"); // Select a specific namespace / database db.use_ns("test") .use_db("test") .await .expect("Couldnt find db"); //let papers: Vec<Wallpaper> = db.select("wallpapers").await.expect("Err"); //println!("{papers:#?}"); let mut res = db.query(query).await?; let pap: Vec<Wallpaper> = res.take(0)?; println!("{pap:#?}"); let mut pics = Vec::new(); let folder_path = "./public"; // Define the number of pictures per page let pics_per_page = 10; // Calculate the index to start from based on the page number let start_index = (page) * pics_per_page; let end_index = start_index + pics_per_page; // manage a vector with all the image paths let mut image_file_paths = Vec::<PathBuf>::new(); for entry in fs::read_dir(folder_path)? { let entry = entry?; let file_path = entry.path(); let file_name_str = file_path.file_name().unwrap_or_default().to_str().unwrap(); if size == 0.5 { //skip 1024 and 512 if file_name_str.contains("512x512") || file_name_str.contains("1024x1024") { continue; } } else if size == 1.0 { if file_name_str.contains("256x256") || file_name_str.contains("1024x1024") { println!("sdfasdf"); continue; } } else if size == 1.5 { if file_name_str.contains("256x256") || file_name_str.contains("512x512") { continue; } } image_file_paths.push(file_path.clone()); } for (i, file_path) in image_file_paths.iter().enumerate() { if file_path.is_file() { if i < start_index as usize { continue; } let file = std::fs::File::open(file_path)?; let mut bufreader = std::io::BufReader::new(&file); let exifreader = exif::Reader::new(); let exif = exifreader.read_from_container(&mut bufreader)?; for f in exif.fields() { println!( "{} {} {}", f.tag, f.ifd_num, f.display_value().with_unit(&exif) ); } let file_name = file_path.file_name().unwrap_or_default(); let file_name_str = file_name.to_str().unwrap(); // Check if the file has a supported image extension if let Some(extension) = file_path.extension() { if let Some(extension_str) = extension.to_str() { if image::ImageFormat::from_extension(extension_str).is_some() { // Process the image let img = image::open(&file_path).expect("Failed to open image"); let (x, y) = img.dimensions(); pics.push(PicStruct { key: file_name_str.to_string(), // Could not be unique if two images were created at exactly // the same time width: x as i32, height: y as i32, url: file_name.to_string_lossy().into(), }); if i + 1 >= end_index as usize { break; } } } } } } // Send different picture resolutions depending on selected size // sizes 256 512 1024 // Iterate over the entries in the folder /*for (index, entry) in fs::read_dir(folder_path) .expect("Failed to read directory") .enumerate() { if let Ok(entry) = entry { if index < start_index as usize { // Skip pictures before the start index continue; } let file_path = entry.path(); let file_name = file_path.file_name().unwrap_or_default(); let file_name_str = file_name.to_str().unwrap(); // Skip the wrong sizes if size == 0.5 { //skip 1024 and 512 if file_name_str.contains("512x512") || file_name_str.contains("1024x1024") { continue; } } else if size == 1.0 { if file_name_str.contains("256x256") || file_name_str.contains("1024x1024") { continue; } } else if size == 1.5 { if file_name_str.contains("256x256") || file_name_str.contains("512x512") { continue; } } // Check if the entry is a file if file_path.is_file() { // Check if the file has a supported image extension if let Some(extension) = file_path.extension() { if let Some(extension_str) = extension.to_str() { if image::ImageFormat::from_extension(extension_str).is_some() { // Process the image let img = image::open(&file_path).expect("Failed to open image"); let (x, y) = img.dimensions(); pics.push(PicStruct { key: file_name_str.to_string(), // Could not be unique if two images were created at exactly // the same time width: x as i32, height: y as i32, url: file_name.to_string_lossy().into(), }); // Break if we have reached the end index if index + 1 >= end_index as usize { break; } } } } } } }*/ println!("{:#?}", pics); Ok(pics) } #[component] fn Info(show: ReadSignal<bool>, set_show: WriteSignal<bool>) -> impl IntoView { view! { <Show when=move || show()> <div id="info-main" class="rounded"> <button type="button" on:click=move |_| set_show(false)> "Close" </button> <input type="text" id="country" name="country" value="Norway" readonly/> <br/> <br/> </div> </Show> } } #[component] fn Pic(width: i32, height: i32, url: String, scale: ReadSignal<f64>) -> impl IntoView { let (showInfo, set_showInfo) = create_signal(false); view! { <div class="pic-outer" // style="border:1px solid black;" style:width=move || format!("{}px", f64::from(width + 10)) style:height=move || format!("{}px", f64::from(height + 10)) > <div class="pic-inner" style=format!("background-image: url('{}'); background-size: cover;", url) style:width=move || format!("{}px", f64::from(width)) style:height=move || format!("{}px", f64::from(height)) > <div class="dropdown"> <button class="dropbtn"> <i class="fa-solid fa-download"></i> </button> <div class="dropdown-content"> <a href="https://google.com">16:9</a> <a href="#">16:10</a> <a href="#">4:3</a> </div> </div> <button id="info-button" on:click=move |_| set_showInfo(true)> <i class="fa-regular fa-circle-question"></i> </button> </div> </div> <Info show=showInfo set_show=set_showInfo/> } }