diff --git a/frontend/src/components/torrent/details.rs b/frontend/src/components/torrent/details.rs index 2d4a1b2..238de52 100644 --- a/frontend/src/components/torrent/details.rs +++ b/frontend/src/components/torrent/details.rs @@ -106,24 +106,19 @@ pub fn TorrentDetailsSheet() -> impl IntoView { - leptos::either::Either::Left(view! { +
+ +
+ }), + None => leptos::either::Either::Right(view! {

"Dosya yükleniyor..."

- } - > - {move || { - let t = selected_torrent.get().unwrap(); - view! { -
- -
- } - }} -
+ }), + }}
diff --git a/frontend/src/components/torrent/files.rs b/frontend/src/components/torrent/files.rs new file mode 100644 index 0000000..7110f64 --- /dev/null +++ b/frontend/src/components/torrent/files.rs @@ -0,0 +1,195 @@ +use leptos::prelude::*; +use crate::components::ui::table::*; +use crate::components::ui::badge::*; +use crate::components::ui::shimmer::*; +use crate::components::ui::context_menu::*; +use shared::TorrentFile; + +#[component] +pub fn TorrentFilesTab(hash: String) -> impl IntoView { + let hash_clone = hash.clone(); + + // Fetch files resource + let files_resource = Resource::new( + move || hash_clone.clone(), + |h| async move { shared::server_fns::torrent::get_files(h).await.unwrap_or_default() } + ); + + // Refresh action + let refresh_files = Action::new(|h: &String| { + let h = h.clone(); + async move { shared::server_fns::torrent::get_files(h).await.unwrap_or_default() } + }); + + let stored_hash = StoredValue::new(hash); + + view! { + }> + {move || { + let files = match refresh_files.value().get() { + Some(f) => f, + None => files_resource.get().unwrap_or_default(), + }; + + if files.is_empty() { + return view! { +
+ +

"Bu torrent için dosya bulunamadı."

+
+ }.into_any(); + } + + let files_len = files.len(); + + view! { +
+ + + + + "#" + "Dosya Adı" + "Boyut" + "Tamamlanan" + "Öncelik" + + + + + } + }} + /> + +
+
+ +
+ {format!("Toplam {} dosya", files_len)} +
+
+ }.into_any() + }} +
+ } +} + +#[component] +fn FileRow(file: TorrentFile, hash: String, refresh_action: Action>) -> impl IntoView { + let f_idx = file.index; + let context_id = format!("file-context-{}-{}", hash, f_idx); + let path_clone = file.path.clone(); + + let set_priority = Action::new(|req: &(String, u32, u8)| { + let (h, idx, p) = req.clone(); + async move { + let res = shared::server_fns::torrent::set_file_priority(h, idx, p).await; + if let Err(e) = &res { + crate::store::show_toast(shared::NotificationLevel::Error, format!("Öncelik değiştirilemedi: {:?}", e)); + } else { + crate::store::show_toast(shared::NotificationLevel::Success, "Dosya önceliği güncellendi.".to_string()); + } + res + } + }); + + view! { + + + + {file.index} + + {file.path.clone()} + + + {format_bytes(file.size)} + + + {format_bytes(file.completed_chunks)} + + + { + let (variant, label) = match file.priority { + 0 => (BadgeVariant::Destructive, "İndirme"), + 2 => (BadgeVariant::Success, "Yüksek"), + _ => (BadgeVariant::Secondary, "Normal"), + }; + view! { {label} } + } + + + + + + "Dosya Önceliği" + + + + "Yüksek" + + + + + "Normal" + + + + + "İndirme (Kapalı)" + + + + + } +} + +#[component] +fn FilesFallback() -> impl IntoView { + view! { + +
+
+
+
+
+ } +} + +fn format_bytes(bytes: i64) -> String { + const UNITS: [&str; 6] = ["B", "KB", "MB", "GB", "TB", "PB"]; + if bytes < 1024 { return format!("{} B", bytes); } + let i = (bytes as f64).log2().div_euclid(10.0) as usize; + format!("{:.1} {}", (bytes as f64) / 1024_f64.powi(i as i32), UNITS[i]) +}