Skip to content

Commit b212c99

Browse files
committed
Improve manual message dialog, improve message bar design
1 parent 10ee058 commit b212c99

File tree

6 files changed

+221
-58
lines changed

6 files changed

+221
-58
lines changed

Cargo.lock

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ members = [
1515
[dependencies]
1616
ntfy-daemon = { path = "./ntfy-daemon" }
1717
gettext-rs = { version = "0.7", features = ["gettext-system"] }
18-
gtk = { version = "0.7", package = "gtk4", features = ["v4_12", "blueprint"] }
18+
gtk = { version = "0.7", package = "gtk4", features = ["gnome_45"] }
19+
gsv = { package = "sourceview5", version = "0.7" }
1920
once_cell = "1.14"
2021
tracing = "0.1.37"
2122
tracing-subscriber = "0.3"

data/resources/style.css

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@
33
font-weight: bold;
44
}
55

6+
button.small {
7+
padding: 6px 12px;
8+
min-height: 0px;
9+
min-width: 0px;
10+
font-size: 14px;
11+
}
12+
613
.chip {
714
min-height: 16px;
815
min-width: 16px;
9-
padding: 3px 5px;
16+
padding: 2px 5px;
1017
color: @theme_fg_color;
1118
border-radius: 8px;
1219
}
@@ -29,3 +36,23 @@
2936
.chip--small {
3037
font-size: 0.8rem;
3138
}
39+
40+
41+
.sourceview {
42+
padding: 4px 8px;
43+
}
44+
45+
.code {
46+
border-radius: 12px;
47+
border: 1px solid @borders;
48+
}
49+
50+
.message_bar {
51+
padding: 2px 2px;
52+
background-color: @sidebar_bg_color;
53+
border-radius: 24px;
54+
}
55+
.message_bar entry {
56+
background-color: @sidebar_bg_color;
57+
border-radius: 12px;
58+
}

