Commit 7645055d authored by Dylan McCall's avatar Dylan McCall

Added Break Status panels to the settings application.

Moved some frequently-used dbus names and object paths to constants defined in IBreakHelper.vala.
parent 68ada347
......@@ -38,3 +38,4 @@ config.log
config.status
libtool
stamp-h1
./libgd
......@@ -15,6 +15,10 @@
* along with Brain Break. If not, see <http://www.gnu.org/licenses/>.
*/
public const string HELPER_BUS_NAME = "org.brainbreak.Helper";
public const string HELPER_OBJECT_PATH = "/org/brainbreak/Helper";
public const string HELPER_BREAK_OBJECT_BASE_PATH = "/org/brainbreak/Breaks/";
[DBus (name = "org.brainbreak.Helper")]
public interface IBreakHelper : Object {
public abstract string[] get_break_ids() throws IOError;
......@@ -29,6 +33,7 @@ public interface IBreakHelper_TimerBreak : Object {
}
public struct TimerBreakStatus {
bool is_enabled;
bool is_active;
int starts_in;
int time_remaining;
......
......@@ -53,10 +53,13 @@ public class SessionStatus : Object {
private void sceensaver_appeared() {
try {
this.screensaver = Bus.get_proxy_sync(BusType.SESSION, "org.gnome.ScreenSaver", "/org/gnome/ScreenSaver");
this.screensaver = Bus.get_proxy_sync(
BusType.SESSION,
"org.gnome.ScreenSaver",
"/org/gnome/ScreenSaver"
);
this.screensaver.active_changed.connect(this.screensaver_active_changed_cb);
this.screensaver_is_active = this.screensaver.get_active();
} catch (IOError error) {
this.screensaver = null;
GLib.warning("Error connecting to screensaver service: %s", error.message);
......
......@@ -28,10 +28,12 @@ public abstract class TimerBreakType : BreakType {
this.break_type_server = new BreakHelper_TimerBreakServer(
(TimerBreakController)this.break_controller
);
string object_path = "/org/brainbreak/Breaks/%s".printf(this.id);
try {
DBusConnection connection = Bus.get_sync(BusType.SESSION, null);
connection.register_object (object_path, break_type_server);
connection.register_object(
HELPER_BREAK_OBJECT_BASE_PATH+this.id,
this.break_type_server
);
} catch (IOError error) {
GLib.error("Error registering break type on the session bus: %s", error.message);
}
......@@ -40,8 +42,6 @@ public abstract class TimerBreakType : BreakType {
[DBus (name = "org.brainbreak.Breaks.TimerBreak")]
private class BreakHelper_TimerBreakServer : Object, IBreakHelper_TimerBreak {
// FIXME: this used to implement IBreakHelper, but currently
// it does not due to a problem detected by Debian's build log filter.
private TimerBreakController break_controller;
public BreakHelper_TimerBreakServer(TimerBreakController break_controller) {
......@@ -50,6 +50,7 @@ private class BreakHelper_TimerBreakServer : Object, IBreakHelper_TimerBreak {
public TimerBreakStatus get_status() {
return TimerBreakStatus() {
is_enabled = this.break_controller.is_enabled(),
is_active = this.break_controller.is_active(),
starts_in = this.break_controller.starts_in(),
time_remaining = this.break_controller.get_time_remaining(),
......
......@@ -16,7 +16,7 @@
*/
public class Application : Gtk.Application {
const string app_id = "org.brainbreak.Helper";
const string app_id = HELPER_BUS_NAME;
const string app_name = _("Brain Break");
/* FIXME: font-size should have units, but we can only do that with GTK 3.8 and later */
......@@ -93,7 +93,10 @@ public class Application : Gtk.Application {
try {
DBusConnection connection = Bus.get_sync(BusType.SESSION, null);
connection.register_object ("/org/brainbreak/Helper", this.break_helper_server);
connection.register_object(
HELPER_OBJECT_PATH,
this.break_helper_server
);
} catch (IOError error) {
GLib.error("Error registering helper on the session bus: %s", error.message);
}
......
......@@ -36,7 +36,7 @@ public class ApplicationPanel : Gtk.Grid {
this.show();
Bus.watch_name(BusType.SESSION, "org.brainbreak.Helper", BusNameWatcherFlags.NONE,
Bus.watch_name(BusType.SESSION, HELPER_BUS_NAME, BusNameWatcherFlags.NONE,
this.break_helper_appeared, this.break_helper_disappeared);
this.settings.bind("master-enabled", this, "master-enabled", SettingsBindFlags.DEFAULT);
......
......@@ -24,6 +24,10 @@ public abstract class BreakType : Object {
this.id = id;
this.settings = settings;
}
public bool is_enabled() {
return this.settings.get_boolean("enabled");
}
public abstract Gtk.Widget get_status_panel();
public abstract Gtk.Widget get_settings_panel();
......
/*
* This file is part of Brain Break.
*
* Brain Break is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Brain Break is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Brain Break. If not, see <http://www.gnu.org/licenses/>.
*/
public class MainWindow : Gtk.ApplicationWindow {
private Settings settings;
private SettingsDialog settings_dialog;
private Gtk.Grid breaks_grid;
public MainWindow(Application application) {
Object(application: application);
this.settings = new Settings("org.brainbreak.breaks");
this.set_title(_("Break Timer"));
this.set_hide_titlebar_when_maximized(true);
this.settings_dialog = new SettingsDialog(application);
this.settings_dialog.set_modal(true);
this.settings_dialog.set_transient_for(this);
Gtk.Grid content = new Gtk.Grid();
this.add(content);
content.set_orientation(Gtk.Orientation.VERTICAL);
Gd.HeaderBar header = new Gd.HeaderBar();
content.add(header);
header.set_hexpand(true);
header.set_title("Break Timer");
Gtk.Switch master_switch = new Gtk.Switch();
header.pack_start(master_switch);
this.settings.bind("master-enabled", master_switch, "active", SettingsBindFlags.DEFAULT);
Gtk.Button settings_button = new Gtk.Button();
header.pack_end(settings_button);
settings_button.clicked.connect(this.settings_clicked_cb);
// FIXME: This icon is not semantically correct. (Wrong category, especially).
settings_button.set_image(new Gtk.Image.from_icon_name(
"preferences-system-symbolic",
Gtk.IconSize.SMALL_TOOLBAR)
);
settings_button.set_always_show_image(true);
this.breaks_grid = new Gtk.Grid();
content.add(this.breaks_grid);
this.breaks_grid.set_orientation(Gtk.Orientation.VERTICAL);
this.breaks_grid.set_row_spacing(36);
this.breaks_grid.margin = 12;
this.breaks_grid.set_vexpand(true);
this.breaks_grid.set_halign(Gtk.Align.CENTER);
this.breaks_grid.set_valign(Gtk.Align.CENTER);
foreach (BreakType break_type in application.breaks) {
this.add_break_type(break_type);
}
content.show_all();
}
public void show_about_dialog() {
Gtk.show_about_dialog(this,
"program-name", _("Brain Break"),
"comments", _("Computer break reminders for active minds"),
"copyright", _("Copyright © Dylan McCall"),
"website", "http://launchpad.net/brainbreak",
"website-label", _("Brain Break Website")
);
}
private void add_break_type(BreakType break_type) {
// Get break_type info panel and put it in this window
Gtk.Widget status_panel = break_type.get_status_panel();
this.breaks_grid.add(status_panel);
break_type.notify["enabled"].connect((s, p) => {
this.on_break_disabled();
});
this.on_break_disabled();
}
private void settings_clicked_cb() {
this.settings_dialog.show();
}
private void on_break_disabled() {
/*
bool any_enabled = false;
foreach (BreakType break_type in this.break_types.values) {
if (break_type.enabled) any_enabled = true;
}
this.application_panel.master_enabled = any_enabled;
*/
}
private void launch_helper() {
AppInfo helper_app_info = new DesktopAppInfo("brainbreak.desktop");
AppLaunchContext app_launch_context = new AppLaunchContext();
try {
helper_app_info.launch(null, app_launch_context);
} catch (Error error) {
stderr.printf("Error launching brainbreak helper: %s\n", error.message);
}
}
}
......@@ -20,6 +20,7 @@ brainbreak_settings_SOURCES = \
SettingsPanel.vala \
TimeChooser.vala \
TimerBreakSettingsPanel.vala \
TimerBreakStatusPanel.vala \
TimerBreakType.vala
brainbreak_settings_VALAFLAGS = $(BRAINBREAK_VALAFLAGS) \
......
......@@ -22,19 +22,33 @@ public class MicroBreakType : TimerBreakType {
this.interval_options = {240, 360, 480, 600};
this.duration_options = {15, 20, 25, 30, 45};
}
public override Gtk.Widget get_status_panel() {
var panel = new Gtk.Grid();
var label = new Gtk.Label("Micro Break");
panel.add(label);
panel.show_all();
return panel;
return new MicroBreakStatusPanel(this);
}
public override Gtk.Widget get_settings_panel() {
return new TimerBreakSettingsPanel(
this,
return new MicroBreakSettingsPanel(this);
}
}
class MicroBreakStatusPanel : TimerBreakStatusPanel {
public MicroBreakStatusPanel(MicroBreakType break_type) {
base(
break_type,
_("Your next microbreak is in"),
_("It's time for a microbreak")
);
}
}
class MicroBreakSettingsPanel : TimerBreakSettingsPanel {
public MicroBreakSettingsPanel(MicroBreakType break_type) {
base(
break_type,
_("Micro Break"),
_("Pause frequently to relax your eyes")
);
......
......@@ -25,16 +25,28 @@ public class RestBreakType : TimerBreakType {
}
public override Gtk.Widget get_status_panel() {
var panel = new Gtk.Grid();
var label = new Gtk.Label("Rest Break");
panel.add(label);
panel.show_all();
return panel;
return new RestBreakStatusPanel(this);
}
public override Gtk.Widget get_settings_panel() {
return new TimerBreakSettingsPanel(
this,
return new RestBreakSettingsPanel(this);
}
}
class RestBreakStatusPanel : TimerBreakStatusPanel {
public RestBreakStatusPanel(RestBreakType break_type) {
base(
break_type,
_("Your next full break is in"),
_("It's break time")
);
}
}
class RestBreakSettingsPanel : TimerBreakSettingsPanel {
public RestBreakSettingsPanel(RestBreakType break_type) {
base(
break_type,
_("Rest Break"),
_("And take some longer breaks to stretch your legs")
);
......
/*
* This file is part of Brain Break.
*
* Brain Break is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Brain Break is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Brain Break. If not, see <http://www.gnu.org/licenses/>.
*/
class TimerBreakStatusPanel : Gtk.Grid {
private TimerBreakType break_type;
private IBreakHelper_TimerBreak? break_server {public get; private set;}
private string upcoming_text;
private string ongoing_text;
private Gtk.Image time_icon;
private Gtk.Label status_label;
private Gtk.Label time_label;
private uint update_timeout_id;
public TimerBreakStatusPanel(TimerBreakType break_type, string upcoming_text, string ongoing_text) {
Object();
this.break_type = break_type;
this.upcoming_text = upcoming_text;
this.ongoing_text = ongoing_text;
this.set_column_spacing(12);
this.set_row_spacing(10);
this.get_style_context().add_class("_break-status");
// FIXME: This is an application icon. It doesn't make sense here.
this.time_icon = new Gtk.Image.from_icon_name(
"preferences-system-time-symbolic",
Gtk.IconSize.DIALOG
);
this.attach(this.time_icon, 0, 0, 1, 2);
this.time_icon.set_pixel_size(90);
this.time_icon.get_style_context().add_class("_break-status-icon");
this.status_label = new Gtk.Label(null);
this.attach(this.status_label, 1, 0, 1, 1);
this.status_label.set_width_chars(25);
this.time_label = new Gtk.Label(null);
this.attach(this.time_label, 1, 1, 1, 1);
this.time_label.set_width_chars(25);
Bus.watch_name(BusType.SESSION, HELPER_BUS_NAME, BusNameWatcherFlags.NONE,
this.breakhelper_appeared, this.breakhelper_disappeared);
}
private void show_status(TimerBreakStatus? status) {
if (status != null && status.is_enabled) {
this.show();
if (status.is_active) {
// TODO: Instead of this, explain the current break. Implement
// the "What should I do?" button from the mockup, seen at
// https://raw.github.com/gnome-design-team/gnome-mockups/master/break-timer/wires-notifications.png
this.status_label.set_label(this.ongoing_text);
string time_text = NaturalTime.instance.get_countdown_for_seconds_with_start(
status.time_remaining, status.current_duration);
this.time_label.set_label(time_text);
} else {
this.status_label.set_label(this.upcoming_text);
string time_text = NaturalTime.instance.get_countdown_for_seconds(status.starts_in);
this.time_label.set_label(time_text);
}
} else {
this.hide();
}
}
private bool update_status_cb() {
TimerBreakStatus? status = this.get_status();
this.show_status(status);
return true;
}
private TimerBreakStatus? get_status() {
if (this.break_server != null) {
try {
return this.break_server.get_status();
} catch (IOError error) {
GLib.warning("Error getting break status: %s", error.message);
return null;
}
} else {
return null;
}
}
private void breakhelper_appeared() {
try {
this.break_server = Bus.get_proxy_sync(
BusType.SESSION,
HELPER_BUS_NAME,
HELPER_BREAK_OBJECT_BASE_PATH+this.break_type.id
);
//this.break_server.active_changed.connect(this.screensaver_active_changed_cb);
this.update_timeout_id = Timeout.add(1, this.update_status_cb);
this.update_status_cb();
} catch (IOError error) {
this.break_server = null;
GLib.warning("Error connecting to break helper service: %s", error.message);
}
}
private void breakhelper_disappeared() {
if (this.update_timeout_id > 0) {
Source.remove(this.update_timeout_id);
this.update_timeout_id = 0;
}
this.break_server = null;
}
}
\ No newline at end of file
......@@ -16,11 +16,17 @@
*/
public abstract class TimerBreakType : BreakType {
public int interval {get; protected set;}
public int duration {get; protected set;}
public int[] interval_options;
public int[] duration_options;
public TimerBreakType(string name, Settings settings) {
base(name, settings);
settings.bind("interval-seconds", this, "interval", SettingsBindFlags.GET);
settings.bind("duration-seconds", this, "duration", SettingsBindFlags.GET);
}
}
......@@ -22,6 +22,14 @@ public class Application : Gtk.Application {
GtkLabel._settings-title {
font-weight:bold;
}
._break-status {
font-size: 12;
}
._break-status-icon {
opacity: 0.2;
}
""";
public BreakType[] breaks {public get; private set;}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment