implement response counter

This commit is contained in:
yggverse 2024-10-16 17:36:12 +03:00
parent 88aeab91be
commit b3b0892d62
17 changed files with 193 additions and 147 deletions

View File

@ -279,8 +279,10 @@ impl Page {
let title = gformat!("Input expected");
let description = gformat!("{placeholder}");
// Show input request
input.show(Some(&description), Some(&1024));
// Make input form
input.use_default(uri, Some(&description), Some(1024));
input.show();
// @TODO hide
// Update meta
meta.borrow_mut().status = Some(status);

View File

@ -1,34 +1,35 @@
mod content;
mod default;
mod widget;
use content::Content;
use default::Default;
use gtk::glib::Uri;
use widget::Widget;
use adw::Clamp;
use std::sync::Arc;
pub struct Input {
content: Arc<Content>,
widget: Arc<Widget>,
}
impl Input {
// Construct
pub fn new_arc() -> Arc<Self> {
// Init components
let content = Content::new_arc();
// Init widget
let widget = Widget::new_arc(content.gobject());
let widget = Widget::new_arc();
// Result
Arc::new(Self { content, widget })
Arc::new(Self { widget })
}
// Actions
pub fn show(&self, title: Option<&str>, limit: Option<&i32>) {
self.content.update(title, limit);
self.widget.show(true);
pub fn use_default(&self, base: Uri, title: Option<&str>, size_limit: Option<usize>) {
self.widget
.update(Some(&Default::new_arc(base, title, size_limit).gobject()));
}
pub fn show(&self) {
self.widget.show();
}
// Getters

View File

@ -1,52 +0,0 @@
mod control;
mod response;
mod title;
mod widget;
use control::Control;
use response::Response;
use title::Title;
use widget::Widget;
use gtk::Box;
use std::sync::Arc;
pub struct Content {
control: Arc<Control>,
response: Arc<Response>,
title: Arc<Title>,
widget: Arc<Widget>,
}
impl Content {
// Construct
pub fn new_arc() -> Arc<Self> {
// Init components
let control = Control::new_arc();
let response = Response::new_arc();
let title = Title::new_arc();
// Init widget
let widget = Widget::new_arc(title.gobject(), response.gobject(), control.gobject());
// Return activated struct
Arc::new(Self {
control,
response,
title,
widget,
})
}
// Actions
pub fn update(&self, title: Option<&str>, count_limit: Option<&i32>) {
self.control.update(&0, count_limit); // @TODO
self.title.update(title);
self.response.grab_focus();
}
// Getters
pub fn gobject(&self) -> &Box {
&self.widget.gobject()
}
}

View File

@ -1,31 +0,0 @@
use gtk::{prelude::WidgetExt, TextView, WrapMode};
use std::sync::Arc;
pub struct Widget {
gobject: TextView,
}
impl Widget {
// Construct
pub fn new_arc() -> Arc<Self> {
let gobject = TextView::builder()
.left_margin(8)
.pixels_above_lines(8)
.pixels_below_lines(8)
.right_margin(8)
.wrap_mode(WrapMode::Word)
.build();
Arc::new(Self { gobject })
}
// Actions
pub fn grab_focus(&self) {
self.gobject.grab_focus();
}
// Getters
pub fn gobject(&self) -> &TextView {
&self.gobject
}
}

View File

@ -0,0 +1,61 @@
mod control;
mod response;
mod title;
mod widget;
use control::Control;
use response::Response;
use title::Title;
use widget::Widget;
use gtk::{
gio::SimpleAction,
glib::{uuid_string_random, Uri, UriHideFlags},
Box,
};
use std::sync::Arc;
pub struct Default {
// Components
widget: Arc<Widget>,
}
impl Default {
// Construct
pub fn new_arc(base: Uri, title: Option<&str>, size_limit: Option<usize>) -> Arc<Self> {
// Init local action group
let action_update = Arc::new(SimpleAction::new(&uuid_string_random(), None));
// Init components
let control = Control::new_arc();
let response = Response::new_arc(action_update.clone());
let title = Title::new_arc(title);
// Init widget
let widget = Widget::new_arc(title.gobject(), response.gobject(), control.gobject());
// Init events
action_update.connect_activate({
let control = control.clone();
let response = response.clone();
move |_, _| {
control.update(match size_limit {
Some(limit_value) => Some(
limit_value
- (base.to_string_partial(UriHideFlags::QUERY).len()
+ Uri::escape_string(response.text().as_str(), None, false).len()),
),
None => None,
});
}
});
// Return activated struct
Arc::new(Self { widget })
}
// Getters
pub fn gobject(&self) -> &Box {
&self.widget.gobject()
}
}

View File

@ -1,8 +1,8 @@
mod limit;
mod left;
mod send;
mod widget;
use limit::Limit;
use left::Left;
use send::Send;
use widget::Widget;
@ -10,7 +10,7 @@ use gtk::Box;
use std::sync::Arc;
pub struct Control {
limit: Arc<Limit>,
limit: Arc<Left>,
send: Arc<Send>,
widget: Arc<Widget>,
}
@ -19,7 +19,7 @@ impl Control {
// Construct
pub fn new_arc() -> Arc<Self> {
// Init components
let limit = Limit::new_arc();
let limit = Left::new_arc();
let send = Send::new_arc();
// Init widget
@ -34,9 +34,13 @@ impl Control {
}
// Actions
pub fn update(&self, count: &i32, count_limit: Option<&i32>) {
self.limit.update(count, count_limit);
// @TODO self.send.update(limit);
pub fn update(&self, left: Option<usize>) {
// Update children components
self.limit.update(left);
self.send.update(match left {
Some(value) => value > 0,
None => false,
});
}
// Getters

View File

@ -5,11 +5,11 @@ use widget::Widget;
use gtk::Label;
use std::sync::Arc;
pub struct Title {
pub struct Left {
widget: Arc<Widget>,
}
impl Title {
impl Left {
// Construct
pub fn new_arc() -> Arc<Self> {
// Init widget
@ -20,8 +20,8 @@ impl Title {
}
// Actions
pub fn update(&self, text: Option<&str>) {
self.widget.update(text);
pub fn update(&self, left: Option<usize>) {
self.widget.update(left);
}
// Getters

View File

@ -8,22 +8,21 @@ pub struct Widget {
impl Widget {
// Construct
pub fn new_arc() -> Arc<Self> {
let gobject = Label::builder().use_markup(true).build();
let gobject = Label::builder().build();
Arc::new(Self { gobject })
}
// Actions
pub fn update(&self, count: &i32, count_limit: Option<&i32>) {
match count_limit {
Some(limit) => {
pub fn update(&self, left: Option<usize>) {
match left {
Some(value) => {
// Update color on limit reached
self.gobject
.set_css_classes(&[if count < limit { "success" } else { "error" }]); // @TODO add warning step?
.set_css_classes(&[if value > 0 { "success" } else { "error" }]); // @TODO add warning step?
// Update text
self.gobject
.set_markup(&format!("{count} <sup>/ {limit}</sup>"));
self.gobject.set_label(&value.to_string());
// Toggle visibility if limit provided
self.gobject.set_visible(true);

View File

@ -10,6 +10,7 @@ pub struct Send {
}
impl Send {
// Construct
pub fn new_arc() -> Arc<Self> {
// Init widget
let widget = Widget::new_arc();
@ -18,6 +19,11 @@ impl Send {
Arc::new(Self { widget })
}
// Actions
pub fn update(&self, is_sensitive: bool) {
self.widget.update(is_sensitive);
}
// Getters
pub fn gobject(&self) -> &Button {
&self.widget.gobject()

View File

@ -1,4 +1,4 @@
use gtk::Button;
use gtk::{prelude::WidgetExt, Button};
use std::sync::Arc;
pub struct Widget {
@ -16,6 +16,11 @@ impl Widget {
Arc::new(Self { gobject })
}
// Actions
pub fn update(&self, is_sensitive: bool) {
self.gobject.set_sensitive(is_sensitive);
}
// Getters
pub fn gobject(&self) -> &Button {
&self.gobject

View File

@ -10,6 +10,7 @@ pub struct Widget {
impl Widget {
// Construct
pub fn new_arc(limit: &Label, send: &Button) -> Arc<Self> {
// Init gobject
let gobject = Box::builder()
.halign(Align::End)
.orientation(Orientation::Horizontal)
@ -19,6 +20,7 @@ impl Widget {
gobject.append(limit);
gobject.append(send);
// Return new struct
Arc::new(Self { gobject })
}

View File

@ -2,7 +2,7 @@ mod widget;
use widget::Widget;
use gtk::TextView;
use gtk::{gio::SimpleAction, glib::GString, TextView};
use std::sync::Arc;
pub struct Response {
@ -11,20 +11,24 @@ pub struct Response {
impl Response {
// Construct
pub fn new_arc() -> Arc<Self> {
pub fn new_arc(action_update: Arc<SimpleAction>) -> Arc<Self> {
// Init widget
let widget = Widget::new_arc();
let widget = Widget::new_arc(action_update);
// Result
Arc::new(Self { widget })
}
// Actions
pub fn grab_focus(&self) {
self.widget.grab_focus();
pub fn focus(&self) {
self.widget.focus();
}
// Getters
pub fn text(&self) -> GString {
self.widget.text()
}
pub fn gobject(&self) -> &TextView {
&self.widget.gobject()
}

View File

@ -0,0 +1,45 @@
use gtk::{
gio::SimpleAction, glib::GString, prelude::{ActionExt, TextBufferExt, TextViewExt, WidgetExt}, TextView, WrapMode
};
use std::sync::Arc;
pub struct Widget {
gobject: TextView,
}
impl Widget {
// Construct
pub fn new_arc(action_update: Arc<SimpleAction>) -> Arc<Self> {
// Init gobject
let gobject = TextView::builder()
.left_margin(8)
.pixels_above_lines(8)
.pixels_below_lines(8)
.right_margin(8)
.wrap_mode(WrapMode::Word)
.build();
// Init events
gobject.buffer().connect_changed(move |_| {
action_update.activate(None);
});
// Return activated struct
Arc::new(Self { gobject })
}
// Actions
pub fn focus(&self) {
self.gobject.grab_focus();
}
// Getters
pub fn text(&self) -> GString {
let buffer = self.gobject.buffer();
buffer.text(&buffer.start_iter(), &buffer.end_iter(), true)
}
pub fn gobject(&self) -> &TextView {
&self.gobject
}
}

View File

@ -5,25 +5,20 @@ use widget::Widget;
use gtk::Label;
use std::sync::Arc;
pub struct Limit {
pub struct Title {
widget: Arc<Widget>,
}
impl Limit {
impl Title {
// Construct
pub fn new_arc() -> Arc<Self> {
pub fn new_arc(title: Option<&str>) -> Arc<Self> {
// Init widget
let widget = Widget::new_arc();
let widget = Widget::new_arc(title);
// Result
Arc::new(Self { widget })
}
// Actions
pub fn update(&self, count: &i32, limit: Option<&i32>) {
self.widget.update(count, limit);
}
// Getters
pub fn gobject(&self) -> &Label {
&self.widget.gobject()

View File

@ -7,7 +7,7 @@ pub struct Widget {
impl Widget {
// Construct
pub fn new_arc() -> Arc<Self> {
pub fn new_arc(title: Option<&str>) -> Arc<Self> {
let gobject = Label::builder()
.css_classes(["heading"])
.halign(Align::Start)
@ -16,20 +16,12 @@ impl Widget {
.visible(false)
.build();
Arc::new(Self { gobject })
}
// Actions
pub fn update(&self, text: Option<&str>) {
match text {
Some(value) => {
self.gobject.set_label(value);
self.gobject.set_visible(!value.is_empty());
}
None => {
self.gobject.set_visible(false);
}
match title {
Some(value) => gobject.set_label(value),
None => gobject.set_visible(false),
}
Arc::new(Self { gobject })
}
// Getters

View File

@ -8,9 +8,8 @@ pub struct Widget {
impl Widget {
// Construct
pub fn new_arc(child: &Box) -> Arc<Self> {
pub fn new_arc() -> Arc<Self> {
let gobject = Clamp::builder()
.child(child)
.css_classes(["app-notification"])
.maximum_size(800)
.visible(false)
@ -20,8 +19,22 @@ impl Widget {
}
// Actions
pub fn show(&self, visible: bool) {
self.gobject.set_visible(visible);
pub fn show(&self) {
self.gobject.set_visible(true)
}
/* not in use
pub fn hide(&self) {
self.gobject.set_visible(false)
} */
pub fn update(&self, child: Option<&Box>) {
if child.is_some() {
self.gobject.set_child(child);
self.gobject.set_visible(true);
} else {
self.gobject.set_visible(false)
}
}
// Getters