From 86bb0a75784bf289d36a54827ab34e58399fa55e Mon Sep 17 00:00:00 2001 From: yggverse Date: Fri, 7 Feb 2025 13:51:14 +0200 Subject: [PATCH] draft file form --- .../window/tab/item/page/input/titan/file.rs | 54 +++++++++++-------- .../tab/item/page/input/titan/file/control.rs | 40 ++++++++++++++ .../page/input/titan/file/control/counter.rs | 28 ++++++++++ .../page/input/titan/file/control/options.rs | 37 +++++++++++++ .../page/input/titan/file/control/upload.rs | 30 +++++++++++ .../window/tab/item/page/input/titan/text.rs | 17 +++--- 6 files changed, 176 insertions(+), 30 deletions(-) create mode 100644 src/app/browser/window/tab/item/page/input/titan/file/control.rs create mode 100644 src/app/browser/window/tab/item/page/input/titan/file/control/counter.rs create mode 100644 src/app/browser/window/tab/item/page/input/titan/file/control/options.rs create mode 100644 src/app/browser/window/tab/item/page/input/titan/file/control/upload.rs diff --git a/src/app/browser/window/tab/item/page/input/titan/file.rs b/src/app/browser/window/tab/item/page/input/titan/file.rs index c2075751..78970e5c 100644 --- a/src/app/browser/window/tab/item/page/input/titan/file.rs +++ b/src/app/browser/window/tab/item/page/input/titan/file.rs @@ -1,31 +1,43 @@ -use gtk::{prelude::BoxExt, Align, Label, Orientation}; +mod control; -const MARGIN: i32 = 8; -const SPACING: i32 = 8; +use super::Header; +use gtk::Box; pub trait File { fn file() -> Self; } -impl File for gtk::Box { +impl File for Box { fn file() -> Self { - // Init widget - let g_box = gtk::Box::builder() - .halign(Align::Center) - .margin_bottom(MARGIN) - .margin_end(MARGIN) - .margin_start(MARGIN) - .orientation(Orientation::Vertical) - .spacing(SPACING) - //.margin_top(MARGIN) - .build(); + use control::Control; + use gtk::Button; + use std::{cell::Cell, rc::Rc}; - g_box.append( - &Label::builder() - .css_classes(["dim-label"]) - .label("Soon..") - .build(), - ); // @TODO - g_box + // Init components + let header = Rc::new(Cell::new(Header { + mime: None, + token: None, + })); + let control = Box::control(&header); + let form = Button::builder().label("Choose a file..").build(); + + // Init main widget + { + use gtk::{prelude::BoxExt, Orientation}; + + const MARGIN: i32 = 8; + + let g_box = Box::builder() + .margin_bottom(MARGIN) + .margin_end(MARGIN) + .margin_start(MARGIN) + .orientation(Orientation::Vertical) + .spacing(MARGIN) + .build(); + + g_box.append(&form); + g_box.append(&control); + g_box + } } } diff --git a/src/app/browser/window/tab/item/page/input/titan/file/control.rs b/src/app/browser/window/tab/item/page/input/titan/file/control.rs new file mode 100644 index 00000000..2e61a1a5 --- /dev/null +++ b/src/app/browser/window/tab/item/page/input/titan/file/control.rs @@ -0,0 +1,40 @@ +mod counter; +mod options; +mod upload; + +use super::Header; +use gtk::Box; +use std::{cell::Cell, rc::Rc}; + +pub trait Control { + fn control(header: &Rc>) -> Self; +} + +impl Control for Box { + fn control(header: &Rc>) -> Self { + use counter::Counter; + use gtk::{Button, Label}; + use options::Options; + use upload::Upload; + + // Init components + let counter = Label::counter(); + let options = Button::options(header); + let upload = Button::upload(); + + // Init main widget + { + use gtk::{prelude::BoxExt, Align, Orientation}; + let g_box = Box::builder() + .halign(Align::End) + .orientation(Orientation::Horizontal) + .spacing(8) + .build(); + + g_box.append(&counter); + g_box.append(&options); + g_box.append(&upload); + g_box + } + } +} diff --git a/src/app/browser/window/tab/item/page/input/titan/file/control/counter.rs b/src/app/browser/window/tab/item/page/input/titan/file/control/counter.rs new file mode 100644 index 00000000..72c08b8f --- /dev/null +++ b/src/app/browser/window/tab/item/page/input/titan/file/control/counter.rs @@ -0,0 +1,28 @@ +use gtk::{prelude::WidgetExt, Label}; +use plurify::Plurify; + +pub trait Counter { + fn counter() -> Self; + fn update(&self, bytes_total: usize); +} + +impl Counter for Label { + // Constructors + + fn counter() -> Self { + Label::builder().css_classes(["dim-label"]).build() // @TODO use `dimmed` in Adw 1.6, + } + + // Actions + + fn update(&self, bytes_total: usize) { + self.set_visible(if bytes_total > 0 { + let format = bytes_total.plurify(&["byte", "bytes", "bytes"]); + self.set_label(format); + self.set_tooltip_text(Some(format)); + true + } else { + false + }) + } +} diff --git a/src/app/browser/window/tab/item/page/input/titan/file/control/options.rs b/src/app/browser/window/tab/item/page/input/titan/file/control/options.rs new file mode 100644 index 00000000..13a92357 --- /dev/null +++ b/src/app/browser/window/tab/item/page/input/titan/file/control/options.rs @@ -0,0 +1,37 @@ +use super::Header; +use gtk::{ + prelude::{ButtonExt, WidgetExt}, + Button, +}; +use std::{cell::Cell, rc::Rc}; + +pub trait Options { + fn options(header: &Rc>) -> Self; +} + +impl Options for Button { + fn options(header: &Rc>) -> Self { + let button = Button::builder() + .icon_name("emblem-system-symbolic") + .sensitive(false) + .tooltip_text("Options") + .build(); + + button.connect_clicked({ + let header = header.clone(); + move |this| { + this.set_sensitive(false); // lock + header.take().dialog(Some(this), { + let this = this.clone(); + let header = header.clone(); + move |options| { + header.replace(options); + this.set_sensitive(true); // unlock + } + }) + } + }); + + button + } +} diff --git a/src/app/browser/window/tab/item/page/input/titan/file/control/upload.rs b/src/app/browser/window/tab/item/page/input/titan/file/control/upload.rs new file mode 100644 index 00000000..c6099c5a --- /dev/null +++ b/src/app/browser/window/tab/item/page/input/titan/file/control/upload.rs @@ -0,0 +1,30 @@ +use gtk::{ + prelude::{ButtonExt, WidgetExt}, + Button, +}; + +pub trait Upload { + fn upload() -> Self; + fn set_uploading(&self); + fn set_resend(&self); +} + +impl Upload for Button { + fn upload() -> Self { + Button::builder() + // @TODO this class not looks well with default GTK Notebook widget + // activate it after upgrade to `ToggleGroup` in Adw v1.7 / Ubuntu 26.04 + // .css_classes(["accent"]) // | `suggested-action` + .label("Upload") + .sensitive(false) + .build() + } + fn set_uploading(&self) { + self.set_sensitive(false); + self.set_label("uploading.."); + } + fn set_resend(&self) { + self.set_sensitive(true); + self.set_label("Resend"); + } +} diff --git a/src/app/browser/window/tab/item/page/input/titan/text.rs b/src/app/browser/window/tab/item/page/input/titan/text.rs index 213e9f43..f387fac4 100644 --- a/src/app/browser/window/tab/item/page/input/titan/text.rs +++ b/src/app/browser/window/tab/item/page/input/titan/text.rs @@ -2,16 +2,7 @@ mod control; mod form; use super::Header; -use control::Control; -use control::Upload; -use form::Form; use gtk::glib::Bytes; -use gtk::{ - prelude::{BoxExt, ButtonExt, TextBufferExt, TextViewExt}, - Orientation, TextView, -}; -use std::cell::Cell; -use std::rc::Rc; pub trait Text { fn text(callback: impl Fn(Header, Bytes, Box) + 'static) -> Self; @@ -19,6 +10,14 @@ pub trait Text { impl Text for gtk::Box { fn text(callback: impl Fn(Header, Bytes, Box) + 'static) -> Self { + use control::{Control, Upload}; + use form::Form; + use gtk::{ + prelude::{BoxExt, ButtonExt, TextBufferExt, TextViewExt}, + Orientation, TextView, + }; + use std::{cell::Cell, rc::Rc}; + // Init components let header = Rc::new(Cell::new(Header { mime: Some("text/plain".into()), // some servers require not empty content type