diff --git a/panels/system.py b/panels/system.py index ad9196ee..6bf9a60d 100644 --- a/panels/system.py +++ b/panels/system.py @@ -3,7 +3,7 @@ import logging import os gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gdk, GLib +from gi.repository import Gtk, Gdk, GLib, Pango from datetime import datetime from ks_includes.KlippyGcodes import KlippyGcodes @@ -59,13 +59,14 @@ class SystemPanel(ScreenPanel): scroll = Gtk.ScrolledWindow() scroll.set_property("overlay-scrolling", False) scroll.set_vexpand(True) + scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) infogrid = Gtk.Grid() infogrid.get_style_context().add_class("system-program-grid") update_resp = self._screen.apiclient.send_request("machine/update/status") self.update_status = False - if update_resp is False: + if not update_resp: logging.info("No update manager configured") else: self.update_status = update_resp['result'] @@ -79,9 +80,7 @@ class SystemPanel(ScreenPanel): self.labels["%s_status" % prog] = self._gtk.Button() self.labels["%s_status" % prog].set_hexpand(False) - self.labels["%s_status" % prog].connect("clicked", self.show_commit_history, prog) - self.labels["%s_info" % prog] = self._gtk.ButtonImage("info", None, None, .7, .7) - self.labels["%s_info" % prog].connect("clicked", self.show_commit_history, prog) + self.labels["%s_status" % prog].connect("clicked", self.show_update_info, prog) if prog in ALLOWED_SERVICES: self.labels["%s_restart" % prog] = self._gtk.ButtonImage("refresh", None, None, .7, .7) @@ -119,7 +118,7 @@ class SystemPanel(ScreenPanel): def get_updates(self): update_resp = self._screen.apiclient.send_request("machine/update/status") - if update_resp is False: + if not update_resp: logging.info("No update manager configured") else: self.update_status = update_resp['result'] @@ -131,14 +130,16 @@ class SystemPanel(ScreenPanel): def process_update(self, action, data): if action == "notify_update_response": logging.info("Update: %s" % data) - if 'application' in data and data['application'] == self.update_prog: + if 'application' in data: self.labels['update_progress'].set_text(self.labels['update_progress'].get_text().strip() + "\n" + data['message'] + "\n") + self.labels['update_progress'].set_ellipsize(True) + self.labels['update_progress'].set_ellipsize(Pango.EllipsizeMode.END) adjustment = self.labels['update_scroll'].get_vadjustment() adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()) adjustment = self.labels['update_scroll'].show_all() - if data['complete'] is True: + if data['complete']: self.update_dialog.set_response_sensitive(Gtk.ResponseType.CANCEL, True) def restart(self, widget, program): @@ -148,48 +149,92 @@ class SystemPanel(ScreenPanel): logging.info("Restarting service: %s" % program) self._screen._ws.send_method("machine.services.restart", {"service": program}) - def show_commit_history(self, widget, program): + def show_update_info(self, widget, program): _ = self.lang.gettext - if self.update_status is False or program not in self.update_status['version_info']: + if not self.update_status or program not in self.update_status['version_info']: return info = self.update_status['version_info'][program] - if info['version'] == info['remote_version']: - return - - buttons = [ - {"name": _("Update"), "response": Gtk.ResponseType.OK}, - {"name": _("Go Back"), "response": Gtk.ResponseType.CANCEL} - ] scroll = Gtk.ScrolledWindow() + scroll.set_property("overlay-scrolling", False) scroll.set_hexpand(True) scroll.set_vexpand(True) + scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) grid = Gtk.Grid() - grid.set_halign(Gtk.Align.START) + grid.set_column_homogeneous(True) + grid.set_halign(Gtk.Align.CENTER) + grid.set_valign(Gtk.Align.CENTER) i = 0 - date = "" - for c in info['commits_behind']: - ndate = datetime.fromtimestamp(int(c['date'])).strftime("%b %d") - if date != ndate: - date = ndate - label = Gtk.Label("") - label.set_markup("%s\n" % date) - label.set_halign(Gtk.Align.START) + label = Gtk.Label() + if "configured_type" in info: + if info['configured_type'] == 'git_repo': + if not info['is_valid'] or info['is_dirty']: + label.set_markup("Do you want to recover %s?" % program) + grid.attach(label, 0, i, 1, 1) + scroll.add(grid) + recoverybuttons = [ + {"name": _("Recover Hard"), "response": Gtk.ResponseType.OK}, + {"name": _("Recover Soft"), "response": Gtk.ResponseType.APPLY}, + {"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL} + ] + dialog = self._gtk.Dialog(self._screen, recoverybuttons, scroll, self.reset_confirm, program) + return + else: + if info['version'] == info['remote_version']: + return + label.set_markup("Outdated by %d commits:\n" % len(info['commits_behind'])) + grid.attach(label, 0, i, 1, 1) + i = i + 1 + date = "" + for c in info['commits_behind']: + ndate = datetime.fromtimestamp(int(c['date'])).strftime("%b %d") + if date != ndate: + date = ndate + label = Gtk.Label() + label.set_markup("%s\n" % date) + label.set_halign(Gtk.Align.START) + grid.attach(label, 0, i, 1, 1) + i = i + 1 + + label = Gtk.Label() + label.set_ellipsize(True) + label.set_ellipsize(Pango.EllipsizeMode.END) + label.set_markup("%s\n%s\n" % (c['subject'], c['author'])) + label.set_halign(Gtk.Align.START) + grid.attach(label, 0, i, 1, 1) + i = i + 1 + else: + label.set_markup("%s will be updated to version: %s" % (program.capitalize(), + info['remote_version'])) grid.attach(label, 0, i, 1, 1) i = i + 1 - - label = Gtk.Label() - label.set_markup("%s\n%s %s %s\n" % (c['subject'], c['author'], _("Commited"), "2 days ago")) - label.set_hexpand(True) - label.set_halign(Gtk.Align.START) - grid.attach(label, 0, i, 1, 1) + if "package_count" in info: + label.set_markup("%d Packages will be updated:\n" % info['package_count']) + label.set_halign(Gtk.Align.CENTER) + grid.attach(label, 0, i, 3, 1) i = i + 1 + j = 0 + for c in info["package_list"]: + label = Gtk.Label() + label.set_markup(" %s " % c) + label.set_halign(Gtk.Align.START) + label.set_ellipsize(True) + label.set_ellipsize(Pango.EllipsizeMode.END) + pos = (j % 3) + grid.attach(label, pos, i, 1, 1) + j = j + 1 + if (pos == 2): + i = i + 1 scroll.add(grid) + buttons = [ + {"name": _("Update"), "response": Gtk.ResponseType.OK}, + {"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL} + ] dialog = self._gtk.Dialog(self._screen, buttons, scroll, self.update_confirm, program) def update_confirm(self, widget, response_id, program): @@ -198,13 +243,55 @@ class SystemPanel(ScreenPanel): self.update_program(self, program) widget.destroy() + def reset_confirm(self, widget, response_id, program): + if response_id == Gtk.ResponseType.OK: + logging.debug("Recovering hard %s" % program) + self.reset_repo(self, program, True) + if response_id == Gtk.ResponseType.APPLY: + logging.debug("Recovering soft %s" % program) + self.reset_repo(self, program, False) + widget.destroy() + + def reset_repo(self, widget, program, hard): + if self._screen.is_updating(): + return + + _ = self.lang.gettext + + buttons = [ + {"name": _("Finish"), "response": Gtk.ResponseType.CANCEL} + ] + + scroll = Gtk.ScrolledWindow() + scroll.set_property("overlay-scrolling", False) + scroll.set_hexpand(True) + scroll.set_vexpand(True) + scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) + + self.labels['update_progress'] = Gtk.Label("%s %s..." % (_("Starting recovery for"), program)) + self.labels['update_progress'].set_halign(Gtk.Align.START) + self.labels['update_progress'].set_valign(Gtk.Align.START) + scroll.add(self.labels['update_progress']) + self.labels['update_scroll'] = scroll + + dialog = self._gtk.Dialog(self._screen, buttons, scroll, self.finish_updating) + dialog.set_response_sensitive(Gtk.ResponseType.CANCEL, False) + + self.update_prog = program + self.update_dialog = dialog + + logging.info("Sending machine.update.recover name: %s" % program) + + self._screen._ws.send_method("machine.update.recover", {"name": program, "hard": str(hard)}) + self._screen.set_updating(True) + def update_program(self, widget, program): if self._screen.is_updating(): return _ = self.lang.gettext - if self.update_status is False or program not in self.update_status['version_info']: + if not self.update_status or program not in self.update_status['version_info']: return info = self.update_status['version_info'][program] @@ -221,10 +308,12 @@ class SystemPanel(ScreenPanel): ] scroll = Gtk.ScrolledWindow() + scroll.set_property("overlay-scrolling", False) scroll.set_hexpand(True) scroll.set_vexpand(True) + scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) - self.labels['update_progress'] = Gtk.Label("%s %s%s" % (_("Starting update for"), program, _("..."))) + self.labels['update_progress'] = Gtk.Label("%s %s..." % (_("Starting update for"), program)) self.labels['update_progress'].set_halign(Gtk.Align.START) self.labels['update_progress'].set_valign(Gtk.Align.START) scroll.add(self.labels['update_progress']) @@ -253,17 +342,40 @@ class SystemPanel(ScreenPanel): info = self.update_status['version_info'][p] logging.info("%s: %s" % (p, info)) + if p != "system": version = (info['full_version_string'] if "full_version_string" in info else info['version']) - - if info['version'] == info['remote_version']: - self.labels[p].set_markup("%s\n%s" % (p, version)) - self.labels["%s_status" % p].set_label(_("Up To Date")) - self.labels["%s_status" % p].set_sensitive(False) + if info['configured_type'] == 'git_repo': + if info['is_valid'] and not info['is_dirty']: + if info['version'] == info['remote_version']: + self.labels[p].set_markup("%s\n%s" % (p, version)) + self.labels["%s_status" % p].set_label(_("Up To Date")) + self.labels["%s_status" % p].get_style_context().remove_class('update') + self.labels["%s_status" % p].get_style_context().remove_class('invalid') + self.labels["%s_status" % p].set_sensitive(False) + else: + self.labels[p].set_markup("%s\n%s -> %s" % (p, version, info['remote_version'])) + self.labels["%s_status" % p].set_label(_("Update")) + self.labels["%s_status" % p].get_style_context().add_class('update') + self.labels["%s_status" % p].set_sensitive(True) + else: + self.labels[p].set_markup("%s\n%s" % (p, version)) + self.labels["%s_status" % p].set_label(_("Invalid")) + self.labels["%s_status" % p].get_style_context().add_class('invalid') + self.labels["%s_status" % p].set_sensitive(True) else: - self.labels[p].set_markup("%s\n%s -> %s" % (p, version, info['remote_version'])) - self.labels["%s_status" % p].set_label(_("Update")) - self.labels["%s_status" % p].set_sensitive(True) + if info['version'] == info['remote_version']: + self.labels[p].set_markup("%s\n%s" % (p, version)) + self.labels["%s_status" % p].set_label(_("Up To Date")) + self.labels["%s_status" % p].get_style_context().remove_class('update') + self.labels["%s_status" % p].set_sensitive(False) + else: + self.labels[p].set_markup("%s\n%s -> %s" % (p, version, info['remote_version'])) + self.labels["%s_status" % p].set_label(_("Update")) + self.labels["%s_status" % p].get_style_context().add_class('update') + self.labels["%s_status" % p].set_sensitive(True) + + else: self.labels[p].set_markup("System") if info['package_count'] == 0: @@ -271,6 +383,7 @@ class SystemPanel(ScreenPanel): self.labels["%s_status" % p].set_sensitive(False) else: self.labels["%s_status" % p].set_label(_("Update")) + self.labels["%s_status" % p].get_style_context().add_class('update') self.labels["%s_status" % p].set_sensitive(True) def restart_klippy(self, widget, type=None): diff --git a/styles/base.css b/styles/base.css index 55448467..4211100f 100644 --- a/styles/base.css +++ b/styles/base.css @@ -56,11 +56,29 @@ button.file-list { margin: 0; } +button.update { + background: #009384; + border: .4em solid #009384; + border-radius: 0.4em; + font-weight: bold; +} + +button.invalid { + background: #e61e1e; + border: .4em solid #e61e1e; + border-radius: 0.4em; + font-weight: bold; +} + combobox box button { border: .05em solid #cccccc; padding: .5em 1em; } +combobox arrow { + min-width: 1em; +} + entry { font-size: 1em; background-color: #20292F; @@ -112,6 +130,11 @@ scale mark { color: white; } +scale trough slider { + min-height: 2em; + min-width: 2em; +} + scrollbar, scrollbar button, scrollbar trough { border: none; background-color: #13181C; @@ -354,7 +377,7 @@ trough { .system-program-grid { padding: 0.25em; - padding-right: 1em; + padding-right: .5em; padding-bottom: 0; } diff --git a/styles/colorized/style.css b/styles/colorized/style.css index d1c2113a..c32e9d3c 100644 --- a/styles/colorized/style.css +++ b/styles/colorized/style.css @@ -46,7 +46,7 @@ button.color4 { border-radius: 1em; } -button.color1:active, button.color2:active, button.color3:active, button.color4:active { +button.color1:active, button.color2:active, button.color3:active, button.color4:active, button.update:active, button.invalid:active, .dialog button:active { border-style: none; } @@ -54,15 +54,40 @@ button.active { background-color: #cb4b16; /*solarized-orange*/ } +button.update { + background-color: #073642; /*base02*/ + border: 0; + border-bottom: .3em solid; + border-bottom-color: #859900; /*solarized-green*/ + border-radius: .75em; +} + +button.invalid { + background-color: #073642; /*base02*/ + border: 0; + border-bottom: .3em solid; + border-bottom-color: #dc322f; /*solarized-red*/ + border-radius: .75em; +} + combobox box button { background-color: #073642; /*base02*/ border-color: #002b36; /*base03*/ } switch { - /* background-color: #073642; base02 */ + background-color: #073642; /* base02 */ + border-color: #073642; /* base02 */ + border-radius: 3em; } +switch:checked { + background-color: #859900; /*solarized-green*/ +} + +switch slider { + border: 0; +} entry { background-color: #073642; /*base02*/ border-color: #002b36; /*base03*/ @@ -98,7 +123,8 @@ trough highlight, trough progress { background-color: #6c71c4; /*solarized-violet*/ color: #fdf6e3; /*base3*/ border-color: #002b36; /*base03*/ - border-radius: 1em; + border-top-left-radius: 1em; + border-bottom-left-radius: 1em; } scale-mark { @@ -110,7 +136,7 @@ scrollbar, scrollbar button, scrollbar trough { } scrollbar slider { - background-color: #586e75; /*base01*/ + background-color: #073642; /*base02*/ } textview .time { @@ -127,9 +153,18 @@ textview .time { } .dialog button { + background-color: #073642; /*base02*/ border-bottom-color: #268bd2; /*solarized-cyan*/ + border-radius: .75em; } +.dialog button:nth-child(1) { + border-bottom-color: #859900; /*solarized-green*/ +} + +.dialog button:nth-child(2) { + border-bottom-color: #dc322f; /*solarazed-red*/ +} .tempbutton_top, .tempbutton, .tempbutton_bottom, .distbutton_top, .distbutton, .distbutton_bottom { border-color: #002b36; /*base03*/ background-color: #073642; /*base02*/ diff --git a/styles/z-bolt/style.css b/styles/z-bolt/style.css index b1f73f95..78179092 100644 --- a/styles/z-bolt/style.css +++ b/styles/z-bolt/style.css @@ -38,6 +38,16 @@ button.active { background-color: #20303D; } +button.update { + background: #009384; + border-color: #009384; +} + +button.invalid { + background: #e61e1e; + border-color: #e61e1e; +} + combobox box button { border-color: #cccccc; } @@ -98,8 +108,8 @@ textview .time { } .dialog { - border: black; - background-color: black; + border: #13181C; + background-color: #13181C; } .dialog button {