diff --git a/data/com.github.artemanufrij.webpin.appdata.xml b/data/com.github.artemanufrij.webpin.appdata.xml index a7b87f0..fda1276 100644 --- a/data/com.github.artemanufrij.webpin.appdata.xml +++ b/data/com.github.artemanufrij.webpin.appdata.xml @@ -32,6 +32,14 @@ + + +

New:

+
    +
  • Option for Dark Theme
  • +
+
+

Fix:

diff --git a/schemas/com.github.artemanufrij.webpin.gschema.xml b/schemas/com.github.artemanufrij.webpin.gschema.xml index 44cfdcd..4576dd6 100644 --- a/schemas/com.github.artemanufrij.webpin.gschema.xml +++ b/schemas/com.github.artemanufrij.webpin.gschema.xml @@ -20,5 +20,10 @@ The saved state of the window. The saved state of the window. + + false + Use Dark Theme. + Use Dark Theme. + diff --git a/src/Application.vala b/src/Application.vala index 1a2023a..468ab18 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -27,7 +27,7 @@ */ namespace Webpin { - public class WebpinApp : Granite.Application { + public class WebpinApp : Gtk.Application { static WebpinApp _instance = null; @@ -40,16 +40,12 @@ namespace Webpin { } construct { - program_name = "Webpin"; - exec_name = "com.github.artemanufrij.webpin"; - app_launcher = application_id + ".desktop"; flags |= GLib.ApplicationFlags.HANDLES_OPEN; var open_web_app = new SimpleAction ("open-web-app", GLib.VariantType.STRING); add_action (open_web_app); open_web_app.activate.connect ((parameter) => { if (parameter != null) { - debug ("start web app over action: '%s'", parameter.get_string ()); start_webapp (parameter.get_string ()); } }); @@ -63,7 +59,7 @@ namespace Webpin { return; } mainwindow = new MainWindow (); - mainwindow.set_application(this); + mainwindow.set_application (this); } public override void open (File[] files, string hint) { @@ -75,13 +71,14 @@ namespace Webpin { mainwindow.present (); return; } - var app_info = Webpin.DesktopFile.get_app_by_url (url); - var desktop_file = new Webpin.DesktopFile.from_desktopappinfo(app_info); + var app_info = Services.DesktopFilesManager.get_app_by_url (url); + var desktop_file = new Webpin.DesktopFile.from_desktopappinfo (app_info); mainwindow = new WebWindow (desktop_file); mainwindow.set_application (this); } } } + static int main (string[] args) { Gtk.init (ref args); var app = Webpin.WebpinApp.instance; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 62d9098..26b049c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,9 +4,9 @@ vala_precompile(VALA_C ${CMAKE_PROJECT_NAME} Widgets/Assistant.vala Widgets/WebApp.vala Objects/DesktopFile.vala - Dialogs/InfoDialog.vala + Dialogs/Preferences.vala + Services/DesktopFilesManager.vala Settings.vala - UrlEntry.vala MainWindow.vala WebWindow.vala Application.vala diff --git a/src/Dialogs/InfoDialog.vala b/src/Dialogs/InfoDialog.vala deleted file mode 100644 index 596ae38..0000000 --- a/src/Dialogs/InfoDialog.vala +++ /dev/null @@ -1,47 +0,0 @@ -/*- - * Copyright (c) 2015 Erasmo Marín - * Copyright (c) 2017-2017 Artem Anufrij - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - * The Noise authors hereby grant permission for non-GPL compatible - * GStreamer plugins to be used and distributed together with GStreamer - * and Noise. This permission is above and beyond the permissions granted - * by the GPL license by which Noise is covered. If you modify this code - * you may extend this exception to your version of the code, but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. - * - * Authored by: Artem Anufrij - */ - -namespace Webpin { - public class InfoDialog : Gtk.Dialog { - public InfoDialog (string title, string label, string icon_name) { - - this.title = title; - set_default_size (350, 100); - - var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 5); - box.pack_start (new Gtk.Image.from_icon_name(icon_name, Gtk.IconSize.DIALOG), false, false, 0); - box.pack_start (new Gtk.Label (label), true, false, 0); - box.margin = 15; - - Gtk.Box content = get_content_area () as Gtk.Box; - content.pack_start (box, true, true, 0); - - add_button (_("Accept"), Gtk.ResponseType.ACCEPT); - } - } -} diff --git a/src/Dialogs/Preferences.vala b/src/Dialogs/Preferences.vala new file mode 100644 index 0000000..81b77e6 --- /dev/null +++ b/src/Dialogs/Preferences.vala @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2017 Artem Anufrij + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * The Noise authors hereby grant permission for non-GPL compatible + * GStreamer plugins to be used and distributed together with GStreamer + * and Noise. This permission is above and beyond the permissions granted + * by the GPL license by which Noise is covered. If you modify this code + * you may extend this exception to your version of the code, but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. + * + * Authored by: Artem Anufrij + */ + +namespace Webpin.Dialogs { + public class Preferences : Gtk.Dialog { + Webpin.Settings settings; + + construct { + settings = Webpin.Settings.get_default (); + } + + public Preferences (Gtk.Window parent) { + Object ( + transient_for: parent + ); + build_ui (); + + this.response.connect ((source, response_id) => { + switch (response_id) { + case Gtk.ResponseType.CLOSE: + destroy (); + break; + } + }); + } + + private void build_ui () { + this.resizable = false; + var content = get_content_area () as Gtk.Box; + + var grid = new Gtk.Grid (); + grid.column_spacing = 12; + grid.row_spacing = 12; + grid.margin = 12; + + var use_dark_theme_label = new Gtk.Label (_("Use Dark Theme")); + use_dark_theme_label.halign = Gtk.Align.START; + var use_dark_theme = new Gtk.Switch (); + use_dark_theme.active = settings.use_dark_theme; + use_dark_theme.notify["active"].connect (() => { + settings.use_dark_theme = use_dark_theme.active; + }); + + grid.attach (use_dark_theme_label, 0, 0); + grid.attach (use_dark_theme, 1, 0); + + content.pack_start (grid, false, false, 0); + + this.add_button ("_Close", Gtk.ResponseType.CLOSE); + this.show_all (); + } + } +} diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 687ccc5..89368a1 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -28,23 +28,35 @@ namespace Webpin { public class MainWindow : Gtk.ApplicationWindow { - private Settings settings; + Settings settings; - private Gtk.Stack stack; - private Gtk.HeaderBar headerbar; - private Gtk.Button back_button; - private Gtk.Button add_button; + Gtk.Stack stack; + Gtk.HeaderBar headerbar; + Gtk.Button back_button; + Gtk.Button add_button; + Gtk.MenuButton app_menu; - private Assistant assistant; - private ApplicationsView apps_view; + Assistant assistant; + ApplicationsView apps_view; + + construct { + settings = Settings.get_default (); + settings.notify["use-dark-theme"].connect (() => { + Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = settings.use_dark_theme; + if (settings.use_dark_theme) { + app_menu.set_image (new Gtk.Image.from_icon_name ("open-menu-symbolic", Gtk.IconSize.LARGE_TOOLBAR)); + } else { + app_menu.set_image (new Gtk.Image.from_icon_name ("open-menu", Gtk.IconSize.LARGE_TOOLBAR)); + } + }); + } public MainWindow () { - settings = Settings.get_default (); - build_ui (); } private void build_ui () { + Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = settings.use_dark_theme; set_default_size (700, 500); //headerbar @@ -55,6 +67,7 @@ namespace Webpin { back_button = new Gtk.Button.with_label (_("Applications")); back_button.get_style_context ().add_class ("back-button"); + back_button.valign = Gtk.Align.CENTER; headerbar.pack_start (back_button); add_button = new Gtk.Button (); @@ -62,6 +75,27 @@ namespace Webpin { add_button.tooltip_text = _("Add a new Web App"); headerbar.pack_start (add_button); + // SETTINGS MENU + app_menu = new Gtk.MenuButton (); + if (settings.use_dark_theme) { + app_menu.set_image (new Gtk.Image.from_icon_name ("open-menu-symbolic", Gtk.IconSize.LARGE_TOOLBAR)); + } else { + app_menu.set_image (new Gtk.Image.from_icon_name ("open-menu", Gtk.IconSize.LARGE_TOOLBAR)); + } + + var settings_menu = new Gtk.Menu (); + var menu_item_preferences = new Gtk.MenuItem.with_label (_("Preferences")); + menu_item_preferences.activate.connect (() => { + var preferences = new Dialogs.Preferences (this); + preferences.run (); + }); + + settings_menu.append (menu_item_preferences); + settings_menu.show_all (); + + app_menu.popup = settings_menu; + headerbar.pack_end (app_menu); + var welcome = new Granite.Widgets.Welcome (_("No Web Apps Available"), _("Manage your web apps.")); welcome.append ("document-new", _("Create App"), _("Create a new web app with Webpin")); welcome.activated.connect ((index) => { @@ -109,10 +143,11 @@ namespace Webpin { }); back_button.clicked.connect (() => { - if (apps_view.has_items) + if (apps_view.has_items) { show_apps_view (); - else + } else { show_welcome_view (); + } }); add_button.clicked.connect (() => { @@ -127,10 +162,11 @@ namespace Webpin { this.restore_settings (); show_all (); - if (apps_view.has_items) + if (apps_view.has_items) { show_apps_view (Gtk.StackTransitionType.NONE); - else + } else { show_welcome_view (Gtk.StackTransitionType.NONE); + } this.present (); } @@ -140,11 +176,7 @@ namespace Webpin { stack.set_visible_child_name("assistant"); back_button.show_all (); add_button.hide (); - //fix ugly border at the bottom of headerbar - queue_draw (); - - if (desktop_file != null) - assistant.edit_desktop_file (desktop_file); + assistant.edit_desktop_file (desktop_file); } private void show_apps_view (Gtk.StackTransitionType slide = Gtk.StackTransitionType.SLIDE_RIGHT) { @@ -153,8 +185,6 @@ namespace Webpin { back_button.hide (); add_button.show_all (); assistant.reset_fields (); - //fix ugly border at the bottom of headerbar - queue_draw (); } private void show_welcome_view (Gtk.StackTransitionType slide = Gtk.StackTransitionType.SLIDE_RIGHT) { @@ -163,15 +193,14 @@ namespace Webpin { back_button.hide (); add_button.hide (); assistant.reset_fields (); - //fix ugly border at the bottom of headerbar - queue_draw (); } private void restore_settings () { this.set_default_size (settings.window_width, settings.window_height); - if (settings.window_state == Settings.WindowState.MAXIMIZED) + if (settings.window_state == Settings.WindowState.MAXIMIZED) { this.maximize (); + } } private void store_settings () { diff --git a/src/Objects/DesktopFile.vala b/src/Objects/DesktopFile.vala index 091c941..ff0094d 100644 --- a/src/Objects/DesktopFile.vala +++ b/src/Objects/DesktopFile.vala @@ -29,7 +29,7 @@ namespace Webpin { public class DesktopFile : GLib.Object { - private string template = """ + string template = """ [Desktop Entry] Name=Webpin GenericName=Web app @@ -42,9 +42,10 @@ namespace Webpin { Categories=Network; X-GNOME-FullName=webpin StartupWMClass=Webpin - WebpinThemeColor=none"""; + X-Webpin-PrimaryColor=none"""; + + GLib.KeyFile file; - private GLib.KeyFile file; public DesktopAppInfo info { get; set; } public string name { get; private set; } @@ -52,12 +53,11 @@ namespace Webpin { public string icon { get; private set; } public bool hide_on_close { get { - this.file = new GLib.KeyFile(); try { file.load_from_file (info.filename, KeyFileFlags.NONE); return file.get_string ("Desktop Entry", "X-Webpin-StayOpen") == "true"; - } catch (Error e) { - warning (e.message); + } catch (Error err) { + warning (err.message); } return false; } @@ -67,16 +67,15 @@ namespace Webpin { public Gdk.RGBA? color { get { if (_color == null) { - Gdk.RGBA return_value = {0, 0, 0, 0}; - this.file = new GLib.KeyFile(); + Gdk.RGBA return_value = {0, 0, 0, 1}; try { file.load_from_file (info.filename, KeyFileFlags.NONE); var property = file.get_string ("Desktop Entry", "X-Webpin-PrimaryColor"); if (property == "" || !return_value.parse (property)) { return null; } - } catch (Error e) { - warning (e.message); + } catch (Error err) { + warning (err.message); return null; } _color = return_value; @@ -85,8 +84,10 @@ namespace Webpin { } set { if (value != null) { _color = value; - var color = "rgba (%d,%d,%d,1)".printf ((int)(value.red * 255), (int)(value.green * 255), (int)(value.blue * 255)); - edit_propertie ("X-Webpin-PrimaryColor", color); + var color = "rgba(%d,%d,%d,1)".printf ((int)(value.red * 255), (int)(value.green * 255), (int)(value.blue * 255)); + edit_property ("X-Webpin-PrimaryColor", color); + } else { + edit_property ("X-Webpin-PrimaryColor", "none"); } } } @@ -99,10 +100,10 @@ namespace Webpin { file = new GLib.KeyFile(); try { file.load_from_data (template, -1, GLib.KeyFileFlags.NONE); - } catch (Error e) { - warning (e.message); + } catch (Error err) { + warning (err.message); } - //TODO: Category + file.set_string ("Desktop Entry", "Name", name); file.set_string ("Desktop Entry", "GenericName", name); file.set_string ("Desktop Entry", "X-GNOME-FullName", name); @@ -112,35 +113,33 @@ namespace Webpin { file.set_string ("Desktop Entry", "X-Webpin-StayOpen", stay_open.to_string ()); } - public DesktopFile.from_desktopappinfo(GLib.DesktopAppInfo info) { + public DesktopFile.from_desktopappinfo (GLib.DesktopAppInfo info) { this.info = info; this.file = new GLib.KeyFile(); try { file.load_from_file (info.filename, KeyFileFlags.NONE); - } catch (Error e) { - warning (e.message); + } catch (Error err) { + warning (err.message); } this.name = info.get_display_name (); this.icon = info.get_icon ().to_string (); try { this.url = file.get_string ("Desktop Entry", "Exec").substring (31); - } catch (Error e) { - warning (e.message); + } catch (Error err) { + warning (err.message); } } - - - public bool edit_propertie (string propertie, string val) { + public bool edit_property (string propertie, string val) { bool return_value = false; try { - string filename = GLib.Environment.get_user_data_dir () + "/applications/" + file.get_string("Desktop Entry", "Name") + "-webpin.desktop"; - file = new GLib.KeyFile(); + string filename = GLib.Environment.get_user_data_dir () + "/applications/" + file.get_string ("Desktop Entry", "Name") + "-webpin.desktop"; + file = new GLib.KeyFile (); file.load_from_file (filename, KeyFileFlags.NONE); file.set_string ("Desktop Entry", propertie, val); return_value = file.save_to_file (filename); - } catch (Error e) { - warning (e.message); + } catch (Error err) { + warning (err.message); } return return_value; @@ -149,76 +148,25 @@ namespace Webpin { public GLib.DesktopAppInfo save_to_file () { GLib.DesktopAppInfo return_value = null; try { - string filename = GLib.Environment.get_user_data_dir () + "/applications/" +file.get_string("Desktop Entry", "Name") + "-webpin.desktop"; - print("Desktop file created: " + filename); + string filename = GLib.Environment.get_user_data_dir () + "/applications/" +file.get_string ("Desktop Entry", "Name") + "-webpin.desktop"; file.save_to_file (filename); return_value = new GLib.DesktopAppInfo.from_filename (filename); - } catch (Error e) { - warning (e.message); + } catch (Error err) { + warning (err.message); } return return_value; } public bool delete_file () { try { - string filename = GLib.Environment.get_user_data_dir () + "/applications/" +file.get_string("Desktop Entry", "Name") + "-webpin.desktop"; + string filename = GLib.Environment.get_user_data_dir () + "/applications/" +file.get_string ("Desktop Entry", "Name") + "-webpin.desktop"; File file = File.new_for_path (filename); file.delete (); - } catch (Error e) { - print(e.message + "\n"); + } catch (Error err) { + warning (err.message); return false; } return true; } - - public static Gee.HashMap get_webpin_applications () { - - var list = new Gee.HashMap(); - - foreach (GLib.AppInfo app in GLib.AppInfo.get_all()) { - - var desktop_app = new GLib.DesktopAppInfo(app.get_id ()); - - //FIXME: This is not working, vala problem? - //var keywords = desktop_app.get_keywords (); - - string keywords = desktop_app.get_string ("Keywords"); - - if (keywords != null && keywords.contains ("webpin")) { - debug (desktop_app.get_name()); - list.set(desktop_app.get_name(), desktop_app); - } - } - return list; - } - - public static GLib.DesktopAppInfo? get_app_by_url (string url) { - foreach (GLib.AppInfo app in GLib.AppInfo.get_all()) { - - var desktop_app = new GLib.DesktopAppInfo(app.get_id ()); - - var exec = desktop_app.get_string ("Exec"); - - if (exec != null) { - exec = exec.replace ("%%", "%"); - if (exec.contains (url)) { - return desktop_app; - } - } - } - return null; - } - - public static Gee.HashMap get_applications() { - - var list = new Gee.HashMap(); - - foreach (GLib.AppInfo app in GLib.AppInfo.get_all()) { - debug (app.get_name()); - list.set(app.get_name(), app); - } - - return list; - } } } diff --git a/src/Services/DesktopFilesManager.vala b/src/Services/DesktopFilesManager.vala new file mode 100644 index 0000000..8d4b4ee --- /dev/null +++ b/src/Services/DesktopFilesManager.vala @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2017-2017 Artem Anufrij + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * The Noise authors hereby grant permission for non-GPL compatible + * GStreamer plugins to be used and distributed together with GStreamer + * and Noise. This permission is above and beyond the permissions granted + * by the GPL license by which Noise is covered. If you modify this code + * you may extend this exception to your version of the code, but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. + * + * Authored by: Artem Anufrij + */ + +namespace Webpin.Services { + public class DesktopFilesManager { + public static GLib.DesktopAppInfo? get_app_by_url (string url) { + foreach (GLib.AppInfo app in GLib.AppInfo.get_all ()) { + var desktop_app = new GLib.DesktopAppInfo (app.get_id ()); + var exec = desktop_app.get_string ("Exec"); + if (exec != null) { + exec = exec.replace ("%%", "%"); + if (exec.contains (url)) { + return desktop_app; + } + } + } + return null; + } + + public static Gee.HashMap get_applications() { + var list = new Gee.HashMap(); + foreach (GLib.AppInfo app in GLib.AppInfo.get_all()) { + list.set(app.get_name(), app); + } + return list; + } + + public static Gee.HashMap get_webpin_applications () { + var list = new Gee.HashMap(); + + foreach (GLib.AppInfo app in GLib.AppInfo.get_all()) { + var desktop_app = new GLib.DesktopAppInfo(app.get_id ()); + + string keywords = desktop_app.get_string ("Keywords"); + if (keywords != null && keywords.contains ("webpin")) { + list.set(desktop_app.get_name(), desktop_app); + } + } + return list; + } + } +} diff --git a/src/Settings.vala b/src/Settings.vala index 2170de1..3fc760d 100644 --- a/src/Settings.vala +++ b/src/Settings.vala @@ -31,14 +31,15 @@ namespace Webpin { private static Settings settings; public static Settings get_default () { - if (settings == null) + if (settings == null) { settings = new Settings (); - + } return settings; } public int window_width { get; set; } public int window_height { get; set; } public WindowState window_state { get; set; } + public bool use_dark_theme { get; set; } private Settings () { base ("com.github.artemanufrij.webpin"); diff --git a/src/UrlEntry.vala b/src/UrlEntry.vala deleted file mode 100644 index c0fa3d8..0000000 --- a/src/UrlEntry.vala +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * Copyright (c) 2015 Erasmo Marín - * Copyright (c) 2017-2017 Artem Anufrij - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - * The Noise authors hereby grant permission for non-GPL compatible - * GStreamer plugins to be used and distributed together with GStreamer - * and Noise. This permission is above and beyond the permissions granted - * by the GPL license by which Noise is covered. If you modify this code - * you may extend this exception to your version of the code, but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. - * - * Authored by: Artem Anufrij - */ - -namespace Webpin { - public class UrlEntry : Gtk.Entry { - public UrlEntry () { - editable = false; - set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "view-refresh-symbolic"); - set_icon_from_icon_name (Gtk.EntryIconPosition.PRIMARY, "text-html-symbolic"); - } - public override void get_preferred_width (out int minimum_width, out int natural_width) { - minimum_width = -1; - natural_width = 3000; - } - } -} diff --git a/src/WebWindow.vala b/src/WebWindow.vala index f532380..dfb1550 100644 --- a/src/WebWindow.vala +++ b/src/WebWindow.vala @@ -29,37 +29,30 @@ namespace Webpin { public class WebWindow : Gtk.Window { - private bool is_full_screen = false; - - //widgets - private WebApp web_app; + Gdk.WindowState current_state; + WebApp web_app; Gtk.Spinner spinner; public DesktopFile desktop_file { get; private set; } public WebWindow (DesktopFile desktop_file) { this.desktop_file = desktop_file; + this.set_wmclass (desktop_file.url, desktop_file.url); this.events |= Gdk.EventMask.STRUCTURE_MASK; var color = desktop_file.color; if (color != null) { - var mid = color.red + color.blue + color.green; - if (mid / 3 < 0.5) { - Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = true; - } - Granite.Widgets.Utils.set_color_primary (this, color); + set_color (color); } - - set_wmclass (desktop_file.url, desktop_file.url); - web_app = new WebApp (desktop_file.url); + web_app = new WebApp (desktop_file); var headerbar = new Gtk.HeaderBar (); headerbar.title = desktop_file.name; headerbar.show_close_button = true; var copy_url = new Gtk.Button.from_icon_name ("insert-link-symbolic", Gtk.IconSize.MENU); - copy_url.tooltip_text = _("Copy URI into clipboard"); + copy_url.tooltip_text = _("Copy URL into clipboard"); copy_url.clicked.connect (() => { Gtk.Clipboard.get_default (Gdk.Display.get_default ()).set_text (web_app.app_view.uri, -1); }); @@ -74,40 +67,26 @@ namespace Webpin { stay_open.tooltip_text = _("Run in background when closed"); stay_open.image = new Gtk.Image.from_icon_name ("view-pin-symbolic", Gtk.IconSize.MENU); stay_open.toggled.connect (() => { - desktop_file.edit_propertie ("X-Webpin-StayOpen", stay_open.active.to_string ()); + desktop_file.edit_property ("X-Webpin-StayOpen", stay_open.active.to_string ()); desktop_file.save_to_file (); }); headerbar.pack_start (stay_open); this.set_titlebar (headerbar); - var width = desktop_file.info.get_string ("X-Webpin-WindowWidth"); - var height = desktop_file.info.get_string ("X-Webpin-WindowHeight"); - var state = desktop_file.info.get_string ("X-Webpin-WindowMaximized"); - var zoom = desktop_file.info.get_string ("X-Webpin-WindowZoom"); - - if (width != null && height != null) { - set_default_size (int.parse(width), int.parse(height)); - } else { - set_default_size (1000, 600); - } - - if (state != null && state == "max") { - this.maximize (); - } - - if (zoom != null) { - web_app.app_view.zoom_level = double.parse (zoom); - } - this.delete_event.connect (() => { - update_window_state(this.get_allocated_width (), this.get_allocated_height (), this.is_maximized); + save_settings (); if (desktop_file.hide_on_close) { this.hide_on_delete (); } return desktop_file.hide_on_close; }); + this.window_state_event.connect ((event) => { + current_state = event.new_window_state; + return false; + }); + web_app.external_request.connect ((action) => { debug ("Web app external request: %s", action.get_request ().uri); try { @@ -133,107 +112,122 @@ namespace Webpin { spinner.active = false; }); - add(web_app); - show_all(); + web_app.found_website_color.connect ((color) => { + int gray_val = (int)(desktop_file.color.red * 255); + if (desktop_file.color == null || (gray_val == 222 && desktop_file.color.red == desktop_file.color.green && desktop_file.color.red == desktop_file.color.blue)) { + set_color (color); + desktop_file.color = color; + } + }); + + this.add (web_app); + + load_settings (); + + this.show_all (); } - public new void fullscreen () { - is_full_screen = true; - base.fullscreen(); - } - - public new void unfullscreen () { - is_full_screen = false; - base.unfullscreen(); + private void set_color (Gdk.RGBA color) { + var mid = color.red + color.blue + color.green; + color.alpha = 1; + if (mid / 3 < 0.5) { + Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = true; + } + Granite.Widgets.Utils.set_color_primary (this, color); } public void toggle_fullscreen() { - if(is_full_screen) { - unfullscreen(); + if (current_state.to_string () == Gdk.WindowState.FULLSCREEN.to_string ()) { + this.unfullscreen (); + } else { + this.fullscreen (); } - else { - fullscreen(); - } - is_full_screen = !is_full_screen; } - public void update_window_state (int width, int height, bool is_maximized) { - var file = web_app.get_desktop_file(); + private void load_settings () { + var width = desktop_file.info.get_string ("X-Webpin-WindowWidth"); + var height = desktop_file.info.get_string ("X-Webpin-WindowHeight"); + var state = desktop_file.info.get_string ("X-Webpin-WindowMaximized"); + var zoom = desktop_file.info.get_string ("X-Webpin-WindowZoom"); - if (is_maximized) { - file.edit_propertie ("X-Webpin-WindowMaximized", "max"); + if (width != null && height != null) { + set_default_size (int.parse(width), int.parse(height)); } else { - file.edit_propertie ("X-Webpin-WindowWidth", width.to_string()); - file.edit_propertie ("X-Webpin-WindowHeight", height.to_string()); - file.edit_propertie ("X-Webpin-WindowMaximized", "norm"); + set_default_size (1000, 600); + } + + if (state != null && state == "max") { + this.maximize (); + } + + if (zoom != null) { + web_app.app_view.zoom_level = double.parse (zoom); + } + } + + private void save_settings () { + if (this.is_maximized) { + desktop_file.edit_property ("X-Webpin-WindowMaximized", "max"); + } else { + desktop_file.edit_property ("X-Webpin-WindowWidth", this.get_allocated_width ().to_string()); + desktop_file.edit_property ("X-Webpin-WindowHeight", this.get_allocated_height ().to_string()); + desktop_file.edit_property ("X-Webpin-WindowMaximized", "norm"); } } public override bool key_press_event (Gdk.EventKey event) { - bool handled = true; switch (event.keyval) { - case Gdk.Key.Escape: - unfullscreen(); - break; - case Gdk.Key.F11: - toggle_fullscreen(); - break; - case Gdk.Key.KP_Add: - case Gdk.Key.plus: - if (Gdk.ModifierType.CONTROL_MASK in event.state) { - web_app.app_view.zoom_level += 0.1; - web_app.get_desktop_file().edit_propertie ("X-Webpin-WindowZoom", web_app.app_view.zoom_level.to_string ()); - } else { - handled = false; - } - break; - case Gdk.Key.KP_Subtract: - case Gdk.Key.minus: - if (Gdk.ModifierType.CONTROL_MASK in event.state) { - web_app.app_view.zoom_level -= 0.1; - web_app.get_desktop_file().edit_propertie ("X-Webpin-WindowZoom", web_app.app_view.zoom_level.to_string ()); - } else { - handled = false; - } - break; - case Gdk.Key.KP_0: - case Gdk.Key.@0: - if (Gdk.ModifierType.CONTROL_MASK in event.state) { - web_app.app_view.zoom_level = 1; - web_app.get_desktop_file().edit_propertie ("X-Webpin-WindowZoom", web_app.app_view.zoom_level.to_string ()); - } else { - handled = false; - } - break; - case Gdk.Key.F5: - if (Gdk.ModifierType.CONTROL_MASK in event.state) { - web_app.app_view.reload (); - } else { - web_app.app_view.reload_bypass_cache (); - } - break; - case Gdk.Key.Left: - if (Gdk.ModifierType.MOD1_MASK in event.state) { - web_app.app_view.go_back (); - } else { - handled = false; - } - break; - case Gdk.Key.Right: - if (Gdk.ModifierType.MOD1_MASK in event.state) { - web_app.app_view.go_forward (); - } else { - handled = false; - } - break; - default: - handled = false; - break; + case Gdk.Key.Escape: + unfullscreen(); + break; + case Gdk.Key.F11: + toggle_fullscreen(); + break; + case Gdk.Key.KP_Add: + case Gdk.Key.plus: + if (Gdk.ModifierType.CONTROL_MASK in event.state) { + web_app.app_view.zoom_level += 0.1; + desktop_file.edit_property ("X-Webpin-WindowZoom", web_app.app_view.zoom_level.to_string ()); + return true; + } + break; + case Gdk.Key.KP_Subtract: + case Gdk.Key.minus: + if (Gdk.ModifierType.CONTROL_MASK in event.state) { + web_app.app_view.zoom_level -= 0.1; + desktop_file.edit_property ("X-Webpin-WindowZoom", web_app.app_view.zoom_level.to_string ()); + return true; + } + break; + case Gdk.Key.KP_0: + case Gdk.Key.@0: + if (Gdk.ModifierType.CONTROL_MASK in event.state) { + web_app.app_view.zoom_level = 1; + desktop_file.edit_property ("X-Webpin-WindowZoom", web_app.app_view.zoom_level.to_string ()); + return true; + } + break; + case Gdk.Key.F5: + if (Gdk.ModifierType.CONTROL_MASK in event.state) { + web_app.app_view.reload (); + } else { + web_app.app_view.reload_bypass_cache (); + } + return true; + case Gdk.Key.Left: + if (Gdk.ModifierType.MOD1_MASK in event.state) { + web_app.app_view.go_back (); + return true; + } + break; + case Gdk.Key.Right: + if (Gdk.ModifierType.MOD1_MASK in event.state) { + web_app.app_view.go_forward (); + return true; + } + break; } - if (handled) - return true; - return (base.key_press_event != null) ? base.key_press_event (event) : true; } } diff --git a/src/Widgets/ApplicationIcon.vala b/src/Widgets/ApplicationIcon.vala index 193e5aa..acbd2a8 100644 --- a/src/Widgets/ApplicationIcon.vala +++ b/src/Widgets/ApplicationIcon.vala @@ -75,8 +75,9 @@ namespace Webpin { }); event_box.leave_notify_event.connect ((event) => { - if (event.detail == Gdk.NotifyType.INFERIOR) + if (event.detail == Gdk.NotifyType.INFERIOR) { return false; + } menu.set_reveal_child (false); return false; }); @@ -109,10 +110,11 @@ namespace Webpin { new_height = new_height * pix.height / pix.width; margin_vertical = (new_width - new_height) / 2; } - if (image == null) + if (image == null) { image = new Gtk.Image.from_pixbuf (pix.scale_simple (new_width, new_height, Gdk.InterpType.BILINEAR)); - else + } else { image.set_from_pixbuf (pix.scale_simple (new_width, new_height, Gdk.InterpType.BILINEAR)); + } image.margin_top = margin_vertical; image.margin_bottom = margin_vertical; diff --git a/src/Widgets/ApplicationsView.vala b/src/Widgets/ApplicationsView.vala index 595c040..75edeae 100644 --- a/src/Widgets/ApplicationsView.vala +++ b/src/Widgets/ApplicationsView.vala @@ -33,8 +33,7 @@ namespace Webpin { public signal void edit_request(DesktopFile desktop_file); public signal void app_deleted (); - private Gtk.FlowBox icon_view; - private Gee.HashMap applications; + Gtk.FlowBox icon_view; public bool has_items { get { return icon_view.get_children ().length () > 0; } } @@ -56,20 +55,19 @@ namespace Webpin { var app_icon = (child as Gtk.FlowBoxChild).get_child () as ApplicationIcon; try { Process.spawn_command_line_async ("com.github.artemanufrij.webpin " + app_icon.desktop_file.url.replace("%%", "%")); - } catch (SpawnError e) { - debug ("Error: %s\n", e.message); + } catch (SpawnError err) { + warning (err.message); } } }); load_applications (); - scrolled.add(icon_view); - this.pack_start(scrolled, true, true, 0); - + scrolled.add (icon_view); + this.pack_start (scrolled, true, true, 0); } public void load_applications () { - applications = DesktopFile.get_webpin_applications(); + var applications = Services.DesktopFilesManager.get_webpin_applications (); foreach (GLib.DesktopAppInfo app in applications.values) { this.add_button (app); diff --git a/src/Widgets/Assistant.vala b/src/Widgets/Assistant.vala index b180de0..d17ad33 100644 --- a/src/Widgets/Assistant.vala +++ b/src/Widgets/Assistant.vala @@ -57,15 +57,20 @@ namespace Webpin { private assistant_mode mode { get; set; default = assistant_mode.new_app; } + Gdk.RGBA default_color; + + construct { + default_color = { 222, 222, 222, 255 }; + } + public Assistant () { GLib.Object (orientation: Gtk.Orientation.VERTICAL); - apps = DesktopFile.get_applications (); + apps = Services.DesktopFilesManager.get_applications (); this.margin = 15; try { - //http(s)://(words or numbers)(port and numbers) this.protocol_regex = new Regex ("""https?\:\/\/[\w+\d+]((\:\d+)?\/\S*)?"""); } catch (RegexError e) { critical ("%s", e.message); @@ -108,18 +113,18 @@ namespace Webpin { icon_selector_popover.add (popover_box); - primary_color_button = new Gtk.ColorButton.with_rgba ({ 222, 222, 222, 255 }); + primary_color_button = new Gtk.ColorButton.with_rgba (default_color); primary_color_button.use_alpha = false; - - //TODO: categories - //combobox + primary_color_button.color_activated.connect ((color) => { + stdout.printf ("COLOR %s\n", color.to_string ()); + }); //checkbuttons save_cookies_check = new Gtk.CheckButton.with_label (_("Save cookies")); save_cookies_check.active = true; save_password_check = new Gtk.CheckButton.with_label (_("Save login information")); save_password_check.active = false; - stay_open_when_closed = new Gtk.CheckButton.with_label (_("Run in background when closed")); + stay_open_when_closed = new Gtk.CheckButton.with_label (_("Run in background if closed")); stay_open_when_closed.active = false; //app information section @@ -127,7 +132,6 @@ namespace Webpin { app_input_box.halign = Gtk.Align.START; app_input_box.pack_start (app_name_entry, false, false, 0); app_input_box.pack_start (app_url_entry, false, false, 0); - //app_input_box.pack_start (app_category_combo, true, false, 0); var app_info_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 5); app_info_box.pack_start (icon_button, false, false, 3); @@ -143,7 +147,7 @@ namespace Webpin { app_options_box.halign = Gtk.Align.CENTER; //create button - accept_button = new Gtk.Button.with_label(_("Save app")); + accept_button = new Gtk.Button.with_label (_("Save app")); accept_button.halign = Gtk.Align.END; accept_button.get_style_context ().add_class ("suggested-action"); accept_button.set_sensitive (false); @@ -161,7 +165,7 @@ namespace Webpin { icon_selector_popover.show_all(); }); - app_url_entry.changed.connect (()=>{ + app_url_entry.changed.connect (() => { if (!this.protocol_regex.match (app_url_entry.get_text())) { app_url_entry.get_style_context ().add_class ("error"); app_url_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "dialog-information"); @@ -174,8 +178,8 @@ namespace Webpin { validate (); }); - app_name_entry.changed.connect (()=>{ - if (mode == assistant_mode.new_app && DesktopFile.get_applications().has_key (app_name_entry.get_text()) ) { + app_name_entry.changed.connect (() => { + if (mode == assistant_mode.new_app && Services.DesktopFilesManager.get_applications ().has_key (app_name_entry.get_text())) { app_name_entry.get_style_context ().add_class ("error"); app_name_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "dialog-information"); app_name_entry.set_icon_tooltip_text (Gtk.EntryIconPosition.SECONDARY, _("App already exist")); @@ -204,7 +208,7 @@ namespace Webpin { } //if is a file uri - if (icon.contains("/")) { + if (icon.contains ("/")) { Gdk.Pixbuf pix = null; try { pix = new Gdk.Pixbuf.from_file_at_size (icon, 48, 48); @@ -222,7 +226,7 @@ namespace Webpin { icon_button.set_image (new Gtk.Image.from_pixbuf (pix)); } } else { - icon_button.set_image (new Gtk.Image.from_icon_name (icon, Gtk.IconSize.DIALOG) ); + icon_button.set_image (new Gtk.Image.from_icon_name (icon, Gtk.IconSize.DIALOG)); } validate (); @@ -245,14 +249,14 @@ namespace Webpin { Gtk.FileChooserAction.OPEN, _("Cancel"), Gtk.ResponseType.CANCEL, _("Open"), Gtk.ResponseType.ACCEPT); - file_chooser.set_select_multiple(false); + file_chooser.set_select_multiple (false); file_chooser.add_filter (filter); - var preview = new Gtk.Image(); + var preview = new Gtk.Image (); preview.valign = Gtk.Align.START; - file_chooser.update_preview.connect ( ()=> { - string filename = file_chooser.get_preview_filename(); + file_chooser.update_preview.connect (()=> { + string filename = file_chooser.get_preview_filename (); Gdk.Pixbuf pix = null; if (filename != null) { @@ -274,7 +278,7 @@ namespace Webpin { if (file_chooser.run () == Gtk.ResponseType.ACCEPT) { - icon_name_entry.set_text(file_chooser.get_filename ()); + icon_name_entry.set_text (file_chooser.get_filename ()); file_chooser.destroy (); } file_chooser.destroy (); @@ -297,19 +301,19 @@ namespace Webpin { app_url_entry.set_text (""); app_name_entry.get_style_context ().remove_class ("error"); app_url_entry.get_style_context ().remove_class ("error"); - icon_button.set_image (new Gtk.Image.from_icon_name (default_app_icon, Gtk.IconSize.DIALOG) ); + icon_button.set_image (new Gtk.Image.from_icon_name (default_app_icon, Gtk.IconSize.DIALOG)); mode = assistant_mode.new_app; } private void on_accept () { - string icon = icon_name_entry.get_text (); string name = app_name_entry.get_text (); string url = app_url_entry.get_text ().replace ("%", "%%"); bool stay_open = stay_open_when_closed.active; - if (icon == "") + if (icon == "") { icon = default_app_icon; + } if (app_icon_valid && app_name_valid && app_url_valid) { var desktop_file = new DesktopFile (name, url, icon, stay_open); @@ -321,23 +325,28 @@ namespace Webpin { application_edited (desktop_file.save_to_file ()); break; } + stdout.printf ("Custom Color %s\n", primary_color_button.rgba.to_string ()); desktop_file.color = primary_color_button.rgba; } } - public void edit_desktop_file (DesktopFile desktop_file) { - mode = assistant_mode.edit_app; - app_name_entry.text = desktop_file.name; - app_name_entry.set_sensitive (false); - app_url_entry.text = desktop_file.url.replace ("%%", "%"); - icon_name_entry.text = desktop_file.icon; - stay_open_when_closed.active = desktop_file.hide_on_close; - if (desktop_file.color != null) { - primary_color_button.set_rgba (desktop_file.color); + public void edit_desktop_file (DesktopFile? desktop_file) { + if (desktop_file == null) { + reset_fields (); } else { - primary_color_button.set_rgba ({ 222, 222, 222, 255 }); + mode = assistant_mode.edit_app; + app_name_entry.text = desktop_file.name; + app_name_entry.set_sensitive (false); + app_url_entry.text = desktop_file.url.replace ("%%", "%"); + icon_name_entry.text = desktop_file.icon; + stay_open_when_closed.active = desktop_file.hide_on_close; + if (desktop_file.color != null) { + primary_color_button.set_rgba (desktop_file.color); + } else { + primary_color_button.set_rgba (default_color); + } + update_app_icon (); } - update_app_icon (); } } } diff --git a/src/Widgets/WebApp.vala b/src/Widgets/WebApp.vala index f277b74..2e19619 100644 --- a/src/Widgets/WebApp.vala +++ b/src/Widgets/WebApp.vala @@ -28,14 +28,11 @@ namespace Webpin { public class WebApp : Gtk.Stack { + public WebKit.WebView app_view { get; private set; } + public DesktopFile desktop_file { get; private set; } - public WebKit.WebView app_view; - public string ui_color = "none"; - private string app_url; - private GLib.DesktopAppInfo info; - private DesktopFile file; - private WebKit.CookieManager cookie_manager; - private Gtk.Box container; + WebKit.CookieManager cookie_manager; + Gtk.Box container; Granite.Widgets.Toast app_notification; GLib.Icon icon_for_notification; @@ -43,54 +40,60 @@ namespace Webpin { public signal void request_begin (); public signal void request_finished (); public signal void desktop_notification (string title, string body, GLib.Icon icon); + public signal void found_website_color (Gdk.RGBA color); - public WebApp (string app_url) { - - this.app_url = app_url; - - //configure cookies settings - cookie_manager = WebKit.WebContext.get_default ().get_cookie_manager (); - cookie_manager.set_accept_policy (WebKit.CookieAcceptPolicy.ALWAYS); + public WebApp (DesktopFile desktop_file) { + this.desktop_file = desktop_file; + this.transition_duration = 350; + this.transition_type = Gtk.StackTransitionType.SLIDE_UP; string cookie_db = Environment.get_user_cache_dir () + "/webpin/cookies/"; - var dir = GLib.File.new_for_path (cookie_db); - if (!dir.query_exists (null)) { try { dir.make_directory_with_parents (null); - GLib.debug ("Directory '%s' created", dir.get_path ()); - } catch (Error e) { - GLib.error ("Could not create caching directory."); + } catch (Error err) { + warning ("Could not create caching directory."); } } + cookie_manager = WebKit.WebContext.get_default ().get_cookie_manager (); + cookie_manager.set_accept_policy (WebKit.CookieAcceptPolicy.ALWAYS); cookie_manager.set_persistent_storage (cookie_db + "cookies.db", WebKit.CookiePersistentStorage.SQLITE); - //load app viewer app_view = new WebKit.WebView.with_context (WebKit.WebContext.get_default ()); - app_view.load_uri (app_url); + app_view.load_uri (desktop_file.url); - container = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); - container.halign = Gtk.Align.FILL; - container.valign = Gtk.Align.FILL; + container = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); app_notification = new Granite.Widgets.Toast (""); - //overlay trick to make snapshot work even with the spinner var overlay = new Gtk.Overlay (); overlay.add (app_view); overlay.add_overlay (app_notification); - add_named (container, "splash"); - add_named (overlay, "app"); + this.add_named (container, "splash"); + this.add_named (overlay, "app"); - transition_duration = 350; - transition_type = Gtk.StackTransitionType.SLIDE_UP; + var icon_file = File.new_for_path (desktop_file.icon); + + Gtk.Image icon; + if (icon_file.query_exists ()) { + try { + icon = new Gtk.Image.from_pixbuf (new Gdk.Pixbuf.from_file_at_scale (desktop_file.icon, 48, 48, true)); + icon_for_notification = GLib.Icon.new_for_string (desktop_file.icon); + } catch (Error err) { + warning (err.message); + icon = new Gtk.Image.from_icon_name ("com.github.artemanufrij.webpin", Gtk.IconSize.DIALOG); + } + } else { + icon = new Gtk.Image.from_icon_name (desktop_file.icon, Gtk.IconSize.DIALOG); + icon_for_notification = new GLib.ThemedIcon (desktop_file.icon); + } + container.pack_start (icon, true, true, 0); app_view.create.connect ((action) => { - print("external request"); app_notification.title = _("Open request in an external application…"); app_notification.send_notification (); @@ -98,33 +101,7 @@ namespace Webpin { return new WebKit.WebView (); }); - info = DesktopFile.get_app_by_url(app_url); - file = new DesktopFile.from_desktopappinfo(info); - - var icon_file = File.new_for_path (file.icon); - - Gtk.Image icon; - if (icon_file.query_exists ()) { - try { - icon = new Gtk.Image.from_pixbuf (new Gdk.Pixbuf.from_file_at_scale (file.icon, 48, 48, true)); - icon_for_notification = GLib.Icon.new_for_string (file.icon); - } catch (Error e) { - warning (e.message); - icon = new Gtk.Image.from_icon_name ("com.github.artemanufrij.webpin", Gtk.IconSize.DIALOG); - } - } else { - icon = new Gtk.Image.from_icon_name (file.icon, Gtk.IconSize.DIALOG); - icon_for_notification = new GLib.ThemedIcon (file.icon); - } - container.pack_start(icon, true, true, 0); - - Gdk.RGBA background = {}; - if (!background.parse (ui_color)){ - background = {1,1,1,1}; - } - container.override_background_color (Gtk.StateFlags.NORMAL, background); - - app_view.load_changed.connect ( (load_event) => { + app_view.load_changed.connect ((load_event) => { request_begin (); if (load_event == WebKit.LoadEvent.FINISHED) { visible_child_name = "app"; @@ -132,6 +109,23 @@ namespace Webpin { app_notification.reveal_child = false; } request_finished (); + var source = app_view.get_main_resource (); + source.get_data.begin (null, (obj, res) => { + try { + var body = (string)source.get_data.end (res); + var regex = new Regex ("(?<=