Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
2f736e2138 |
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -103,6 +103,14 @@ version = "0.8.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dndbuster"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"gtk4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -551,14 +559,6 @@ dependencies = [
|
|||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pdt"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"gtk4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pdt"
|
name = "dndbuster"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
# pdt - PleaseDisturbTimer
|
# DnDBuster - Do not Disturb Buster
|
||||||
|
|
||||||
A timer that notifies you - even if "do not disturb" is enabled.
|
A timer that notifies you - even if "do not disturb" is enabled.
|
||||||
|
|
||||||
|
Note: notification doesn't work as .desktop entry is missing. See dndbuster-python.
|
||||||
|
|
||||||
## Alternatives
|
## Alternatives
|
||||||
|
|
||||||
https://man.archlinux.org/man/notify-send.1.en
|
https://man.archlinux.org/man/notify-send.1.en
|
||||||
|
172
src/clipboard.rs
172
src/clipboard.rs
@ -1,172 +0,0 @@
|
|||||||
// Copied from https://github.com/gtk-rs/gtk4-rs/blob/main/examples/clipboard/main.rs
|
|
||||||
|
|
||||||
use gtk4 as gtk;
|
|
||||||
use gtk::{
|
|
||||||
gdk, gio,
|
|
||||||
glib::{self, clone},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
|
||||||
let application = gtk::Application::builder()
|
|
||||||
.application_id("com.github.gtk-rs.examples.clipboard")
|
|
||||||
.build();
|
|
||||||
application.connect_activate(build_ui);
|
|
||||||
application.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_ui(application: >k::Application) {
|
|
||||||
let window = gtk::ApplicationWindow::builder()
|
|
||||||
.application(application)
|
|
||||||
.title("Clipboard")
|
|
||||||
.default_width(660)
|
|
||||||
.default_height(420)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let display = gdk::Display::default().unwrap();
|
|
||||||
let clipboard = display.clipboard();
|
|
||||||
|
|
||||||
let container = gtk::Box::builder()
|
|
||||||
.orientation(gtk::Orientation::Vertical)
|
|
||||||
.margin_top(24)
|
|
||||||
.margin_bottom(24)
|
|
||||||
.margin_start(24)
|
|
||||||
.margin_end(24)
|
|
||||||
.halign(gtk::Align::Center)
|
|
||||||
.valign(gtk::Align::Center)
|
|
||||||
.spacing(24)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// The text copy/paste part
|
|
||||||
let title = gtk::Label::builder()
|
|
||||||
.label("Text")
|
|
||||||
.halign(gtk::Align::Start)
|
|
||||||
.build();
|
|
||||||
title.add_css_class("title-2");
|
|
||||||
container.append(&title);
|
|
||||||
|
|
||||||
let text_container = gtk::Box::builder()
|
|
||||||
.halign(gtk::Align::Center)
|
|
||||||
.orientation(gtk::Orientation::Horizontal)
|
|
||||||
.spacing(24)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let from_entry = gtk::Entry::builder()
|
|
||||||
.placeholder_text("Type text to copy")
|
|
||||||
.build();
|
|
||||||
text_container.append(&from_entry);
|
|
||||||
|
|
||||||
let copy_btn = gtk::Button::with_label("Copy");
|
|
||||||
copy_btn.connect_clicked(clone!(
|
|
||||||
#[weak]
|
|
||||||
clipboard,
|
|
||||||
#[weak]
|
|
||||||
from_entry,
|
|
||||||
move |_btn| {
|
|
||||||
let text = from_entry.text();
|
|
||||||
clipboard.set_text(&text);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
text_container.append(©_btn);
|
|
||||||
|
|
||||||
let into_entry = gtk::Entry::new();
|
|
||||||
text_container.append(&into_entry);
|
|
||||||
|
|
||||||
let paste_btn = gtk::Button::with_label("Paste");
|
|
||||||
paste_btn.connect_clicked(clone!(
|
|
||||||
#[weak]
|
|
||||||
clipboard,
|
|
||||||
#[weak]
|
|
||||||
into_entry,
|
|
||||||
move |_btn| {
|
|
||||||
clipboard.read_text_async(
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
clone!(
|
|
||||||
#[weak]
|
|
||||||
into_entry,
|
|
||||||
move |res| {
|
|
||||||
if let Ok(Some(text)) = res {
|
|
||||||
into_entry.set_text(&text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
text_container.append(&paste_btn);
|
|
||||||
container.append(&text_container);
|
|
||||||
|
|
||||||
// The texture copy/paste part
|
|
||||||
let title = gtk::Label::builder()
|
|
||||||
.label("Texture")
|
|
||||||
.halign(gtk::Align::Start)
|
|
||||||
.build();
|
|
||||||
title.add_css_class("title-2");
|
|
||||||
container.append(&title);
|
|
||||||
|
|
||||||
let texture_container = gtk::Box::builder()
|
|
||||||
.orientation(gtk::Orientation::Horizontal)
|
|
||||||
.halign(gtk::Align::Center)
|
|
||||||
.spacing(24)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let file = gio::File::for_path("./examples/clipboard/asset.png");
|
|
||||||
let asset_paintable = gdk::Texture::from_file(&file).unwrap();
|
|
||||||
|
|
||||||
let image_from = gtk::Image::builder()
|
|
||||||
.pixel_size(96)
|
|
||||||
.paintable(&asset_paintable)
|
|
||||||
.build();
|
|
||||||
texture_container.append(&image_from);
|
|
||||||
let copy_texture_btn = gtk::Button::builder()
|
|
||||||
.label("Copy")
|
|
||||||
.valign(gtk::Align::Center)
|
|
||||||
.build();
|
|
||||||
copy_texture_btn.connect_clicked(clone!(
|
|
||||||
#[weak]
|
|
||||||
clipboard,
|
|
||||||
#[weak]
|
|
||||||
image_from,
|
|
||||||
move |_btn| {
|
|
||||||
let texture = image_from
|
|
||||||
.paintable()
|
|
||||||
.and_downcast::<gdk::Texture>()
|
|
||||||
.unwrap();
|
|
||||||
clipboard.set_texture(&texture);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
texture_container.append(©_texture_btn);
|
|
||||||
|
|
||||||
let image_into = gtk::Image::builder()
|
|
||||||
.pixel_size(96)
|
|
||||||
.icon_name("image-missing")
|
|
||||||
.build();
|
|
||||||
texture_container.append(&image_into);
|
|
||||||
let paste_texture_btn = gtk::Button::builder()
|
|
||||||
.label("Paste")
|
|
||||||
.valign(gtk::Align::Center)
|
|
||||||
.build();
|
|
||||||
paste_texture_btn.connect_clicked(clone!(
|
|
||||||
#[weak]
|
|
||||||
clipboard,
|
|
||||||
move |_btn| {
|
|
||||||
clipboard.read_texture_async(
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
clone!(
|
|
||||||
#[weak]
|
|
||||||
image_into,
|
|
||||||
move |res| {
|
|
||||||
if let Ok(Some(texture)) = res {
|
|
||||||
image_into.set_paintable(Some(&texture));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
texture_container.append(&paste_texture_btn);
|
|
||||||
container.append(&texture_container);
|
|
||||||
|
|
||||||
window.set_child(Some(&container));
|
|
||||||
window.present();
|
|
||||||
}
|
|
45
src/clock.rs
45
src/clock.rs
@ -1,45 +0,0 @@
|
|||||||
// Example copied from https://github.com/gtk-rs/gtk4-rs/blob/main/examples/clock/main.rs
|
|
||||||
|
|
||||||
use chrono::Local;
|
|
||||||
|
|
||||||
use gtk4 as gtk;
|
|
||||||
use gtk::{glib, prelude::*};
|
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
|
||||||
let application = gtk::Application::builder()
|
|
||||||
.application_id("com.github.gtk-rs.examples.clock")
|
|
||||||
.build();
|
|
||||||
application.connect_activate(build_ui);
|
|
||||||
application.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_ui(application: >k::Application) {
|
|
||||||
let window = gtk::ApplicationWindow::new(application);
|
|
||||||
|
|
||||||
window.set_title(Some("Clock Example"));
|
|
||||||
window.set_default_size(260, 40);
|
|
||||||
|
|
||||||
let time = current_time();
|
|
||||||
let label = gtk::Label::default();
|
|
||||||
label.set_text(&time);
|
|
||||||
|
|
||||||
window.set_child(Some(&label));
|
|
||||||
|
|
||||||
window.present();
|
|
||||||
|
|
||||||
// we are using a closure to capture the label (else we could also use a normal
|
|
||||||
// function)
|
|
||||||
let tick = move || {
|
|
||||||
let time = current_time();
|
|
||||||
label.set_text(&time);
|
|
||||||
// we could return glib::ControlFlow::Break to stop our clock after this tick
|
|
||||||
glib::ControlFlow::Continue
|
|
||||||
};
|
|
||||||
|
|
||||||
// executes the closure once every second
|
|
||||||
glib::timeout_add_seconds_local(1, tick);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_time() -> String {
|
|
||||||
format!("{}", Local::now().format("%Y-%m-%d %H:%M:%S"))
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
// Example copied from https://github.com/kashifsoofi/blog-code-samples/blob/gtk4-c-counter-app/gtk4-rust-counter-app/src/main.rs
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use gtk4 as gtk;
|
|
||||||
use gtk::glib::clone;
|
|
||||||
use gtk::prelude::*;
|
|
||||||
use gtk::{glib, Application, ApplicationWindow, Label, Box, Button, Orientation};
|
|
||||||
|
|
||||||
const APP_ID: &str = "org.gtk_rs.GTK4Counter";
|
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
|
||||||
// Create a new application
|
|
||||||
let app = Application::builder().application_id(APP_ID).build();
|
|
||||||
|
|
||||||
// Connect to "activate" signal of `app`
|
|
||||||
app.connect_activate(build_ui);
|
|
||||||
|
|
||||||
// Run the application
|
|
||||||
app.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_ui(app: &Application) {
|
|
||||||
let counter = Rc::new(Cell::new(0));
|
|
||||||
let label_counter = Label::builder()
|
|
||||||
.label(&counter.get().to_string())
|
|
||||||
.margin_top(12)
|
|
||||||
.margin_bottom(12)
|
|
||||||
.margin_start(12)
|
|
||||||
.margin_end(12)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let button_increase = Button::builder()
|
|
||||||
.label("Increase")
|
|
||||||
.margin_top(12)
|
|
||||||
.margin_bottom(12)
|
|
||||||
.margin_start(12)
|
|
||||||
.margin_end(12)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let button_decrease = Button::builder()
|
|
||||||
.label("Decrease")
|
|
||||||
.margin_top(12)
|
|
||||||
.margin_bottom(12)
|
|
||||||
.margin_start(12)
|
|
||||||
.margin_end(12)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
button_increase.connect_clicked(clone!(@weak counter, @weak label_counter =>
|
|
||||||
move |_| {
|
|
||||||
counter.set(counter.get() + 1);
|
|
||||||
label_counter.set_label(&counter.get().to_string());
|
|
||||||
}));
|
|
||||||
|
|
||||||
button_decrease.connect_clicked(clone!(@weak label_counter =>
|
|
||||||
move |_| {
|
|
||||||
counter.set(counter.get() - 1);
|
|
||||||
label_counter.set_label(&counter.get().to_string());
|
|
||||||
}));
|
|
||||||
|
|
||||||
let gtk_box = Box::builder()
|
|
||||||
.orientation(Orientation::Vertical)
|
|
||||||
.build();
|
|
||||||
gtk_box.append(&label_counter);
|
|
||||||
gtk_box.append(&button_increase);
|
|
||||||
gtk_box.append(&button_decrease);
|
|
||||||
|
|
||||||
// Create a window and set the title
|
|
||||||
let window = ApplicationWindow::builder()
|
|
||||||
.application(app)
|
|
||||||
.title("GTK Counter App")
|
|
||||||
.child(>k_box)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Present window
|
|
||||||
window.present();
|
|
||||||
}
|
|
22
src/custom_app/imp.rs
Normal file
22
src/custom_app/imp.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use gtk::glib;
|
||||||
|
use gtk::subclass::prelude::*;
|
||||||
|
use gtk4 as gtk;
|
||||||
|
|
||||||
|
// Object holding the state
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct CustomApp;
|
||||||
|
|
||||||
|
// The central trait for subclassing a GObject
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for CustomApp {
|
||||||
|
const NAME: &'static str = "MyGtkAppCustomApp";
|
||||||
|
type Type = super::CustomApp;
|
||||||
|
type ParentType = gtk::Application;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for CustomApp {}
|
||||||
|
|
||||||
|
impl ApplicationImpl for CustomApp {}
|
||||||
|
|
||||||
|
impl GtkApplicationImpl for CustomApp {}
|
||||||
|
|
44
src/custom_app/mod.rs
Normal file
44
src/custom_app/mod.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
mod imp;
|
||||||
|
|
||||||
|
use gtk::gio;
|
||||||
|
use gtk::glib;
|
||||||
|
use gtk::prelude::ApplicationExtManual;
|
||||||
|
use gtk4 as gtk;
|
||||||
|
use gtk4::prelude::ApplicationExt;
|
||||||
|
|
||||||
|
const APP_ID: &str = "de.privacy1st.dndbuster";
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct CustomApp(ObjectSubclass<imp::CustomApp>)
|
||||||
|
@extends gio::Application, gtk::Application,
|
||||||
|
@implements gio::ActionMap, gio::ActionGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomApp {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
glib::Object::builder()
|
||||||
|
.property("application-id", APP_ID)
|
||||||
|
.property("resource-base-path", "/io/github/seadve/Kooha/")
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&self) -> glib::ExitCode {
|
||||||
|
eprintln!("Kooha ({})", APP_ID);
|
||||||
|
eprintln!("Version: {} ({})", 0.1, "dev");
|
||||||
|
eprintln!("Datadir: {}", ".");
|
||||||
|
|
||||||
|
ApplicationExtManual::run(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_record_success_notification(&self) {
|
||||||
|
let notification = gio::Notification::new("Screencast recorded");
|
||||||
|
notification.set_body(Some("Yeeeeha!"));
|
||||||
|
self.send_notification(Some("record-success"), ¬ification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CustomApp {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
24
src/custom_button/imp.rs
Normal file
24
src/custom_button/imp.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use gtk::glib;
|
||||||
|
use gtk::subclass::prelude::*;
|
||||||
|
use gtk4 as gtk;
|
||||||
|
|
||||||
|
// Object holding the state
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct CustomButton;
|
||||||
|
|
||||||
|
// The central trait for subclassing a GObject
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for CustomButton {
|
||||||
|
const NAME: &'static str = "MyGtkAppCustomButton";
|
||||||
|
type Type = super::CustomButton;
|
||||||
|
type ParentType = gtk::Button;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trait shared by all GObjects
|
||||||
|
impl ObjectImpl for CustomButton {}
|
||||||
|
|
||||||
|
// Trait shared by all widgets
|
||||||
|
impl WidgetImpl for CustomButton {}
|
||||||
|
|
||||||
|
// Trait shared by all buttons
|
||||||
|
impl ButtonImpl for CustomButton {}
|
27
src/custom_button/mod.rs
Normal file
27
src/custom_button/mod.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
mod imp;
|
||||||
|
|
||||||
|
use glib::Object;
|
||||||
|
use gtk::glib;
|
||||||
|
use gtk4 as gtk;
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct CustomButton(ObjectSubclass<imp::CustomButton>)
|
||||||
|
@extends gtk::Button, gtk::Widget,
|
||||||
|
@implements gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomButton {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Object::builder().build()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_label(label: &str) -> Self {
|
||||||
|
Object::builder().property("label", label).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CustomButton {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
104
src/main.rs
104
src/main.rs
@ -1,106 +1,12 @@
|
|||||||
// Based on examples
|
mod custom_button;
|
||||||
// - https://crates.io/crates/gtk4
|
mod custom_app;
|
||||||
// - https://github.com/gtk-rs/gtk4-rs/blob/main/examples/clock/main.rs
|
|
||||||
// - https://github.com/gtk-rs/gtk4-rs/blob/main/examples/clipboard/main.rs
|
|
||||||
// - https://github.com/kashifsoofi/blog-code-samples/blob/gtk4-c-counter-app/gtk4-rust-counter-app/src/main.rs
|
|
||||||
|
|
||||||
use chrono::Local;
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use gtk::gio::{Notification, NotificationPriority};
|
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use gtk::glib::clone;
|
|
||||||
use gtk::prelude::*;
|
|
||||||
use gtk4 as gtk;
|
use gtk4 as gtk;
|
||||||
|
use crate::custom_app::CustomApp;
|
||||||
const APP_ID: &str = "de.privacy1st.pdt";
|
|
||||||
|
|
||||||
const DUR_MIN: f64 = 1.0;
|
|
||||||
const INTERVAL_SEC: u32 = 1;
|
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
fn main() -> glib::ExitCode {
|
||||||
let app = gtk::Application::builder().application_id(APP_ID).build();
|
let app = CustomApp::new();
|
||||||
app.connect_activate(move |app| build_ui(app));
|
app.send_record_success_notification().await;
|
||||||
app.run()
|
app.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_ui(app: >k::Application) {
|
|
||||||
let window = gtk::ApplicationWindow::builder()
|
|
||||||
.application(app)
|
|
||||||
.title("PleaseDisturbTimer")
|
|
||||||
.default_width(350)
|
|
||||||
.default_height(70)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let container = gtk::Box::builder()
|
|
||||||
.orientation(gtk::Orientation::Vertical)
|
|
||||||
.margin_top(24)
|
|
||||||
.margin_bottom(24)
|
|
||||||
.margin_start(24)
|
|
||||||
.margin_end(24)
|
|
||||||
.halign(gtk::Align::Center)
|
|
||||||
.valign(gtk::Align::Center)
|
|
||||||
.spacing(24)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// How to change variable using GTK4 Button? https://stackoverflow.com/a/76657798/6334421
|
|
||||||
let running = Rc::new(Cell::new(false));
|
|
||||||
|
|
||||||
let button_start = gtk::Button::with_label("Start");
|
|
||||||
button_start.connect_clicked(clone!(@strong running => move |_| {
|
|
||||||
running.set(true);
|
|
||||||
eprintln!("Timer started.");
|
|
||||||
}));
|
|
||||||
container.append(&button_start);
|
|
||||||
|
|
||||||
let button_stop = gtk::Button::with_label("Stop");
|
|
||||||
button_stop.connect_clicked(clone!(@strong running => move |_| {
|
|
||||||
running.set(false);
|
|
||||||
eprintln!("Timer stopped.");
|
|
||||||
}));
|
|
||||||
container.append(&button_stop);
|
|
||||||
|
|
||||||
let mut progress: f64 = 0.0;
|
|
||||||
let progress_bar = gtk::ProgressBar::new();
|
|
||||||
progress_bar.set_fraction(progress);
|
|
||||||
container.append(&progress_bar);
|
|
||||||
|
|
||||||
let time = current_time();
|
|
||||||
let label = gtk::Label::default();
|
|
||||||
label.set_text(&time);
|
|
||||||
// label.set_halign(gtk::Align::Center);
|
|
||||||
container.append(&label);
|
|
||||||
|
|
||||||
window.set_child(Some(&container));
|
|
||||||
window.present();
|
|
||||||
|
|
||||||
let tick = clone!(@strong app => move || {
|
|
||||||
if running.get() {
|
|
||||||
progress += ((INTERVAL_SEC as f64) / 60.0) / DUR_MIN;
|
|
||||||
progress_bar.set_fraction(progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
if progress > 1.0 {
|
|
||||||
eprintln!("Time over.");
|
|
||||||
|
|
||||||
// TODO: Notification does not show up
|
|
||||||
let notification = Notification::new("Alert");
|
|
||||||
notification.set_body(Some("Time is over"));
|
|
||||||
notification.set_priority(NotificationPriority::Urgent);
|
|
||||||
app.send_notification(Some(APP_ID), ¬ification);
|
|
||||||
}
|
|
||||||
|
|
||||||
let time = current_time();
|
|
||||||
label.set_text(&time);
|
|
||||||
// we could return glib::ControlFlow::Break to stop our clock after this tick
|
|
||||||
glib::ControlFlow::Continue
|
|
||||||
});
|
|
||||||
|
|
||||||
// executes the closure once every `INTERVAL_SEC` seconds
|
|
||||||
glib::timeout_add_seconds_local(INTERVAL_SEC, tick);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_time() -> String {
|
|
||||||
format!("{}", Local::now().format("%Y-%m-%d %H:%M:%S"))
|
|
||||||
}
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
use gtk4 as gtk;
|
|
||||||
use gtk::glib;
|
|
||||||
use gtk::prelude::*;
|
|
||||||
use gtk::gio::{Notification, NotificationPriority};
|
|
||||||
|
|
||||||
const APP_ID: &str = "de.privacy1st.pdt";
|
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
|
||||||
let app = gtk::Application::builder().application_id(APP_ID).build();
|
|
||||||
app.connect_activate(move |app| build_ui(app));
|
|
||||||
app.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_ui(app: >k::Application) {
|
|
||||||
let window = gtk::ApplicationWindow::builder()
|
|
||||||
.application(app)
|
|
||||||
.title("System Notification")
|
|
||||||
.default_width(350)
|
|
||||||
.default_height(70)
|
|
||||||
.build();
|
|
||||||
window.present();
|
|
||||||
|
|
||||||
// TODO: Notification does not show up
|
|
||||||
let notification = Notification::new("Alert");
|
|
||||||
notification.set_body(Some("Time is over"));
|
|
||||||
notification.set_priority(NotificationPriority::Urgent);
|
|
||||||
let notification_id = "pdt.timeout";
|
|
||||||
app.send_notification(Some(notification_id), ¬ification);
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user