diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..423da6e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ + sudo: required + language: generic + + services: + - docker + + script: + - wget -O- https://raw.githubusercontent.com/harisvsulaiman/element-build/master/script.sh | sh - + + branches: + except: + - /^debian\/\d/ diff --git a/README.md b/README.md index 78758be..f430506 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,6 @@ Webpin is a fork of Webby created by Erasmo Marín Pin your any favourite website on Applications Menu or Plank like a regular desktop app ![Apps](Apps.png) + +## Donations +If you liked _Webpin_, and would like to support it's development of this app and more, consider [buying me a coffee](https://www.paypal.me/ArtemAnufrij) :) diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 33f3fdc..b91ec4e 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -1,8 +1,8 @@ install (FILES com.github.artemanufrij.webpin.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/applications) install (FILES com.github.artemanufrij.webpin.appdata.xml DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/metainfo) -install (FILES icons/artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/) -install (FILES icons/32/artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/32x32/apps/) -install (FILES icons/48/artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/48x48/apps/) -install (FILES icons/artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/64x64/apps/) -install (FILES icons/artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/128x128/apps/) +install (FILES icons/com.github.artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/) +install (FILES icons/32/com.github.artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/32x32/apps/) +install (FILES icons/48/com.github.artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/48x48/apps/) +install (FILES icons/com.github.artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/64x64/apps/) +install (FILES icons/com.github.artemanufrij.webpin.svg DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/128x128/apps/) diff --git a/data/com.github.artemanufrij.webpin.appdata.xml b/data/com.github.artemanufrij.webpin.appdata.xml index a59dcf8..dfaf69d 100644 --- a/data/com.github.artemanufrij.webpin.appdata.xml +++ b/data/com.github.artemanufrij.webpin.appdata.xml @@ -7,7 +7,7 @@ Webpin A simple app to pin websites on the desktop -

Pin your any favorite website on Applications Menu or Plank like a regular desktop app

+

Create your own WebApps. Pin your any favorite website on Applications Menu or Plank like a regular desktop app.

Utility @@ -31,4 +31,91 @@ https://raw.githubusercontent.com/artemanufrij/webpin/master/Screenshot_new_app.png + + + +

New:

+
    +
  • Option for Dark Theme
  • +
  • Grab 'theme-color' (if exists) from called website
  • +
+
+
+ + +

Fix:

+
    +
  • Custom settings in .desktop
  • +
+
+
+ + +

Fix:

+
    +
  • Custom settings in .desktop
  • +
+
+
+ + +

Fix:

+
    +
  • Set custom color
  • +
+
+
+ + +

Fix:

+
    +
  • Desktop icon name
  • +
+
+
+ + +

Fix:

+
    +
  • Set custom color for headerbar
  • +
+
+
+ + +

Fix:

+
    +
  • Set custom color for headerbar
  • +
+
+
+ + +

New:

+
    +
  • Set custom color for headerbar
  • +
+

Fix:

+
    +
  • Open application on clicking desktop notification
  • +
+

Translation:

+
    +
  • Lithuanian (by welaq)
  • +
+
+
+ + +

New:

+
    +
  • Copy current URI into clipboard
  • +
+

Fix:

+
    +
  • Open WebApp on single click instead double click
  • +
+
+
+
diff --git a/data/com.github.artemanufrij.webpin.desktop b/data/com.github.artemanufrij.webpin.desktop index 76c3f9b..3bde0e9 100644 --- a/data/com.github.artemanufrij.webpin.desktop +++ b/data/com.github.artemanufrij.webpin.desktop @@ -5,7 +5,7 @@ Comment=Pin your websites on your desktop Comment[lt]=Prisegti interneto svetaines savo darbalaukyje Keywords=internet;webapp; Exec=com.github.artemanufrij.webpin %u -Icon=artemanufrij.webpin +Icon=com.github.artemanufrij.webpin Terminal=false Type=Application Categories=Network;GNOME;GTK; diff --git a/data/icons/32/artemanufrij.webpin.svg b/data/icons/32/com.github.artemanufrij.webpin.svg similarity index 100% rename from data/icons/32/artemanufrij.webpin.svg rename to data/icons/32/com.github.artemanufrij.webpin.svg diff --git a/data/icons/48/artemanufrij.webpin.svg b/data/icons/48/com.github.artemanufrij.webpin.svg similarity index 100% rename from data/icons/48/artemanufrij.webpin.svg rename to data/icons/48/com.github.artemanufrij.webpin.svg diff --git a/data/icons/artemanufrij.webpin.svg b/data/icons/com.github.artemanufrij.webpin.svg similarity index 100% rename from data/icons/artemanufrij.webpin.svg rename to data/icons/com.github.artemanufrij.webpin.svg diff --git a/debian/changelog b/debian/changelog index 4dcf9ad..5f47cfc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +com.github.artemanufrij.webpin (0.2.1) xenial; urgency=low + + * Fixed custom color. + + -- Artem Anufrij Sun, 19 Nov 2017 04:53:39 +0100 + com.github.artemanufrij.webpin (0.1.3) xenial; urgency=low * Initial Release. diff --git a/po/com.github.artemanufrij.webpin.pot b/po/com.github.artemanufrij.webpin.pot index 87eccd7..3e88a39 100644 --- a/po/com.github.artemanufrij.webpin.pot +++ b/po/com.github.artemanufrij.webpin.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-09-09 21:07+0400\n" +"POT-Creation-Date: 2017-10-15 19:26+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,24 +17,20 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../src/WebWindow.vala:61 ../src/Widgets/Assistant.vala:118 +#: ../src/Dialogs/InfoDialog.vala:44 +msgid "Accept" +msgstr "" + +#: ../src/WebWindow.vala:53 +msgid "Copy URI into clipboard" +msgstr "" + +#: ../src/WebWindow.vala:65 ../src/Widgets/Assistant.vala:118 msgid "Run in background when closed" msgstr "" -#: ../src/WebWindow.vala:73 ../src/WebWindow.vala:83 -msgid "Unmute notifications" -msgstr "" - -#: ../src/WebWindow.vala:76 ../src/WebWindow.vala:86 -msgid "Mute notifications" -msgstr "" - -#: ../src/WebWindow.vala:88 -msgid "Desktop notifications are enabled" -msgstr "" - -#: ../src/Dialogs/InfoDialog.vala:44 -msgid "Accept" +#: ../src/WebWindow.vala:115 +msgid "Open %s" msgstr "" #: ../src/MainWindow.vala:56 @@ -61,6 +57,10 @@ msgstr "" msgid "Create a new web app with Webpin" msgstr "" +#: ../src/Widgets/WebApp.vala:94 +msgid "Open request in an external application…" +msgstr "" + #: ../src/Widgets/Assistant.vala:74 msgid "Create a new web app" msgstr "" @@ -124,7 +124,3 @@ msgstr "" #: ../src/Widgets/ApplicationIcon.vala:147 msgid "Edit Webapp Properties" msgstr "" - -#: ../src/Widgets/WebApp.vala:93 -msgid "Open request in an external application…" -msgstr "" diff --git a/po/lt.po b/po/lt.po index f747281..1a42661 100644 --- a/po/lt.po +++ b/po/lt.po @@ -7,88 +7,33 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-08-28 22:31+0300\n" -"PO-Revision-Date: 2017-08-28 22:39+0300\n" +"POT-Creation-Date: 2017-10-18 22:53+0300\n" +"PO-Revision-Date: 2017-10-18 22:55+0300\n" +"Last-Translator: Moo\n" "Language-Team: \n" +"Language: lt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7.1\n" -"Last-Translator: Moo\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"Language: lt\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" +"%100<10 || n%100>=20) ? 1 : 2);\n" #: ../src/Dialogs/InfoDialog.vala:44 msgid "Accept" msgstr "Priimti" -#: ../src/Widgets/ApplicationIcon.vala:142 -msgid "Delete Webapp" -msgstr "Ištrinti saityno programą" +#: ../src/WebWindow.vala:53 +msgid "Copy URI into clipboard" +msgstr "Kopijuoti URI į iškarpinę" -#: ../src/Widgets/ApplicationIcon.vala:147 -msgid "Edit Webapp Properties" -msgstr "Taisyti saityno programos savybes" +#: ../src/WebWindow.vala:65 ../src/Widgets/Assistant.vala:118 +msgid "Run in background when closed" +msgstr "Užvėrus, palikti veikti fone" -#: ../src/Widgets/Assistant.vala:73 -msgid "Create a new web app" -msgstr "Sukurti naują saityno programą" - -#: ../src/Widgets/Assistant.vala:81 -msgid "Application name" -msgstr "Programos pavadinimas" - -#: ../src/Widgets/Assistant.vala:84 -msgid "http://myapp.domain" -msgstr "http://manoprograma.sritis" - -#: ../src/Widgets/Assistant.vala:94 -msgid "theme icon name" -msgstr "temos piktogramos pavadinimas" - -#: ../src/Widgets/Assistant.vala:96 -msgid "or" -msgstr "arba" - -#: ../src/Widgets/Assistant.vala:97 -msgid "Set from file..." -msgstr "Nustatyti iš failo..." - -#: ../src/Widgets/Assistant.vala:113 -msgid "Save cookies" -msgstr "Įrašyti slapukus" - -#: ../src/Widgets/Assistant.vala:115 -msgid "Save login information" -msgstr "Įrašyti prisijungimo informaciją" - -#: ../src/Widgets/Assistant.vala:138 -msgid "Save app" -msgstr "Įrašyti programą" - -#: ../src/Widgets/Assistant.vala:160 -msgid "url must start with http:// or https://" -msgstr "url privalo prasidėti http:// arba https://" - -#: ../src/Widgets/Assistant.vala:173 -msgid "App already exist" -msgstr "Programa jau yra" - -#: ../src/Widgets/Assistant.vala:226 -msgid "Images" -msgstr "Paveikslai" - -#: ../src/Widgets/Assistant.vala:238 -msgid "Cancel" -msgstr "Atsisakyti" - -#: ../src/Widgets/Assistant.vala:239 -msgid "Open" -msgstr "Atverti" - -#: ../src/Widgets/WebApp.vala:93 -msgid "Open request in an external application…" -msgstr "Užklausa atveriama išorinėje programoje…" +#: ../src/WebWindow.vala:115 +msgid "Open %s" +msgstr "Atverti %s" #: ../src/MainWindow.vala:56 msgid "Applications" @@ -113,3 +58,71 @@ msgstr "Sukurti programą" #: ../src/MainWindow.vala:66 msgid "Create a new web app with Webpin" msgstr "Sukurkite naują saityno programą, naudodami Webpin" + +#: ../src/Widgets/WebApp.vala:94 +msgid "Open request in an external application…" +msgstr "Užklausa atveriama išorinėje programoje…" + +#: ../src/Widgets/Assistant.vala:74 +msgid "Create a new web app" +msgstr "Sukurti naują saityno programą" + +#: ../src/Widgets/Assistant.vala:82 +msgid "Application name" +msgstr "Programos pavadinimas" + +#: ../src/Widgets/Assistant.vala:85 +msgid "http://myapp.domain" +msgstr "http://manoprograma.sritis" + +#: ../src/Widgets/Assistant.vala:95 +msgid "theme icon name" +msgstr "temos piktogramos pavadinimas" + +#: ../src/Widgets/Assistant.vala:97 +msgid "or" +msgstr "arba" + +#: ../src/Widgets/Assistant.vala:98 +msgid "Set from file..." +msgstr "Nustatyti iš failo..." + +#: ../src/Widgets/Assistant.vala:114 +msgid "Save cookies" +msgstr "Įrašyti slapukus" + +#: ../src/Widgets/Assistant.vala:116 +msgid "Save login information" +msgstr "Įrašyti prisijungimo informaciją" + +#: ../src/Widgets/Assistant.vala:141 +msgid "Save app" +msgstr "Įrašyti programą" + +#: ../src/Widgets/Assistant.vala:163 +msgid "url must start with http:// or https://" +msgstr "url privalo prasidėti http:// arba https://" + +#: ../src/Widgets/Assistant.vala:176 +msgid "App already exist" +msgstr "Programa jau yra" + +#: ../src/Widgets/Assistant.vala:229 +msgid "Images" +msgstr "Paveikslai" + +#: ../src/Widgets/Assistant.vala:241 +msgid "Cancel" +msgstr "Atsisakyti" + +#: ../src/Widgets/Assistant.vala:242 +msgid "Open" +msgstr "Atverti" + +#: ../src/Widgets/ApplicationIcon.vala:142 +msgid "Delete Webapp" +msgstr "Ištrinti saityno programą" + +#: ../src/Widgets/ApplicationIcon.vala:147 +msgid "Edit Webapp Properties" +msgstr "Taisyti saityno programos savybes" 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 f062c23..393f10c 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -27,12 +27,10 @@ */ namespace Webpin { - public class WebpinApp : Granite.Application { + public class WebpinApp : Gtk.Application { static WebpinApp _instance = null; - public GLib.List app_list; - public static WebpinApp instance { get { if (_instance == null) @@ -42,51 +40,55 @@ namespace Webpin { } construct { - program_name = "Webpin"; - exec_name = "com.github.artemanufrij.webpin"; - application_id = "com.github.artemanufrij.webpin"; - app_launcher = application_id + ".desktop"; flags |= GLib.ApplicationFlags.HANDLES_OPEN; - app_list = new GLib.List (); + + 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) { + start_webapp (parameter.get_string ()); + } + }); } - public Gtk.Window mainwindow; + public Gtk.Window mainwindow { get; private set; default = null; } protected override void activate () { if (mainwindow != null) { mainwindow.present (); return; } - mainwindow = new MainWindow (); - mainwindow.destroy.connect (() => { mainwindow = null; }); - mainwindow.set_application(this); + mainwindow.set_application (this); } public override void open (File[] files, string hint) { - debug (files [0].get_uri ()); start_webapp (files [0].get_uri ()); } - - public void start_webapp (string url) { - foreach (var item in app_list) { - if (item.desktop_file.url == url) { - item.present (); - return; - } - } - var app_info = Webpin.DesktopFile.get_app_by_url (url); - var desktop_file = new Webpin.DesktopFile.from_desktopappinfo(app_info); - var app = new WebWindow(desktop_file); - app.destroy.connect (() => { app_list.remove (app); }); - app.set_application (this); - app_list.append (app); + private void start_webapp (string url) { + if (mainwindow != null ) { + mainwindow.present (); + return; + } + var app_info = Services.DesktopFilesManager.get_app_by_url (url); + var desktop_file = new Webpin.DesktopFile.from_desktopappinfo (app_info); + mainwindow = new Windows.WebApp (desktop_file); + mainwindow.set_application (this); } } } + static int main (string[] args) { Gtk.init (ref args); var app = Webpin.WebpinApp.instance; + if (args.length > 1) { + var checksum = new GLib.Checksum (GLib.ChecksumType.MD5); + checksum.update (args[1].data, args[1].length); + var id = "a" + checksum.get_string ().substring (0, 5) + "a.artemanufrij.webpin"; + app.application_id = id; + } else { + app.application_id = "com.github.artemanufrij.webpin"; + } return app.run (args); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 62d9098..b26fde2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,14 +1,14 @@ vala_precompile(VALA_C ${CMAKE_PROJECT_NAME} - Widgets/ApplicationIcon.vala - Widgets/ApplicationsView.vala - Widgets/Assistant.vala - Widgets/WebApp.vala + Widgets/WebItem.vala + Widgets/Views/WebItemsView.vala + Widgets/Views/Editor.vala + Widgets/Browser.vala + Windows/WebApp.vala Objects/DesktopFile.vala - Dialogs/InfoDialog.vala + Dialogs/Preferences.vala + Services/DesktopFilesManager.vala Settings.vala - UrlEntry.vala MainWindow.vala - WebWindow.vala Application.vala PACKAGES gtk+-3.0 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..2f36c7a 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; + Widgets.Views.Editor editor; + Widgets.Views.WebItemsView web_items_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) => { @@ -72,47 +106,48 @@ namespace Webpin { } }); - apps_view = new ApplicationsView(); - assistant = new Assistant(); + web_items_view = new Widgets.Views.WebItemsView (); + editor = new Widgets.Views.Editor (); stack = new Gtk.Stack (); stack.set_transition_duration (500); stack.add_named (welcome, "welcome"); - stack.add_named (apps_view, "apps_view"); - stack.add_named (assistant, "assistant"); + stack.add_named (web_items_view, "apps_view"); + stack.add_named (editor, "editor"); add (stack); - apps_view.add_request.connect (() => { + web_items_view.add_request.connect (() => { show_assistant (); }); - apps_view.edit_request.connect ((desktop_file) => { + web_items_view.edit_request.connect ((desktop_file) => { show_assistant (desktop_file); }); - apps_view.app_deleted.connect (() => { - if (!apps_view.has_items) { + web_items_view.app_deleted.connect (() => { + if (!web_items_view.has_items) { show_welcome_view (Gtk.StackTransitionType.NONE); } }); - assistant.application_created.connect ((new_file) => { - apps_view.add_button (new_file); - apps_view.select_last_item (); + editor.application_created.connect ((new_file) => { + web_items_view.add_web_item (new_file); + web_items_view.select_last_item (); show_apps_view (); }); - assistant.application_edited.connect ((edited_file) => { - apps_view.update_button (edited_file); + editor.application_edited.connect ((edited_file) => { + web_items_view.update_button (edited_file); show_apps_view (); }); back_button.clicked.connect (() => { - if (apps_view.has_items) + if (web_items_view.has_items) { show_apps_view (); - else + } else { show_welcome_view (); + } }); add_button.clicked.connect (() => { @@ -127,24 +162,21 @@ namespace Webpin { this.restore_settings (); show_all (); - if (apps_view.has_items) + if (web_items_view.has_items) { show_apps_view (Gtk.StackTransitionType.NONE); - else + } else { show_welcome_view (Gtk.StackTransitionType.NONE); + } this.present (); } private void show_assistant (DesktopFile? desktop_file = null) { stack.set_transition_type (Gtk.StackTransitionType.SLIDE_LEFT); - stack.set_visible_child_name("assistant"); + stack.set_visible_child_name("editor"); 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); + editor.edit_desktop_file (desktop_file); } private void show_apps_view (Gtk.StackTransitionType slide = Gtk.StackTransitionType.SLIDE_RIGHT) { @@ -152,9 +184,7 @@ namespace Webpin { stack.set_visible_child_name ("apps_view"); back_button.hide (); add_button.show_all (); - assistant.reset_fields (); - //fix ugly border at the bottom of headerbar - queue_draw (); + editor.reset_fields (); } private void show_welcome_view (Gtk.StackTransitionType slide = Gtk.StackTransitionType.SLIDE_RIGHT) { @@ -162,16 +192,15 @@ namespace Webpin { stack.set_visible_child_name ("welcome"); back_button.hide (); add_button.hide (); - assistant.reset_fields (); - //fix ugly border at the bottom of headerbar - queue_draw (); + editor.reset_fields (); } 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 1db111c..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,27 +53,42 @@ 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", "WebpinStayOpen") == "true"; - } catch (Error e) { - warning (e.message); + return file.get_string ("Desktop Entry", "X-Webpin-StayOpen") == "true"; + } catch (Error err) { + warning (err.message); } return false; } } - public bool mute_notifications { + Gdk.RGBA? _color; + public Gdk.RGBA? color { get { - this.file = new GLib.KeyFile(); - try { - file.load_from_file (info.filename, KeyFileFlags.NONE); - return file.get_string ("Desktop Entry", "WebpinMuteNotifications") == "true"; - } catch (Error e) { - warning (e.message); + if (_color == null) { + 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 err) { + warning (err.message); + return null; + } + _color = return_value; + } + return _color; + } 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_property ("X-Webpin-PrimaryColor", color); + } else { + edit_property ("X-Webpin-PrimaryColor", "none"); } - return false; } } @@ -84,46 +100,46 @@ 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); file.set_string ("Desktop Entry", "Exec", "com.github.artemanufrij.webpin " + url); file.set_string ("Desktop Entry", "Icon", icon); file.set_string ("Desktop Entry", "StartupWMClass", url); - file.set_string ("Desktop Entry", "WebpinStayOpen", stay_open.to_string ()); + 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; @@ -132,73 +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").replace ("%%", "%"); - - if (exec != null && 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..eda853f --- /dev/null +++ b/src/Services/DesktopFilesManager.vala @@ -0,0 +1,103 @@ +/*- + * 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; + } + + public static Gdk.Pixbuf? align_and_scale_pixbuf (Gdk.Pixbuf p, int size) { + Gdk.Pixbuf? pixbuf = p; + if (pixbuf.width != pixbuf.height) { + if (pixbuf.width > pixbuf.height) { + int dif = (pixbuf.width - pixbuf.height) / 2; + pixbuf = new Gdk.Pixbuf.subpixbuf (pixbuf, dif, 0, pixbuf.height, pixbuf.height); + } else { + int dif = (pixbuf.height - pixbuf.width) / 2; + pixbuf = new Gdk.Pixbuf.subpixbuf (pixbuf, 0, dif, pixbuf.width, pixbuf.width); + } + } + pixbuf = pixbuf.scale_simple (size, size, Gdk.InterpType.BILINEAR); + return pixbuf; + } + + public static string? choose_new_icon () { + string? return_value = null; + var dialog = new Gtk.FileChooserDialog ( + _("Choose an image…"), WebpinApp.instance.mainwindow, + Gtk.FileChooserAction.OPEN, + _("_Cancel"), Gtk.ResponseType.CANCEL, + _("_Open"), Gtk.ResponseType.ACCEPT); + + var filter = new Gtk.FileFilter (); + filter.set_filter_name (_("Images")); + filter.add_mime_type ("image/*"); + + dialog.add_filter (filter); + + if (dialog.run () == Gtk.ResponseType.ACCEPT) { + return_value = dialog.get_filename (); + } + + dialog.destroy(); + return return_value; + } + } +} 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 deleted file mode 100644 index ff676fe..0000000 --- a/src/WebWindow.vala +++ /dev/null @@ -1,252 +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 WebWindow : Gtk.Window { - - private bool is_full_screen = false; - - //widgets - private WebApp web_app; - - Gtk.Spinner spinner; - - public DesktopFile desktop_file { get; private set; } - private Notification desktop_notification; - - public WebWindow (DesktopFile desktop_file) { - this.desktop_file = desktop_file; - this.events |= Gdk.EventMask.STRUCTURE_MASK; - - set_wmclass (desktop_file.url, desktop_file.url); - web_app = new WebApp (desktop_file.url); - - desktop_notification = new Notification (""); - - var headerbar = new Gtk.HeaderBar (); - headerbar.title = desktop_file.name; - headerbar.show_close_button = true; - - spinner = new Gtk.Spinner (); - spinner.set_size_request (16, 16); - headerbar.pack_end (spinner); - - var stay_open = new Gtk.ToggleButton (); - stay_open.active = desktop_file.hide_on_close; - 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 ("WebpinStayOpen", stay_open.active.to_string ()); - desktop_file.save_to_file (); - }); - headerbar.pack_start (stay_open); - - var mute_notifications = new Gtk.ToggleButton (); - mute_notifications.active = desktop_file.mute_notifications; - if (mute_notifications.active) { - mute_notifications.image = new Gtk.Image.from_icon_name ("notification-disabled-symbolic", Gtk.IconSize.MENU); - mute_notifications.tooltip_text = _("Unmute notifications"); - } else { - mute_notifications.image = new Gtk.Image.from_icon_name ("notification-symbolic", Gtk.IconSize.MENU); - mute_notifications.tooltip_text = _("Mute notifications"); - } - mute_notifications.toggled.connect (() => { - desktop_file.edit_propertie ("WebpinMuteNotifications", mute_notifications.active.to_string ()); - desktop_file.save_to_file (); - if (mute_notifications.active) { - mute_notifications.image = new Gtk.Image.from_icon_name ("notification-disabled-symbolic", Gtk.IconSize.MENU); - mute_notifications.tooltip_text = _("Unmute notifications"); - } else { - mute_notifications.image = new Gtk.Image.from_icon_name ("notification-symbolic", Gtk.IconSize.MENU); - mute_notifications.tooltip_text = _("Mute notifications"); - desktop_notification.set_title (desktop_file.name); - desktop_notification.set_body (_("Desktop notifications are enabled")); - WebpinApp.instance.send_notification (null, desktop_notification); - } - }); - headerbar.pack_start (mute_notifications); - - this.set_titlebar (headerbar); - - var width = desktop_file.info.get_string ("WebpinWindowWidth"); - var height = desktop_file.info.get_string ("WebpinWindowHeight"); - var state = desktop_file.info.get_string ("WebpinWindowMaximized"); - var zoom = desktop_file.info.get_string ("WebpinWindowZoom"); - - 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); - if (desktop_file.hide_on_close) { - this.hide_on_delete (); - } - return desktop_file.hide_on_close; - }); - - web_app.external_request.connect ((action) => { - debug ("Web app external request: %s", action.get_request ().uri); - try { - Process.spawn_command_line_async ("xdg-open " + action.get_request ().uri); - } catch (Error e) { - warning (e.message); - } - }); - - web_app.desktop_notification.connect ((title, body) => { - if (!desktop_file.mute_notifications) { - desktop_notification.set_title (title); - desktop_notification.set_body (body); - WebpinApp.instance.send_notification (null, desktop_notification); - } - }); - - web_app.request_begin.connect (() => { - spinner.active = true; - }); - - web_app.request_finished.connect (() => { - spinner.active = false; - }); - - add(web_app); - show_all(); - } - - public new void fullscreen () { - is_full_screen = true; - base.fullscreen(); - } - - public new void unfullscreen () { - is_full_screen = false; - base.unfullscreen(); - } - - public void toggle_fullscreen() { - if(is_full_screen) { - unfullscreen(); - } - 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(); - - if (is_maximized) { - file.edit_propertie ("WebpinWindowMaximized", "max"); - } else { - file.edit_propertie ("WebpinWindowWidth", width.to_string()); - file.edit_propertie ("WebpinWindowHeight", height.to_string()); - file.edit_propertie ("WebpinWindowMaximized", "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 ("WebpinWindowZoom", 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 ("WebpinWindowZoom", 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 ("WebpinWindowZoom", 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; - } - - if (handled) - return true; - - return (base.key_press_event != null) ? base.key_press_event (event) : true; - } - } -} diff --git a/src/Widgets/WebApp.vala b/src/Widgets/Browser.vala similarity index 50% rename from src/Widgets/WebApp.vala rename to src/Widgets/Browser.vala index e128e18..7b6aefb 100644 --- a/src/Widgets/WebApp.vala +++ b/src/Widgets/Browser.vala @@ -26,70 +26,85 @@ * Authored by: Artem Anufrij */ -namespace Webpin { - public class WebApp : Gtk.Stack { +namespace Webpin.Widgets { + public class Browser : Gtk.Stack { + public WebKit.WebView web_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; public signal void external_request (WebKit.NavigationAction action); public signal void request_begin (); public signal void request_finished (); - public signal void desktop_notification (string title, string body); + 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 Browser (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); + web_view = new WebKit.WebView.with_context (WebKit.WebContext.get_default ()); + web_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); + + if (desktop_file.color != null) { + var css_provider = Gtk.CssProvider.get_default (); + try { + css_provider.load_from_data (""" .box { background: """ + desktop_file.color.to_string () + """; } """); + } catch (Error err) { + warning (err.message); + } + container.get_style_context ().add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + container.get_style_context ().add_class ("box"); + } 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 (web_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); - app_view.create.connect ((action) => { - print("external request"); + 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); + + web_view.create.connect ((action) => { app_notification.title = _("Open request in an external application…"); app_notification.send_notification (); @@ -97,32 +112,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)); - - } catch (Error e) { - warning (e.message); - icon = new Gtk.Image.from_icon_name ("artemanufrij.webpin", Gtk.IconSize.DIALOG); - } - } else { - icon = new Gtk.Image.from_icon_name (file.icon, Gtk.IconSize.DIALOG); - } - 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) => { + web_view.load_changed.connect ((load_event) => { request_begin (); if (load_event == WebKit.LoadEvent.FINISHED) { visible_child_name = "app"; @@ -130,15 +120,32 @@ namespace Webpin { app_notification.reveal_child = false; } request_finished (); + var source = web_view.get_main_resource (); + source.get_data.begin (null, (obj, res) => { + try { + var body = (string)source.get_data.end (res); + var regex = new Regex ("(?<= { - desktop_notification (notification.title, notification.body); - return false; + web_view.show_notification.connect ((notification) => { + desktop_notification (notification.title, notification.body, icon_for_notification); + return true; }); - app_view.permission_request.connect ((permission) => { + web_view.permission_request.connect ((permission) => { var permission_type = permission as WebKit.NotificationPermissionRequest; if (permission_type != null) { permission_type.allow (); @@ -146,9 +153,5 @@ namespace Webpin { return false; }); } - - public DesktopFile get_desktop_file () { - return this.file; - } } } diff --git a/src/Widgets/Assistant.vala b/src/Widgets/Views/Editor.vala similarity index 76% rename from src/Widgets/Assistant.vala rename to src/Widgets/Views/Editor.vala index 7be9ec8..ae71906 100644 --- a/src/Widgets/Assistant.vala +++ b/src/Widgets/Views/Editor.vala @@ -26,29 +26,30 @@ * Authored by: Artem Anufrij */ -namespace Webpin { - public class Assistant : Gtk.Box { +namespace Webpin.Widgets.Views { + public class Editor : Gtk.Box { public enum assistant_mode { new_app, edit_app } public signal void application_created (GLib.DesktopAppInfo? new_file); public signal void application_edited (GLib.DesktopAppInfo? new_file); - private Gtk.Label message; - private Gtk.Button icon_button; - private Gtk.Entry app_name_entry; - private Gtk.Entry app_url_entry; - private Gtk.Entry icon_name_entry; - private Gtk.CheckButton save_cookies_check; - private Gtk.CheckButton save_password_check; - private Gtk.CheckButton stay_open_when_closed; - private Gtk.Popover icon_selector_popover; - private Gtk.FileChooserDialog file_chooser; - private Gtk.Button accept_button; - private GLib.Regex protocol_regex; - private Gee.HashMap apps; + Gtk.Label message; + Gtk.Button icon_button; + Gtk.Entry app_name_entry; + Gtk.Entry app_url_entry; + Gtk.Entry icon_name_entry; + Gtk.CheckButton save_cookies_check; + Gtk.CheckButton save_password_check; + Gtk.CheckButton stay_open_when_closed; + Gtk.Popover icon_selector_popover; + Gtk.FileChooserDialog file_chooser; + Gtk.Button accept_button; + Gtk.ColorButton primary_color_button; + GLib.Regex protocol_regex; + Gee.HashMap apps; - private string default_app_icon = "artemanufrij.webpin"; + private string default_app_icon = "com.github.artemanufrij.webpin"; private bool app_name_valid = false; private bool app_url_valid = false; @@ -56,15 +57,20 @@ namespace Webpin { private assistant_mode mode { get; set; default = assistant_mode.new_app; } - public Assistant () { + Gdk.RGBA default_color; + + construct { + default_color = { 222, 222, 222, 255 }; + } + + public Editor () { 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); @@ -107,15 +113,18 @@ namespace Webpin { icon_selector_popover.add (popover_box); - //TODO: categories - //combobox + primary_color_button = new Gtk.ColorButton.with_rgba (default_color); + primary_color_button.use_alpha = false; + 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 @@ -123,11 +132,11 @@ 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); app_info_box.pack_start (app_input_box, false, false, 3); + app_info_box.pack_start (primary_color_button, false, false, 3); app_info_box.halign = Gtk.Align.CENTER; //app options @@ -138,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); @@ -156,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"); @@ -169,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")); @@ -199,25 +208,25 @@ 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); app_icon_valid = true; - } catch (GLib.Error error) { + } catch (GLib.Error error) { app_icon_valid = false; try { Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default (); pix = icon_theme.load_icon ("image-missing", 48, Gtk.IconLookupFlags.FORCE_SIZE); } catch (GLib.Error err) { - warning ("Getting selection-checked icon from theme failed"); + warning ("Getting selection-checked icon from theme failed"); } - } finally { - if (pix != null) - icon_button.set_image (new Gtk.Image.from_pixbuf (pix)); + } + if (pix != null) { + 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 (); @@ -225,38 +234,29 @@ namespace Webpin { private void on_icon_chooser_activate () { var filter = new Gtk.FileFilter (); - filter.set_filter_name (_("Images")); - filter.add_pattern ("*.png"); - filter.add_pattern ("*.svg"); - filter.add_pattern ("*.jpg"); - filter.add_pattern ("*.jpeg"); - filter.add_pattern ("*.PNG"); - filter.add_pattern ("*.SVG"); - filter.add_pattern ("*.JPG"); - filter.add_pattern ("*.JPEG"); + filter.add_mime_type ("image/*"); file_chooser = new Gtk.FileChooserDialog ("", null, 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) { try { pix = new Gdk.Pixbuf.from_file_at_size (filename, 128, 128); - } catch (GLib.Error error) { + } catch (GLib.Error error) { warning ("There was a problem loading preview."); - } + } } if (pix != null){ @@ -270,7 +270,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 (); @@ -293,19 +293,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); @@ -317,17 +317,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; - update_app_icon (); + public void edit_desktop_file (DesktopFile? desktop_file) { + if (desktop_file == null) { + reset_fields (); + } else { + 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 (); + } } } } diff --git a/src/Widgets/ApplicationsView.vala b/src/Widgets/Views/WebItemsView.vala similarity index 54% rename from src/Widgets/ApplicationsView.vala rename to src/Widgets/Views/WebItemsView.vala index 45d1639..517ffb3 100644 --- a/src/Widgets/ApplicationsView.vala +++ b/src/Widgets/Views/WebItemsView.vala @@ -26,87 +26,83 @@ * Authored by: Artem Anufrij */ -namespace Webpin { - public class ApplicationsView : Gtk.Box { +namespace Webpin.Widgets.Views { + public class WebItemsView : Gtk.Box { - public signal void add_request(); - public signal void edit_request(DesktopFile desktop_file); + public signal void add_request (); + public signal void edit_request (DesktopFile desktop_file); public signal void app_deleted (); - private Gtk.FlowBox icon_view; - private Gee.HashMap applications; + Gtk.FlowBox web_items; - public bool has_items { get { return icon_view.get_children ().length () > 0; } } + public bool has_items { get { return web_items.get_children ().length () > 0; } } - public ApplicationsView () { + public WebItemsView () { GLib.Object (orientation: Gtk.Orientation.VERTICAL); var scrolled = new Gtk.ScrolledWindow (null, null); scrolled.hscrollbar_policy = Gtk.PolicyType.NEVER; - icon_view = new Gtk.FlowBox(); - icon_view.valign = Gtk.Align.START; - icon_view.vexpand = false; - icon_view.homogeneous = true; - icon_view.column_spacing = 15; - icon_view.row_spacing = 15; - icon_view.margin = 15; - icon_view.activate_on_single_click = false; - icon_view.child_activated.connect ((child) => { - if ((child as Gtk.FlowBoxChild).get_child () is ApplicationIcon) { - var app_icon = (child as Gtk.FlowBoxChild).get_child () as ApplicationIcon; + web_items = new Gtk.FlowBox(); + web_items.valign = Gtk.Align.START; + web_items.vexpand = false; + web_items.homogeneous = true; + web_items.column_spacing = 12; + web_items.row_spacing = 12; + web_items.margin = 24; + web_items.child_activated.connect ((child) => { + if (child is WebItem) { + var app_icon = child as WebItem; 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 (web_items); + 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); + this.add_web_item (app); } } - public void add_button (GLib.DesktopAppInfo app) { - var image = new ApplicationIcon (app); - image.edit_request.connect ((desktop_file) => { + public void add_web_item (GLib.DesktopAppInfo app) { + var web_item = new WebItem (app); + web_item.edit_request.connect ((desktop_file) => { edit_request (desktop_file); - icon_view.unselect_all (); + web_items.unselect_all (); }); - image.deleted.connect ((parent) => { - this.icon_view.remove (parent); + web_item.deleted.connect (() => { app_deleted (); }); - icon_view.add (image); - icon_view.show_all (); + web_items.add (web_item); + web_items.show_all (); } public void select_last_item () { - icon_view.select_child (icon_view.get_child_at_index ((int)icon_view.get_children ().length () - 1)); + web_items.select_child (web_items.get_child_at_index ((int)web_items.get_children ().length () - 1)); } public void select_first_item () { - icon_view.select_child (icon_view.get_child_at_index (0)); + web_items.select_child (web_items.get_child_at_index (0)); } public void update_button (GLib.DesktopAppInfo app) { - foreach (var item in icon_view.get_children ()) { - if ((item as Gtk.FlowBoxChild).get_child () is ApplicationIcon) { - var app_icon = (item as Gtk.FlowBoxChild).get_child () as ApplicationIcon; + foreach (var item in web_items.get_children ()) { + if (item is WebItem) { + var app_icon = item as WebItem; if (app_icon.desktop_file.name == app.get_display_name ()) { app_icon.set_new_desktopfile (new DesktopFile.from_desktopappinfo (app)); - icon_view.select_child (item as Gtk.FlowBoxChild); + web_items.select_child (item as Gtk.FlowBoxChild); break; } } diff --git a/src/Widgets/ApplicationIcon.vala b/src/Widgets/WebItem.vala similarity index 62% rename from src/Widgets/ApplicationIcon.vala rename to src/Widgets/WebItem.vala index 193e5aa..7fde4cc 100644 --- a/src/Widgets/ApplicationIcon.vala +++ b/src/Widgets/WebItem.vala @@ -26,58 +26,56 @@ * Authored by: Artem Anufrij */ -namespace Webpin { - public class ApplicationIcon : Gtk.Overlay { +namespace Webpin.Widgets { + public class WebItem : Gtk.FlowBoxChild { Gtk.Image image; Gtk.Label label; - Gtk.Box box; internal DesktopFile desktop_file { get; private set; } - public signal void deleted (Gtk.Container? parent); + public signal void deleted (); public signal void edit_request (DesktopFile desktop_file); - public ApplicationIcon (GLib.DesktopAppInfo app) { + public WebItem (GLib.DesktopAppInfo app) { this.desktop_file = new DesktopFile.from_desktopappinfo (app); + build_ui (); + } - hexpand = false; - vexpand = false; + private void build_ui () { + var content = new Gtk.Grid (); + content.margin = 12; + content.halign = Gtk.Align.CENTER; + content.row_spacing = 6; + image = new Gtk.Image (); label = new Gtk.Label (this.desktop_file.name); set_icon (this.desktop_file.icon); - this.margin = 6; - this.margin_start = 20; - this.margin_end = 20; - var menu = new ActionMenu (); menu.halign = Gtk.Align.CENTER; menu.delete_clicked.connect (() => { remove_application (); }); menu.edit_clicked.connect (() => { edit_request (desktop_file); }); - box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - box.pack_start (image, false, false, 0); - box.pack_start (label, false, false, 0); - box.pack_start (menu, false, false, 0); - - box.hexpand = false; - box.vexpand = false; + content.attach (image, 0, 0); + content.attach (label, 0, 1); + content.attach (menu, 0, 2); var event_box = new Gtk.EventBox (); - event_box.add (box); + event_box.add (content); event_box.events |= Gdk.EventMask.ENTER_NOTIFY_MASK|Gdk.EventMask.LEAVE_NOTIFY_MASK; event_box.enter_notify_event.connect ((event) => { - menu.set_reveal_child (true); + menu.opacity = 0.5; return false; }); 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); + } + menu.opacity = 0; return false; }); @@ -97,29 +95,9 @@ namespace Webpin { } catch (Error e) { warning (e.message); } - int new_height = 64; - int new_width = 64; - int margin_vertical = 0; - int margin_horizontal = 0; - - if (pix.height > pix.width) { - new_width = new_width * pix.width / pix.height; - margin_horizontal = (new_height - new_width) / 2; - } else if (pix.height < pix.width) { - new_height = new_height * pix.height / pix.width; - margin_vertical = (new_width - new_height) / 2; - } - if (image == null) - image = new Gtk.Image.from_pixbuf (pix.scale_simple (new_width, new_height, Gdk.InterpType.BILINEAR)); - 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; - image.margin_right = margin_horizontal; - image.margin_left = margin_horizontal; + pix = Services.DesktopFilesManager.align_and_scale_pixbuf (pix, 64); + image.set_from_pixbuf (pix); } else { - image = new Gtk.Image (); image.icon_name = icon; image.pixel_size = 64; } @@ -127,12 +105,12 @@ namespace Webpin { private void remove_application () { desktop_file.delete_file (); - deleted (this.get_parent()); + deleted (); this.destroy (); } } - public class ActionMenu : Gtk.Revealer { + public class ActionMenu : Gtk.Grid { public signal void delete_clicked (); public signal void edit_clicked (); @@ -148,14 +126,9 @@ namespace Webpin { edit_button.relief = Gtk.ReliefStyle.NONE; edit_button.clicked.connect (() => { edit_clicked (); }); - var buttons = new Gtk.Grid (); - buttons.orientation = Gtk.Orientation.HORIZONTAL; - buttons.add (edit_button); - buttons.add (delete_button); - buttons.opacity = 0.5; - - this.transition_type = Gtk.RevealerTransitionType.CROSSFADE; - this.add (buttons); + this.add (edit_button); + this.add (delete_button); + this.opacity = 0; } } } diff --git a/src/Windows/WebApp.vala b/src/Windows/WebApp.vala new file mode 100644 index 0000000..056015d --- /dev/null +++ b/src/Windows/WebApp.vala @@ -0,0 +1,234 @@ +/*- + * 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.Windows { + public class WebApp : Gtk.Window { + + Gdk.WindowState current_state; + + Widgets.Browser browser; + Gtk.Spinner spinner; + + public DesktopFile desktop_file { get; private set; } + + public WebApp (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) { + set_color (color); + } + browser = new Widgets.Browser (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 URL into clipboard"); + copy_url.clicked.connect (() => { + Gtk.Clipboard.get_default (Gdk.Display.get_default ()).set_text (browser.web_view.uri, -1); + }); + headerbar.pack_end (copy_url); + + spinner = new Gtk.Spinner (); + spinner.set_size_request (16, 16); + headerbar.pack_end (spinner); + + var stay_open = new Gtk.ToggleButton (); + stay_open.active = desktop_file.hide_on_close; + stay_open.tooltip_text = _("Run in background if closed"); + stay_open.image = new Gtk.Image.from_icon_name ("view-pin-symbolic", Gtk.IconSize.MENU); + stay_open.toggled.connect (() => { + 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); + + this.delete_event.connect (() => { + 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; + }); + + browser.external_request.connect ((action) => { + debug ("Web app external request: %s", action.get_request ().uri); + try { + Process.spawn_command_line_async ("xdg-open " + action.get_request ().uri); + } catch (Error e) { + warning (e.message); + } + }); + + browser.desktop_notification.connect ((title, body, icon) => { + var desktop_notification = new Notification (title); + desktop_notification.set_body (body); + desktop_notification.set_icon (icon); + desktop_notification.add_button_with_target_value (_("Open %s").printf (desktop_file.name), "app.open-web-app", new GLib.Variant.string (desktop_file.url)); + WebpinApp.instance.send_notification (null, desktop_notification); + }); + + browser.request_begin.connect (() => { + spinner.active = true; + }); + + browser.request_finished.connect (() => { + spinner.active = false; + }); + + browser.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 (browser); + + load_settings (); + + this.show_all (); + } + + 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 (current_state.to_string () == Gdk.WindowState.FULLSCREEN.to_string ()) { + this.unfullscreen (); + } else { + this.fullscreen (); + } + } + + 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 (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) { + browser.web_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) { + 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) { + browser.web_view.zoom_level += 0.1; + desktop_file.edit_property ("X-Webpin-WindowZoom", browser.web_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) { + browser.web_view.zoom_level -= 0.1; + desktop_file.edit_property ("X-Webpin-WindowZoom", browser.web_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) { + browser.web_view.zoom_level = 1; + desktop_file.edit_property ("X-Webpin-WindowZoom", browser.web_view.zoom_level.to_string ()); + return true; + } + break; + case Gdk.Key.F5: + if (Gdk.ModifierType.CONTROL_MASK in event.state) { + browser.web_view.reload (); + } else { + browser.web_view.reload_bypass_cache (); + } + return true; + case Gdk.Key.Left: + if (Gdk.ModifierType.MOD1_MASK in event.state) { + browser.web_view.go_back (); + return true; + } + break; + case Gdk.Key.Right: + if (Gdk.ModifierType.MOD1_MASK in event.state) { + browser.web_view.go_forward (); + return true; + } + break; + } + + return (base.key_press_event != null) ? base.key_press_event (event) : true; + } + } +}