data/resources/ui/window.blp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,19 @@ template $NotifyWindow : Adw.ApplicationWindow {
127127
};
128128
[bottom]
129129
Adw.Bin {
130-
margin-top: 8;
131-
margin-bottom: 8;
132-
margin-start: 8;
133-
margin-end: 8;
130+
margin-top: 4;
131+
margin-bottom: 4;
132+
margin-start: 4;
133+
margin-end: 4;
134134
Adw.Clamp {
135135
Gtk.Box {
136-
spacing: 4;
136+
styles [
137+
"message_bar"
138+
]
137139
Gtk.Button code_btn {
138140
styles [
139-
"circular"
141+
"circular",
142+
"flat"
140143
]
141144
icon-name: "code-symbolic";
142145
}

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ base_id = 'com.ranfdev.Notify'
1414
dependency('glib-2.0', version: '>= 2.66')
1515
dependency('gio-2.0', version: '>= 2.66')
1616
dependency('gtk4', version: '>= 4.0.0')
17+
dependency('gtksourceview-5', version: '>= 5.0.0')
1718

1819
glib_compile_resources = find_program('glib-compile-resources', required: true)
1920
glib_compile_schemas = find_program('glib-compile-schemas', required: true)

src/widgets/window.rs

Lines changed: 145 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::cell::OnceCell;
44
use adw::prelude::*;
55
use adw::subclass::prelude::*;
66
use futures::prelude::*;
7+
use gsv::prelude::*;
78
use gtk::{gio, glib};
89
use ntfy_daemon::models;
910
use ntfy_daemon::ntfy_capnp::{system_notifier, Status};
@@ -26,13 +27,17 @@ impl<W: glib::IsA<gtk::Widget>> SpawnWithToast for W {
2627
&self,
2728
f: impl Future<Output = Result<T, R>> + 'static,
2829
) {
29-
let p: Option<NotifyWindow> = self.ancestor(NotifyWindow::static_type()).and_downcast();
30+
let toast_overlay: Option<adw::ToastOverlay> = self
31+
.ancestor(adw::ToastOverlay::static_type())
32+
.and_downcast();
33+
let win: Option<NotifyWindow> = self.ancestor(NotifyWindow::static_type()).and_downcast();
3034
glib::MainContext::default().spawn_local(async move {
3135
if let Err(e) = f.await {
32-
if let Some(p) = p {
33-
p.imp()
34-
.toast_overlay
35-
.add_toast(adw::Toast::builder().title(&e.to_string()).build())
36+
if let Some(o) = toast_overlay
37+
.as_ref()
38+
.or_else(|| win.as_ref().map(|win| win.imp().toast_overlay.as_ref()))
39+
{
40+
o.add_toast(adw::Toast::builder().title(&e.to_string()).build())
3641
}
3742
}
3843
});
@@ -255,13 +260,6 @@ impl NotifyWindow {
255260
let this = self.clone();
256261
let topic = self.selected_subscription().unwrap().topic();
257262
let message = imp.entry.text();
258-
let buffer = gtk::TextBuffer::new(None);
259-
buffer.set_text(&format!(
260-
r#"{{
261-
"topic": "{topic}",
262-
"message": "{message}"
263-
}}"#
264-
));
265263
relm4_macros::view! {
266264
window = adw::Window {
267265
set_modal: true,
@@ -270,50 +268,127 @@ impl NotifyWindow {
270268
set_content = &adw::ToolbarView {
271269
add_top_bar = &adw::HeaderBar {},
272270
#[wrap(Some)]
273-
set_content = &adw::Clamp {
271+
set_content: toast_overlay = &adw::ToastOverlay {
274272
#[wrap(Some)]
275-
set_child = &gtk::Box {
276-
set_margin_top: 8,
277-
set_margin_bottom: 8,
278-
set_margin_start: 8,
279-
set_margin_end: 8,
280-
set_spacing: 8,
281-
set_orientation: gtk::Orientation::Vertical,
282-
append = &gtk::Label {
283-
set_label: "Here you can manually build the JSON message you want to POST to this topic",
284-
set_xalign: 0.0,
285-
set_halign: gtk::Align::Start,
286-
set_wrap_mode: gtk::pango::WrapMode::WordChar,
287-
set_wrap: true,
288-
},
289-
append: text_view = &gtk::TextView {
290-
set_top_margin: 8,
291-
set_bottom_margin: 8,
292-
set_left_margin: 8,
293-
set_right_margin: 8,
294-
set_hexpand: true,
295-
set_vexpand: true,
296-
set_buffer: Some(&buffer),
297-
},
298-
append = &gtk::Box {
299-
set_halign: gtk::Align::Center,
273+
set_child = &adw::Clamp {
274+
#[wrap(Some)]
275+
set_child = &gtk::Box {
276+
set_margin_top: 8,
277+
set_margin_bottom: 8,
278+
set_margin_start: 8,
279+
set_margin_end: 8,
300280
set_spacing: 8,
301-
append = &gtk::Button {
302-
add_css_class: "pill",
303-
set_label: "Documentation",
304-
connect_clicked[this] => move |_| {
305-
gtk::UriLauncher::new("https://docs.ntfy.sh/publish/#publish-as-json").launch(
306-
Some(&this),
307-
gio::Cancellable::NONE,
308-
|_| {}
309-
);
310-
}
281+
set_orientation: gtk::Orientation::Vertical,
282+
append = &gtk::Label {
283+
set_label: "Here you can manually build the JSON message you want to POST to this topic",
284+
set_natural_wrap_mode: gtk::NaturalWrapMode::None,
285+
set_xalign: 0.0,
286+
set_halign: gtk::Align::Start,
287+
set_wrap_mode: gtk::pango::WrapMode::WordChar,
288+
set_wrap: true,
289+
},
290+
append = &gtk::Label {
291+
add_css_class: "heading",
292+
set_label: "JSON",
293+
set_xalign: 0.0,
294+
set_halign: gtk::Align::Start,
295+
},
296+
append: text_view = &gsv::View {
297+
add_css_class: "code",
298+
set_tab_width: 4,
299+
set_indent_width: 2,
300+
set_auto_indent: true,
301+
set_top_margin: 4,
302+
set_bottom_margin: 4,
303+
set_left_margin: 4,
304+
set_right_margin: 4,
305+
set_hexpand: true,
306+
set_vexpand: true,
307+
set_monospace: true,
308+
set_background_pattern: gsv::BackgroundPatternType::Grid
309+
},
310+
append = &gtk::Label {
311+
add_css_class: "heading",
312+
set_label: "Snippets",
313+
set_xalign: 0.0,
314+
set_halign: gtk::Align::Start,
315+
},
316+
append = &gtk::Box {
317+
set_spacing: 4,
318+
append = &gtk::Button {
319+
add_css_class: "pill",
320+
add_css_class: "small",
321+
set_label: "Title",
322+
connect_clicked[text_view] => move |_| {
323+
text_view.buffer().insert_at_cursor(r#""title": "Title of your message""#)
324+
}
325+
},
326+
append = &gtk::Button {
327+
add_css_class: "pill",
328+
add_css_class: "small",
329+
set_label: "Tags",
330+
connect_clicked[text_view] => move |_| {
331+
text_view.buffer().insert_at_cursor(r#""tags": ["warning","cd"]"#)
332+
}
333+
},
334+
append = &gtk::Button {
335+
add_css_class: "pill",
336+
add_css_class: "small",
337+
set_label: "Priority",
338+
connect_clicked[text_view] => move |_| {
339+
text_view.buffer().insert_at_cursor(r#""priority": 5"#)
340+
}
341+
},
342+
append = &gtk::Button {
343+
add_css_class: "pill",
344+
add_css_class: "small",
345+
set_label: "View Action",
346+
connect_clicked[text_view] => move |_| {
347+
text_view.buffer().insert_at_cursor(r#""action": [
348+
{
349+
"type": "view",
350+
"label": "torvalds boosted your toot",
351+
"url": "https://joinmastodon.org"
352+
}
353+
]"#)
354+
}
355+
},
356+
append = &gtk::Button {
357+
add_css_class: "pill",
358+
add_css_class: "small",
359+
set_label: "HTTP Action",
360+
connect_clicked[text_view] => move |_| {
361+
text_view.buffer().insert_at_cursor(r#""action": [
362+
{
363+
"type": "http",
364+
"label": "Turn off lights",
365+
"method": "post",
366+
"url": "https://api.example.com/lights",
367+
"body": "OFF"
368+
}
369+
]"#)
370+
}
371+
},
372+
append = &gtk::Button {
373+
add_css_class: "circular",
374+
add_css_class: "small",
375+
set_label: "?",
376+
connect_clicked[this] => move |_| {
377+
gtk::UriLauncher::new("https://docs.ntfy.sh/publish/#publish-as-json").launch(
378+
Some(&this),
379+
gio::Cancellable::NONE,
380+
|_| {}
381+
);
382+
}
383+
},
311384
},
312385
append = &gtk::Button {
386+
set_margin_top: 8,
387+
set_margin_bottom: 8,
313388
add_css_class: "suggested-action",
314389
add_css_class: "pill",
315390
set_label: "Send",
316-
connect_clicked[this, text_view] => move |_| {
391+
connect_clicked[this, toast_overlay, text_view] => move |_| {
317392
let thisc = this.clone();
318393
let text_view = text_view.clone();
319394
let f = async move {
@@ -327,7 +402,7 @@ impl NotifyWindow {
327402
.unwrap()
328403
.publish_msg(msg).await
329404
};
330-
this.spawn_with_near_toast(f);
405+
toast_overlay.spawn_with_near_toast(f);
331406
}
332407
}
333408
}
@@ -336,6 +411,26 @@ impl NotifyWindow {
336411
}
337412
}
338413
}
414+
415+
let lang = gsv::LanguageManager::default().language("json").unwrap();
416+
let buffer = gsv::Buffer::with_language(&lang);
417+
buffer.set_text(&format!(
418+
r#"{{
419+
"topic": "{topic}",
420+
"message": "{message}"
421+
}}"#
422+
));
423+
text_view.set_buffer(Some(&buffer));
424+
425+
let manager = adw::StyleManager::default();
426+
let scheme_name = if manager.is_dark() {
427+
"solarized-dark"
428+
} else {
429+
"solarized-light"
430+
};
431+
let scheme = gsv::StyleSchemeManager::default().scheme(scheme_name);
432+
buffer.set_style_scheme(scheme.as_ref());
433+
339434
window.present();
340435
}
341436
fn show_subscription_info(&self) {

0 commit comments

Comments
 (0)