Improve manual message dialog, improve message bar design
This commit is contained in:
36
Cargo.lock
generated
36
Cargo.lock
generated
@ -1658,6 +1658,7 @@ dependencies = [
|
|||||||
"relm4-macros",
|
"relm4-macros",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sourceview5",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"ureq",
|
"ureq",
|
||||||
@ -2397,6 +2398,41 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sourceview5"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88c5f976a113e947bc5ec67758b2960c0db4ca76f80fb410d7cd86cd456d9ee5"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"gdk-pixbuf",
|
||||||
|
"gdk4",
|
||||||
|
"gio",
|
||||||
|
"glib",
|
||||||
|
"gtk4",
|
||||||
|
"libc",
|
||||||
|
"pango",
|
||||||
|
"sourceview5-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sourceview5-sys"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29637cccd56075a37ba72c0cc8b8d599dbc1d857e30dadea97eaacbc29b7fd46"
|
||||||
|
dependencies = [
|
||||||
|
"gdk-pixbuf-sys",
|
||||||
|
"gdk4-sys",
|
||||||
|
"gio-sys",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"gtk4-sys",
|
||||||
|
"libc",
|
||||||
|
"pango-sys",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
|||||||
@ -15,7 +15,8 @@ members = [
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ntfy-daemon = { path = "./ntfy-daemon" }
|
ntfy-daemon = { path = "./ntfy-daemon" }
|
||||||
gettext-rs = { version = "0.7", features = ["gettext-system"] }
|
gettext-rs = { version = "0.7", features = ["gettext-system"] }
|
||||||
gtk = { version = "0.7", package = "gtk4", features = ["v4_12", "blueprint"] }
|
gtk = { version = "0.7", package = "gtk4", features = ["gnome_45"] }
|
||||||
|
gsv = { package = "sourceview5", version = "0.7" }
|
||||||
once_cell = "1.14"
|
once_cell = "1.14"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
|
|||||||
@ -3,10 +3,17 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.small {
|
||||||
|
padding: 6px 12px;
|
||||||
|
min-height: 0px;
|
||||||
|
min-width: 0px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
.chip {
|
.chip {
|
||||||
min-height: 16px;
|
min-height: 16px;
|
||||||
min-width: 16px;
|
min-width: 16px;
|
||||||
padding: 3px 5px;
|
padding: 2px 5px;
|
||||||
color: @theme_fg_color;
|
color: @theme_fg_color;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
@ -29,3 +36,23 @@
|
|||||||
.chip--small {
|
.chip--small {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sourceview {
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code {
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid @borders;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message_bar {
|
||||||
|
padding: 2px 2px;
|
||||||
|
background-color: @sidebar_bg_color;
|
||||||
|
border-radius: 24px;
|
||||||
|
}
|
||||||
|
.message_bar entry {
|
||||||
|
background-color: @sidebar_bg_color;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|||||||
@ -127,16 +127,19 @@ template $NotifyWindow : Adw.ApplicationWindow {
|
|||||||
};
|
};
|
||||||
[bottom]
|
[bottom]
|
||||||
Adw.Bin {
|
Adw.Bin {
|
||||||
margin-top: 8;
|
margin-top: 4;
|
||||||
margin-bottom: 8;
|
margin-bottom: 4;
|
||||||
margin-start: 8;
|
margin-start: 4;
|
||||||
margin-end: 8;
|
margin-end: 4;
|
||||||
Adw.Clamp {
|
Adw.Clamp {
|
||||||
Gtk.Box {
|
Gtk.Box {
|
||||||
spacing: 4;
|
styles [
|
||||||
|
"message_bar"
|
||||||
|
]
|
||||||
Gtk.Button code_btn {
|
Gtk.Button code_btn {
|
||||||
styles [
|
styles [
|
||||||
"circular"
|
"circular",
|
||||||
|
"flat"
|
||||||
]
|
]
|
||||||
icon-name: "code-symbolic";
|
icon-name: "code-symbolic";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ base_id = 'com.ranfdev.Notify'
|
|||||||
dependency('glib-2.0', version: '>= 2.66')
|
dependency('glib-2.0', version: '>= 2.66')
|
||||||
dependency('gio-2.0', version: '>= 2.66')
|
dependency('gio-2.0', version: '>= 2.66')
|
||||||
dependency('gtk4', version: '>= 4.0.0')
|
dependency('gtk4', version: '>= 4.0.0')
|
||||||
|
dependency('gtksourceview-5', version: '>= 5.0.0')
|
||||||
|
|
||||||
glib_compile_resources = find_program('glib-compile-resources', required: true)
|
glib_compile_resources = find_program('glib-compile-resources', required: true)
|
||||||
glib_compile_schemas = find_program('glib-compile-schemas', required: true)
|
glib_compile_schemas = find_program('glib-compile-schemas', required: true)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use std::cell::OnceCell;
|
|||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
|
use gsv::prelude::*;
|
||||||
use gtk::{gio, glib};
|
use gtk::{gio, glib};
|
||||||
use ntfy_daemon::models;
|
use ntfy_daemon::models;
|
||||||
use ntfy_daemon::ntfy_capnp::{system_notifier, Status};
|
use ntfy_daemon::ntfy_capnp::{system_notifier, Status};
|
||||||
@ -26,13 +27,17 @@ impl<W: glib::IsA<gtk::Widget>> SpawnWithToast for W {
|
|||||||
&self,
|
&self,
|
||||||
f: impl Future<Output = Result<T, R>> + 'static,
|
f: impl Future<Output = Result<T, R>> + 'static,
|
||||||
) {
|
) {
|
||||||
let p: Option<NotifyWindow> = self.ancestor(NotifyWindow::static_type()).and_downcast();
|
let toast_overlay: Option<adw::ToastOverlay> = self
|
||||||
|
.ancestor(adw::ToastOverlay::static_type())
|
||||||
|
.and_downcast();
|
||||||
|
let win: Option<NotifyWindow> = self.ancestor(NotifyWindow::static_type()).and_downcast();
|
||||||
glib::MainContext::default().spawn_local(async move {
|
glib::MainContext::default().spawn_local(async move {
|
||||||
if let Err(e) = f.await {
|
if let Err(e) = f.await {
|
||||||
if let Some(p) = p {
|
if let Some(o) = toast_overlay
|
||||||
p.imp()
|
.as_ref()
|
||||||
.toast_overlay
|
.or_else(|| win.as_ref().map(|win| win.imp().toast_overlay.as_ref()))
|
||||||
.add_toast(adw::Toast::builder().title(&e.to_string()).build())
|
{
|
||||||
|
o.add_toast(adw::Toast::builder().title(&e.to_string()).build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -255,13 +260,6 @@ impl NotifyWindow {
|
|||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
let topic = self.selected_subscription().unwrap().topic();
|
let topic = self.selected_subscription().unwrap().topic();
|
||||||
let message = imp.entry.text();
|
let message = imp.entry.text();
|
||||||
let buffer = gtk::TextBuffer::new(None);
|
|
||||||
buffer.set_text(&format!(
|
|
||||||
r#"{{
|
|
||||||
"topic": "{topic}",
|
|
||||||
"message": "{message}"
|
|
||||||
}}"#
|
|
||||||
));
|
|
||||||
relm4_macros::view! {
|
relm4_macros::view! {
|
||||||
window = adw::Window {
|
window = adw::Window {
|
||||||
set_modal: true,
|
set_modal: true,
|
||||||
@ -270,50 +268,127 @@ impl NotifyWindow {
|
|||||||
set_content = &adw::ToolbarView {
|
set_content = &adw::ToolbarView {
|
||||||
add_top_bar = &adw::HeaderBar {},
|
add_top_bar = &adw::HeaderBar {},
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
set_content = &adw::Clamp {
|
set_content: toast_overlay = &adw::ToastOverlay {
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
set_child = >k::Box {
|
set_child = &adw::Clamp {
|
||||||
set_margin_top: 8,
|
#[wrap(Some)]
|
||||||
set_margin_bottom: 8,
|
set_child = >k::Box {
|
||||||
set_margin_start: 8,
|
set_margin_top: 8,
|
||||||
set_margin_end: 8,
|
set_margin_bottom: 8,
|
||||||
set_spacing: 8,
|
set_margin_start: 8,
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
set_margin_end: 8,
|
||||||
append = >k::Label {
|
|
||||||
set_label: "Here you can manually build the JSON message you want to POST to this topic",
|
|
||||||
set_xalign: 0.0,
|
|
||||||
set_halign: gtk::Align::Start,
|
|
||||||
set_wrap_mode: gtk::pango::WrapMode::WordChar,
|
|
||||||
set_wrap: true,
|
|
||||||
},
|
|
||||||
append: text_view = >k::TextView {
|
|
||||||
set_top_margin: 8,
|
|
||||||
set_bottom_margin: 8,
|
|
||||||
set_left_margin: 8,
|
|
||||||
set_right_margin: 8,
|
|
||||||
set_hexpand: true,
|
|
||||||
set_vexpand: true,
|
|
||||||
set_buffer: Some(&buffer),
|
|
||||||
},
|
|
||||||
append = >k::Box {
|
|
||||||
set_halign: gtk::Align::Center,
|
|
||||||
set_spacing: 8,
|
set_spacing: 8,
|
||||||
append = >k::Button {
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
add_css_class: "pill",
|
append = >k::Label {
|
||||||
set_label: "Documentation",
|
set_label: "Here you can manually build the JSON message you want to POST to this topic",
|
||||||
connect_clicked[this] => move |_| {
|
set_natural_wrap_mode: gtk::NaturalWrapMode::None,
|
||||||
gtk::UriLauncher::new("https://docs.ntfy.sh/publish/#publish-as-json").launch(
|
set_xalign: 0.0,
|
||||||
Some(&this),
|
set_halign: gtk::Align::Start,
|
||||||
gio::Cancellable::NONE,
|
set_wrap_mode: gtk::pango::WrapMode::WordChar,
|
||||||
|_| {}
|
set_wrap: true,
|
||||||
);
|
},
|
||||||
}
|
append = >k::Label {
|
||||||
|
add_css_class: "heading",
|
||||||
|
set_label: "JSON",
|
||||||
|
set_xalign: 0.0,
|
||||||
|
set_halign: gtk::Align::Start,
|
||||||
|
},
|
||||||
|
append: text_view = &gsv::View {
|
||||||
|
add_css_class: "code",
|
||||||
|
set_tab_width: 4,
|
||||||
|
set_indent_width: 2,
|
||||||
|
set_auto_indent: true,
|
||||||
|
set_top_margin: 4,
|
||||||
|
set_bottom_margin: 4,
|
||||||
|
set_left_margin: 4,
|
||||||
|
set_right_margin: 4,
|
||||||
|
set_hexpand: true,
|
||||||
|
set_vexpand: true,
|
||||||
|
set_monospace: true,
|
||||||
|
set_background_pattern: gsv::BackgroundPatternType::Grid
|
||||||
|
},
|
||||||
|
append = >k::Label {
|
||||||
|
add_css_class: "heading",
|
||||||
|
set_label: "Snippets",
|
||||||
|
set_xalign: 0.0,
|
||||||
|
set_halign: gtk::Align::Start,
|
||||||
|
},
|
||||||
|
append = >k::Box {
|
||||||
|
set_spacing: 4,
|
||||||
|
append = >k::Button {
|
||||||
|
add_css_class: "pill",
|
||||||
|
add_css_class: "small",
|
||||||
|
set_label: "Title",
|
||||||
|
connect_clicked[text_view] => move |_| {
|
||||||
|
text_view.buffer().insert_at_cursor(r#""title": "Title of your message""#)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append = >k::Button {
|
||||||
|
add_css_class: "pill",
|
||||||
|
add_css_class: "small",
|
||||||
|
set_label: "Tags",
|
||||||
|
connect_clicked[text_view] => move |_| {
|
||||||
|
text_view.buffer().insert_at_cursor(r#""tags": ["warning","cd"]"#)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append = >k::Button {
|
||||||
|
add_css_class: "pill",
|
||||||
|
add_css_class: "small",
|
||||||
|
set_label: "Priority",
|
||||||
|
connect_clicked[text_view] => move |_| {
|
||||||
|
text_view.buffer().insert_at_cursor(r#""priority": 5"#)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append = >k::Button {
|
||||||
|
add_css_class: "pill",
|
||||||
|
add_css_class: "small",
|
||||||
|
set_label: "View Action",
|
||||||
|
connect_clicked[text_view] => move |_| {
|
||||||
|
text_view.buffer().insert_at_cursor(r#""action": [
|
||||||
|
{
|
||||||
|
"type": "view",
|
||||||
|
"label": "torvalds boosted your toot",
|
||||||
|
"url": "https://joinmastodon.org"
|
||||||
|
}
|
||||||
|
]"#)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append = >k::Button {
|
||||||
|
add_css_class: "pill",
|
||||||
|
add_css_class: "small",
|
||||||
|
set_label: "HTTP Action",
|
||||||
|
connect_clicked[text_view] => move |_| {
|
||||||
|
text_view.buffer().insert_at_cursor(r#""action": [
|
||||||
|
{
|
||||||
|
"type": "http",
|
||||||
|
"label": "Turn off lights",
|
||||||
|
"method": "post",
|
||||||
|
"url": "https://api.example.com/lights",
|
||||||
|
"body": "OFF"
|
||||||
|
}
|
||||||
|
]"#)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append = >k::Button {
|
||||||
|
add_css_class: "circular",
|
||||||
|
add_css_class: "small",
|
||||||
|
set_label: "?",
|
||||||
|
connect_clicked[this] => move |_| {
|
||||||
|
gtk::UriLauncher::new("https://docs.ntfy.sh/publish/#publish-as-json").launch(
|
||||||
|
Some(&this),
|
||||||
|
gio::Cancellable::NONE,
|
||||||
|
|_| {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
append = >k::Button {
|
append = >k::Button {
|
||||||
|
set_margin_top: 8,
|
||||||
|
set_margin_bottom: 8,
|
||||||
add_css_class: "suggested-action",
|
add_css_class: "suggested-action",
|
||||||
add_css_class: "pill",
|
add_css_class: "pill",
|
||||||
set_label: "Send",
|
set_label: "Send",
|
||||||
connect_clicked[this, text_view] => move |_| {
|
connect_clicked[this, toast_overlay, text_view] => move |_| {
|
||||||
let thisc = this.clone();
|
let thisc = this.clone();
|
||||||
let text_view = text_view.clone();
|
let text_view = text_view.clone();
|
||||||
let f = async move {
|
let f = async move {
|
||||||
@ -327,7 +402,7 @@ impl NotifyWindow {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.publish_msg(msg).await
|
.publish_msg(msg).await
|
||||||
};
|
};
|
||||||
this.spawn_with_near_toast(f);
|
toast_overlay.spawn_with_near_toast(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,6 +411,26 @@ impl NotifyWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lang = gsv::LanguageManager::default().language("json").unwrap();
|
||||||
|
let buffer = gsv::Buffer::with_language(&lang);
|
||||||
|
buffer.set_text(&format!(
|
||||||
|
r#"{{
|
||||||
|
"topic": "{topic}",
|
||||||
|
"message": "{message}"
|
||||||
|
}}"#
|
||||||
|
));
|
||||||
|
text_view.set_buffer(Some(&buffer));
|
||||||
|
|
||||||
|
let manager = adw::StyleManager::default();
|
||||||
|
let scheme_name = if manager.is_dark() {
|
||||||
|
"solarized-dark"
|
||||||
|
} else {
|
||||||
|
"solarized-light"
|
||||||
|
};
|
||||||
|
let scheme = gsv::StyleSchemeManager::default().scheme(scheme_name);
|
||||||
|
buffer.set_style_scheme(scheme.as_ref());
|
||||||
|
|
||||||
window.present();
|
window.present();
|
||||||
}
|
}
|
||||||
fn show_subscription_info(&self) {
|
fn show_subscription_info(&self) {
|
||||||
|
|||||||
Reference in New Issue
Block a user