use uuid::Uuid; use domain::models::{ DiaryEntry, FeedEntry, MonthActivity, Movie, MovieProfile, MovieStats, UserStats, UserSummary, UserTrends, collections::Paginated, }; pub struct RemoteActorView { pub handle: String, pub display_name: Option, pub url: String, pub avatar_url: Option, } pub struct HtmlPageContext { pub user_email: Option, pub user_id: Option, pub is_admin: bool, pub register_enabled: bool, pub rss_url: String, pub page_title: String, pub canonical_url: String, pub csrf_token: String, pub page_rss_url: Option, } impl HtmlPageContext { pub fn is_current_user(&self, id: Uuid) -> bool { self.user_id == Some(id) } } pub struct LoginPageData<'a> { pub ctx: HtmlPageContext, pub error: Option<&'a str>, } pub struct RegisterPageData<'a> { pub ctx: HtmlPageContext, pub error: Option<&'a str>, } pub struct NewReviewPageData<'a> { pub ctx: HtmlPageContext, pub error: Option<&'a str>, } pub struct ActivityFeedPageData { pub ctx: HtmlPageContext, pub entries: Paginated, pub current_offset: u32, pub has_more: bool, pub limit: u32, pub filter: String, pub sort_by: String, pub search: String, } pub struct UsersPageData { pub ctx: HtmlPageContext, pub users: Vec, pub remote_actors: Vec, } pub struct ProfilePageData { pub ctx: HtmlPageContext, pub profile_user_id: Uuid, pub profile_user_email: String, pub stats: UserStats, pub view: String, pub entries: Option>, pub current_offset: u32, pub has_more: bool, pub limit: u32, pub history: Option>, pub trends: Option, pub is_own_profile: bool, pub error: Option, pub following_count: usize, pub followers_count: usize, pub pending_followers: Vec, pub sort_by: String, pub search: String, } pub struct FollowingPageData { pub ctx: HtmlPageContext, pub user_id: Uuid, pub actors: Vec, pub error: Option, } pub struct FollowersPageData { pub ctx: HtmlPageContext, pub user_id: Uuid, pub actors: Vec, pub error: Option, } pub struct MovieDetailPageData { pub ctx: HtmlPageContext, pub movie: Movie, pub stats: MovieStats, pub reviews: Paginated, pub profile: Option, pub on_watchlist: bool, pub current_offset: u32, pub has_more: bool, pub limit: u32, pub histogram_max: u64, } #[derive(Clone, Debug)] pub struct WatchlistDisplayEntry { /// Always a full URL: /images/{path} for local, https://... for remote pub poster_url: Option, pub movie_title: String, pub release_year: u16, /// /movies/{id} for local; None for remote entries without a local movie record pub movie_url: Option, pub added_at: String, /// /watchlist/{movie_id}/remove for owner; None for remote or non-owner pub remove_url: Option, } pub struct WatchlistPageData { pub ctx: HtmlPageContext, pub owner_id: uuid::Uuid, pub display_entries: Vec, pub current_offset: u32, pub has_more: bool, pub limit: u32, pub is_owner: bool, pub error: Option, } pub struct ImportUploadPageData { pub ctx: HtmlPageContext, pub profiles: Vec, pub error: Option, } pub struct ImportProfileView { pub id: String, pub name: String, } pub struct ImportMappingPageData { pub ctx: HtmlPageContext, pub session_id: String, pub columns: Vec, pub sample_rows: Vec>, pub domain_fields: Vec<(&'static str, &'static str)>, pub error: Option, } pub struct ImportPreviewRow { pub index: usize, pub status: ImportRowStatus, pub cells: Vec, } pub enum ImportRowStatus { Valid, Duplicate, Invalid(String), } pub struct ImportPreviewPageData { pub ctx: HtmlPageContext, pub session_id: String, pub columns: Vec, pub rows: Vec, } pub struct ProfileSettingsPageData { pub ctx: HtmlPageContext, pub bio: Option, pub avatar_url: Option, pub banner_url: Option, pub also_known_as: Option, pub profile_fields: Vec<(String, String)>, pub saved: bool, } pub struct BlockedDomainEntry { pub domain: String, pub reason: Option, pub blocked_at: String, } pub struct BlockedDomainsPageData { pub ctx: HtmlPageContext, pub domains: Vec, } pub struct BlockedActorEntry { pub url: String, pub handle: String, pub display_name: Option, pub avatar_url: Option, } pub struct BlockedActorsPageData { pub ctx: HtmlPageContext, pub actors: Vec, } pub struct WebhookTokenView { pub id: String, pub provider: String, pub label: Option, pub created_at: String, pub last_used_at: Option, } pub struct IntegrationsPageData { pub ctx: HtmlPageContext, pub tokens: Vec, pub webhook_base_url: String, pub new_token: Option, } pub struct WatchQueueDisplayEntry { pub id: String, pub title: String, pub year: Option, pub source: String, pub watched_at: String, pub movie_url: Option, } pub struct WatchQueuePageData { pub ctx: HtmlPageContext, pub entries: Vec, pub error: Option, } pub trait HtmlRenderer: Send + Sync { fn render_diary_page( &self, data: &Paginated, ctx: HtmlPageContext, ) -> Result; fn render_login_page(&self, data: LoginPageData<'_>) -> Result; fn render_register_page(&self, data: RegisterPageData<'_>) -> Result; fn render_new_review_page(&self, data: NewReviewPageData<'_>) -> Result; fn render_activity_feed_page(&self, data: ActivityFeedPageData) -> Result; fn render_users_page(&self, data: UsersPageData) -> Result; fn render_profile_page(&self, data: ProfilePageData) -> Result; fn render_following_page(&self, data: FollowingPageData) -> Result; fn render_followers_page(&self, data: FollowersPageData) -> Result; fn render_movie_detail_page(&self, data: MovieDetailPageData) -> Result; fn render_import_upload_page(&self, data: ImportUploadPageData) -> Result; fn render_import_mapping_page(&self, data: ImportMappingPageData) -> Result; fn render_import_preview_page(&self, data: ImportPreviewPageData) -> Result; fn render_profile_settings_page(&self, data: ProfileSettingsPageData) -> Result; fn render_blocked_domains_page(&self, data: BlockedDomainsPageData) -> Result; fn render_blocked_actors_page(&self, data: BlockedActorsPageData) -> Result; fn render_watchlist_page(&self, data: WatchlistPageData) -> Result; fn render_integrations_page(&self, data: IntegrationsPageData) -> Result; fn render_watch_queue_page(&self, data: WatchQueuePageData) -> Result; } pub trait RssFeedRenderer: Send + Sync { fn render_feed(&self, entries: &[DiaryEntry], title: &str) -> Result; }