mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-09-03 18:32:33 +00:00
begin titan file uploads implementation
This commit is contained in:
parent
00877ee36f
commit
f5e850ead3
@ -4,7 +4,11 @@ mod titan;
|
|||||||
|
|
||||||
use super::ItemAction;
|
use super::ItemAction;
|
||||||
use adw::Clamp;
|
use adw::Clamp;
|
||||||
use gtk::{glib::Uri, prelude::WidgetExt};
|
use gtk::{
|
||||||
|
glib::Uri,
|
||||||
|
prelude::{IsA, WidgetExt},
|
||||||
|
Widget,
|
||||||
|
};
|
||||||
use response::Response;
|
use response::Response;
|
||||||
use sensitive::Sensitive;
|
use sensitive::Sensitive;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -37,10 +41,10 @@ impl Input {
|
|||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
pub fn unset(&self) {
|
pub fn unset(&self) {
|
||||||
self.update(None);
|
self.update(Widget::NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self, child: Option<>k::Box>) {
|
pub fn update(&self, child: Option<&impl IsA<Widget>>) {
|
||||||
if child.is_some() {
|
if child.is_some() {
|
||||||
self.clamp.set_visible(true); // widget may be hidden, make it visible to child redraw
|
self.clamp.set_visible(true); // widget may be hidden, make it visible to child redraw
|
||||||
self.clamp.set_child(child);
|
self.clamp.set_child(child);
|
||||||
@ -71,6 +75,6 @@ impl Input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_new_titan(&self, on_send: impl Fn(&[u8], Box<dyn Fn()>) + 'static) {
|
pub fn set_new_titan(&self, on_send: impl Fn(&[u8], Box<dyn Fn()>) + 'static) {
|
||||||
self.update(Some(>k::Box::titan(on_send)));
|
self.update(Some(>k::Notebook::titan(on_send)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,67 +1,55 @@
|
|||||||
mod control;
|
mod file;
|
||||||
mod form;
|
mod text;
|
||||||
mod title;
|
mod title;
|
||||||
|
|
||||||
use control::Control;
|
use file::File;
|
||||||
use control::Send;
|
use gtk::{glib::uuid_string_random, prelude::WidgetExt, Label, Notebook};
|
||||||
use form::Form;
|
use text::Text;
|
||||||
use gtk::{
|
|
||||||
prelude::{BoxExt, ButtonExt, TextBufferExt, TextViewExt},
|
|
||||||
Label, Orientation, TextView,
|
|
||||||
};
|
|
||||||
use std::rc::Rc;
|
|
||||||
use title::Title;
|
use title::Title;
|
||||||
|
|
||||||
const MARGIN: i32 = 6;
|
|
||||||
const SPACING: i32 = 8;
|
|
||||||
|
|
||||||
pub trait Titan {
|
pub trait Titan {
|
||||||
fn titan(callback: impl Fn(&[u8], Box<dyn Fn()>) + 'static) -> Self;
|
fn titan(callback: impl Fn(&[u8], Box<dyn Fn()>) + 'static) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Titan for gtk::Box {
|
impl Titan for Notebook {
|
||||||
fn titan(callback: impl Fn(&[u8], Box<dyn Fn()>) + 'static) -> Self {
|
fn titan(callback: impl Fn(&[u8], Box<dyn Fn()>) + 'static) -> Self {
|
||||||
// Init components
|
let notebook = Notebook::builder()
|
||||||
let control = Rc::new(Control::build());
|
.name(format!("s{}", uuid_string_random()))
|
||||||
let form = TextView::form();
|
.show_border(false)
|
||||||
let title = Label::title(None);
|
|
||||||
|
|
||||||
// Init widget
|
|
||||||
let g_box = gtk::Box::builder()
|
|
||||||
.margin_bottom(MARGIN)
|
|
||||||
.margin_end(MARGIN)
|
|
||||||
.margin_start(MARGIN)
|
|
||||||
.margin_top(MARGIN)
|
|
||||||
.spacing(SPACING)
|
|
||||||
.orientation(Orientation::Vertical)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
g_box.append(&title);
|
notebook.append_page(>k::Box::text(callback), Some(&Label::title("Text")));
|
||||||
g_box.append(&form);
|
notebook.append_page(>k::Box::file(), Some(&Label::title("File")));
|
||||||
g_box.append(&control.g_box);
|
|
||||||
|
|
||||||
// Connect events
|
notebook_css_patch(¬ebook);
|
||||||
control.send.connect_clicked({
|
notebook
|
||||||
let form = form.clone();
|
|
||||||
move |this| {
|
|
||||||
this.set_sending();
|
|
||||||
callback(
|
|
||||||
form.text().as_bytes(),
|
|
||||||
Box::new({
|
|
||||||
let this = this.clone();
|
|
||||||
move || this.set_resend() // on failure
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
form.buffer().connect_changed({
|
|
||||||
let control = control.clone();
|
|
||||||
let form = form.clone();
|
|
||||||
move |this| control.update(this.char_count(), form.text().len())
|
|
||||||
});
|
|
||||||
|
|
||||||
// Return activated `Self`
|
|
||||||
g_box
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tools
|
||||||
|
|
||||||
|
fn notebook_css_patch(notebook: &Notebook) {
|
||||||
|
let name = notebook.widget_name();
|
||||||
|
let provider = gtk::CssProvider::new();
|
||||||
|
|
||||||
|
provider.load_from_string(&format!(
|
||||||
|
"
|
||||||
|
#{name} stack {{
|
||||||
|
background-color:rgba(0,0,0,0);
|
||||||
|
}}
|
||||||
|
#{name} header {{
|
||||||
|
border-bottom-color:rgba(0,0,0,0);
|
||||||
|
}}
|
||||||
|
#{name} tab {{
|
||||||
|
opacity:0.9;
|
||||||
|
}}
|
||||||
|
"
|
||||||
|
));
|
||||||
|
|
||||||
|
gtk::style_context_add_provider_for_display(
|
||||||
|
¬ebook.display(),
|
||||||
|
&provider,
|
||||||
|
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||||
|
);
|
||||||
|
} // @TODO replace `Notebook` with `ToggleGroup` in Adw 1.7 / Ubuntu 26.04
|
||||||
|
// https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ToggleGroup.html
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
use gtk::{
|
|
||||||
prelude::{ButtonExt, WidgetExt},
|
|
||||||
Button,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait Send {
|
|
||||||
fn send() -> Self;
|
|
||||||
fn set_sending(&self);
|
|
||||||
fn set_resend(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Send for Button {
|
|
||||||
fn send() -> Self {
|
|
||||||
Button::builder()
|
|
||||||
.css_classes(["accent"]) // | `suggested-action`
|
|
||||||
.label("Send")
|
|
||||||
.sensitive(false)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
fn set_sending(&self) {
|
|
||||||
self.set_sensitive(false);
|
|
||||||
self.set_label("sending..");
|
|
||||||
}
|
|
||||||
fn set_resend(&self) {
|
|
||||||
self.set_sensitive(true);
|
|
||||||
self.set_label("Resend");
|
|
||||||
}
|
|
||||||
}
|
|
31
src/app/browser/window/tab/item/page/input/titan/file.rs
Normal file
31
src/app/browser/window/tab/item/page/input/titan/file.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use gtk::{prelude::BoxExt, Align, Label, Orientation};
|
||||||
|
|
||||||
|
const MARGIN: i32 = 8;
|
||||||
|
const SPACING: i32 = 8;
|
||||||
|
|
||||||
|
pub trait File {
|
||||||
|
fn file() -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl File for gtk::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();
|
||||||
|
|
||||||
|
g_box.append(
|
||||||
|
&Label::builder()
|
||||||
|
.css_classes(["dim-label"])
|
||||||
|
.label("Soon..")
|
||||||
|
.build(),
|
||||||
|
); // @TODO
|
||||||
|
g_box
|
||||||
|
}
|
||||||
|
}
|
62
src/app/browser/window/tab/item/page/input/titan/text.rs
Normal file
62
src/app/browser/window/tab/item/page/input/titan/text.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
mod control;
|
||||||
|
mod form;
|
||||||
|
|
||||||
|
use control::Control;
|
||||||
|
use control::Upload;
|
||||||
|
use form::Form;
|
||||||
|
use gtk::{
|
||||||
|
prelude::{BoxExt, ButtonExt, TextBufferExt, TextViewExt},
|
||||||
|
Orientation, TextView,
|
||||||
|
};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
const MARGIN: i32 = 8;
|
||||||
|
const SPACING: i32 = 8;
|
||||||
|
|
||||||
|
pub trait Text {
|
||||||
|
fn text(callback: impl Fn(&[u8], Box<dyn Fn()>) + 'static) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Text for gtk::Box {
|
||||||
|
fn text(callback: impl Fn(&[u8], Box<dyn Fn()>) + 'static) -> Self {
|
||||||
|
// Init components
|
||||||
|
let control = Rc::new(Control::build());
|
||||||
|
let form = TextView::form();
|
||||||
|
|
||||||
|
// Init widget
|
||||||
|
let g_box = gtk::Box::builder()
|
||||||
|
.margin_bottom(MARGIN)
|
||||||
|
.margin_end(MARGIN)
|
||||||
|
.margin_start(MARGIN)
|
||||||
|
.orientation(Orientation::Vertical)
|
||||||
|
.spacing(SPACING)
|
||||||
|
//.margin_top(MARGIN)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
g_box.append(&form);
|
||||||
|
g_box.append(&control.g_box);
|
||||||
|
|
||||||
|
// Connect events
|
||||||
|
control.upload.connect_clicked({
|
||||||
|
let form = form.clone();
|
||||||
|
move |this| {
|
||||||
|
this.set_uploading();
|
||||||
|
callback(
|
||||||
|
form.text().as_bytes(),
|
||||||
|
Box::new({
|
||||||
|
let this = this.clone();
|
||||||
|
move || this.set_resend() // on failure
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
form.buffer().connect_changed({
|
||||||
|
let control = control.clone();
|
||||||
|
let form = form.clone();
|
||||||
|
move |this| control.update(this.char_count(), form.text().len())
|
||||||
|
});
|
||||||
|
|
||||||
|
g_box
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,18 @@
|
|||||||
mod counter;
|
mod counter;
|
||||||
mod send;
|
mod upload;
|
||||||
|
|
||||||
use counter::Counter;
|
use counter::Counter;
|
||||||
use gtk::{
|
use gtk::{
|
||||||
prelude::{BoxExt, WidgetExt},
|
prelude::{BoxExt, WidgetExt},
|
||||||
Align, Box, Button, Label, Orientation,
|
Align, Box, Button, Label, Orientation,
|
||||||
};
|
};
|
||||||
pub use send::Send;
|
pub use upload::Upload;
|
||||||
|
|
||||||
const SPACING: i32 = 8;
|
const SPACING: i32 = 8;
|
||||||
|
|
||||||
pub struct Control {
|
pub struct Control {
|
||||||
pub counter: Label,
|
pub counter: Label,
|
||||||
pub send: Button,
|
pub upload: Button,
|
||||||
pub g_box: Box,
|
pub g_box: Box,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ impl Control {
|
|||||||
pub fn build() -> Self {
|
pub fn build() -> Self {
|
||||||
// Init components
|
// Init components
|
||||||
let counter = Label::counter();
|
let counter = Label::counter();
|
||||||
let send = Button::send();
|
let upload = Button::upload();
|
||||||
|
|
||||||
// Init main widget
|
// Init main widget
|
||||||
let g_box = Box::builder()
|
let g_box = Box::builder()
|
||||||
@ -33,12 +33,12 @@ impl Control {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
g_box.append(&counter);
|
g_box.append(&counter);
|
||||||
g_box.append(&send);
|
g_box.append(&upload);
|
||||||
|
|
||||||
// Return activated struct
|
// Return activated struct
|
||||||
Self {
|
Self {
|
||||||
counter,
|
counter,
|
||||||
send,
|
upload,
|
||||||
g_box,
|
g_box,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,6 +47,6 @@ impl Control {
|
|||||||
pub fn update(&self, chars_count: i32, bytes_total: usize) {
|
pub fn update(&self, chars_count: i32, bytes_total: usize) {
|
||||||
// Update children components
|
// Update children components
|
||||||
self.counter.update(chars_count, bytes_total);
|
self.counter.update(chars_count, bytes_total);
|
||||||
self.send.set_sensitive(bytes_total > 0);
|
self.upload.set_sensitive(bytes_total > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ impl Form for TextView {
|
|||||||
.css_classes(["frame", "view"])
|
.css_classes(["frame", "view"])
|
||||||
.extra_menu(&adapter.menu_model())
|
.extra_menu(&adapter.menu_model())
|
||||||
.left_margin(MARGIN)
|
.left_margin(MARGIN)
|
||||||
.margin_bottom(MARGIN / 4)
|
.margin_bottom(MARGIN / 2)
|
||||||
.right_margin(MARGIN)
|
.right_margin(MARGIN)
|
||||||
.top_margin(MARGIN)
|
.top_margin(MARGIN)
|
||||||
.wrap_mode(WrapMode::Word)
|
.wrap_mode(WrapMode::Word)
|
@ -1,15 +1,14 @@
|
|||||||
use gtk::{Align, Label};
|
use gtk::Label;
|
||||||
|
|
||||||
pub trait Title {
|
pub trait Title {
|
||||||
fn title(title: Option<&str>) -> Self;
|
fn title(label: &str) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Title for Label {
|
impl Title for Label {
|
||||||
fn title(title: Option<&str>) -> Self {
|
fn title(label: &str) -> Self {
|
||||||
Label::builder()
|
Label::builder()
|
||||||
.css_classes(["heading"])
|
.css_classes(["heading"])
|
||||||
.halign(Align::Start)
|
.label(label)
|
||||||
.label(title.unwrap_or("Titan input"))
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user