use crate::{ error::Error, extensions::{ProfileExt, SubmissionExt}, images::ThumbnailImage, middleware::UserProfile, nav::NavState, pagination::PageSource, profiles::SubmissionPage, submissions::pagination::{browse_page, Cache}, ActixLoader, State, }; use actix_web::{web, HttpRequest, HttpResponse}; use hyaenidae_accounts::User; use hyaenidae_toolkit::{Button, IndicatorColor, Thumbnail}; use i18n_embed_fl::fl; use uuid::Uuid; pub(crate) async fn index( loader: ActixLoader, req: HttpRequest, page: Option>, user: Option, profile: Option, nav_state: NavState, state: web::Data, ) -> Result { let profile = profile.map(|p| p.0); if user.is_some() && profile.is_none() { return Ok(crate::profiles::to_change_profile_page()); } let viewer = profile.map(|p| p.id()); let view = ViewBrowseState::build( req.path().to_owned(), viewer, page.map(|q| q.into_inner().into()), &state, ) .await?; crate::rendered(HttpResponse::Ok(), |cursor| { crate::templates::browse(cursor, &loader, &view, &nav_state) }) } pub struct ViewBrowseState { cache: Cache, submissions: Vec, previous_id: Option, next_id: Option, logged_in: bool, path: String, reset: bool, } impl ViewBrowseState { async fn build( path: String, viewer: Option, source: Option, state: &State, ) -> Result { let store = state.profiles.clone(); let can_view_sensitive = if let Some(viewer) = viewer { state.settings.for_profile(viewer).await?.sensitive } else { false }; let state = actix_web::web::block(move || { let mut cache = Cache::new(); let page = browse_page(viewer, can_view_sensitive, &store, &mut cache, source); ViewBrowseState { cache, submissions: page.items, next_id: page.next, previous_id: page.prev, reset: page.reset, logged_in: viewer.is_some(), path, } }) .await?; Ok(state) } pub(crate) fn has_submissions(&self) -> bool { !self.submissions.is_empty() } pub(crate) fn is_logged_in(&self) -> bool { self.logged_in } pub(crate) fn has_nav(&self) -> bool { self.next_id.is_some() || self.previous_id.is_some() } pub(crate) fn submissions(&self) -> Vec { self.submissions .iter() .filter_map(move |submission_id| { let submission = self.cache.submission_map.get(&submission_id)?; let author = self.cache.profile_map.get(&submission.profile_id())?; let file_id = submission.files().get(0)?; let file = self.cache.file_map.get(&file_id)?; let key = file.pictrs_key()?; let thumb = Thumbnail::new( ThumbnailImage::new(key, &submission.title_text()), &submission.view_path(), ) .title(&submission.title_text()) .author(&author.name(), &author.view_path()); let sensitive_color = if submission.is_sensitive() { Some(IndicatorColor::Red) } else { None }; if submission.files().len() > 1 { Some(thumb.indicator( &format!("+{}", submission.files().len() - 1), sensitive_color.unwrap_or(IndicatorColor::White), )) } else { if let Some(sensitive_color) = sensitive_color { Some(thumb.indicator("", sensitive_color)) } else { Some(thumb) } } }) .collect() } pub(crate) fn nav(&self, loader: &ActixLoader) -> Vec