add and use the concept of a "global overlay"
a problem with my previous merge was that the top overlay was always removed when the install finished, but if the user had opened a help topic in the mean time that was the wrong thing to do. also if the view was switched under the install notification (which is a bit unlikely but could happen) the dialog would disappear. this finally pushed me to generically handle "global overlays" that are not tied to the underlying, controller-controlled view. there are a few of these now: * help dialogs * error reports * the "are you sure?" install confirmation * now the install notification this adds an api for adding and removing them, and the api for removing them includes which overlay to remove.
This commit is contained in:
parent
2a53fce963
commit
2aa3bea55e
|
@ -35,6 +35,7 @@ from subiquitycore.async_helpers import (
|
|||
)
|
||||
from subiquitycore.controller import Skip
|
||||
from subiquitycore.core import Application
|
||||
from subiquitycore.view import BaseView
|
||||
|
||||
from subiquity.controllers.error import (
|
||||
ErrorReportKind,
|
||||
|
@ -128,7 +129,7 @@ class Subiquity(Application):
|
|||
["subiquity"], self.subiquity_event, seek=True)
|
||||
super().__init__(opts)
|
||||
self.install_lock_file = Lockfile(self.state_path("installing"))
|
||||
self.install_running = None
|
||||
self.global_overlays = []
|
||||
self.block_log_dir = block_log_dir
|
||||
self.kernel_cmdline = shlex.split(opts.kernel_cmdline)
|
||||
if opts.snaps_from_examples:
|
||||
|
@ -168,16 +169,15 @@ class Subiquity(Application):
|
|||
InstallRunning,
|
||||
)
|
||||
tty = self.install_lock_file.read_content()
|
||||
self.install_running = InstallRunning(self.ui.body, self, tty)
|
||||
self.ui.body.show_stretchy_overlay(self.install_running)
|
||||
schedule_task(self._hide_install_running())
|
||||
install_running = InstallRunning(self.ui.body, self, tty)
|
||||
self.add_global_overlay(install_running)
|
||||
schedule_task(self._hide_install_running(install_running))
|
||||
|
||||
async def _hide_install_running(self):
|
||||
async def _hide_install_running(self, install_running):
|
||||
# Wait until the install has completed...
|
||||
async with self.install_lock_file.shared():
|
||||
# And remove the overlay.
|
||||
self.install_running = None
|
||||
self.ui.body.remove_overlay()
|
||||
self.remove_global_overlay(install_running)
|
||||
|
||||
def restart(self, remove_last_screen=True):
|
||||
if remove_last_screen:
|
||||
|
@ -343,7 +343,7 @@ class Subiquity(Application):
|
|||
InstallConfirmation,
|
||||
)
|
||||
self._cancel_show_progress()
|
||||
self.ui.body.show_stretchy_overlay(
|
||||
self.add_global_overlay(
|
||||
InstallConfirmation(self.ui.body, self))
|
||||
else:
|
||||
yes = _('yes')
|
||||
|
@ -371,12 +371,22 @@ class Subiquity(Application):
|
|||
return True
|
||||
return bool(self.autoinstall_config.get('interactive-sections'))
|
||||
|
||||
def add_global_overlay(self, overlay):
|
||||
self.global_overlays.append(overlay)
|
||||
if isinstance(self.ui.body, BaseView):
|
||||
self.ui.body.show_stretchy_overlay(overlay)
|
||||
|
||||
def remove_global_overlay(self, overlay):
|
||||
self.global_overlays.remove(overlay)
|
||||
if isinstance(self.ui.body, BaseView):
|
||||
self.ui.body.remove_overlay(overlay)
|
||||
|
||||
def select_initial_screen(self, index):
|
||||
super().select_initial_screen(index)
|
||||
for report in self.controllers.Error.reports:
|
||||
if report.kind == ErrorReportKind.UI and not report.seen:
|
||||
self.report_to_show = report
|
||||
return
|
||||
self.show_error_report(report)
|
||||
break
|
||||
super().select_initial_screen(index)
|
||||
|
||||
def select_screen(self, new):
|
||||
if new.interactive():
|
||||
|
@ -390,12 +400,6 @@ class Subiquity(Application):
|
|||
return
|
||||
self.progress_showing = False
|
||||
super().select_screen(new)
|
||||
if self.report_to_show is not None:
|
||||
log.debug("showing new error %r", self.report_to_show.base)
|
||||
self.show_error_report(self.report_to_show)
|
||||
self.report_to_show = None
|
||||
if self.install_running is not None:
|
||||
self.ui.body.show_stretchy_overlay(self.install_running)
|
||||
elif self.autoinstall_config and not new.autoinstall_applied:
|
||||
if self.interactive() and self.show_progress_handle is None:
|
||||
self.ui.block_input = True
|
||||
|
@ -520,12 +524,12 @@ class Subiquity(Application):
|
|||
|
||||
def show_error_report(self, report):
|
||||
log.debug("show_error_report %r", report.base)
|
||||
w = getattr(self.ui.body._w, 'top_w', None)
|
||||
if isinstance(w, ErrorReportStretchy):
|
||||
# Don't show an error if already looking at one.
|
||||
return
|
||||
self.ui.body.show_stretchy_overlay(
|
||||
ErrorReportStretchy(self, self.ui.body, report))
|
||||
if isinstance(self.ui.body, BaseView):
|
||||
w = getattr(self.ui.body._w, 'stretchy', None)
|
||||
if isinstance(w, ErrorReportStretchy):
|
||||
# Don't show an error if already looking at one.
|
||||
return
|
||||
self.add_global_overlay(ErrorReportStretchy(self, report))
|
||||
|
||||
def make_autoinstall(self):
|
||||
config = {}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import logging
|
||||
|
||||
from subiquitycore.ui.frame import SubiquityCoreUI
|
||||
from subiquitycore.view import BaseView
|
||||
|
||||
from subiquity.ui.views.help import HelpButton
|
||||
|
||||
|
@ -28,9 +29,16 @@ class SubiquityUI(SubiquityCoreUI):
|
|||
block_input = False
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.right_icon = HelpButton(app)
|
||||
super().__init__()
|
||||
|
||||
def keypress(self, size, key):
|
||||
if not self.block_input:
|
||||
return super().keypress(size, key)
|
||||
|
||||
def set_body(self, widget):
|
||||
super().set_body(widget)
|
||||
if isinstance(widget, BaseView):
|
||||
for overlay in self.app.global_overlays:
|
||||
widget.show_stretchy_overlay(overlay)
|
||||
|
|
|
@ -54,10 +54,12 @@ from subiquity.controllers.error import (
|
|||
log = logging.getLogger('subiquity.ui.error')
|
||||
|
||||
|
||||
def close_btn(parent, label=None):
|
||||
def close_btn(stretchy, label=None):
|
||||
if label is None:
|
||||
label = _("Close")
|
||||
return other_btn(label, on_press=lambda sender: parent.remove_overlay())
|
||||
return other_btn(
|
||||
label,
|
||||
on_press=lambda sender: stretchy.app.remove_global_overlay(stretchy))
|
||||
|
||||
|
||||
error_report_intros = {
|
||||
|
@ -129,17 +131,16 @@ If you want to help improve the installer, you can send an error report.
|
|||
|
||||
class ErrorReportStretchy(Stretchy):
|
||||
|
||||
def __init__(self, app, parent, report, interrupting=True):
|
||||
def __init__(self, app, report, interrupting=True):
|
||||
self.app = app
|
||||
self.report = report
|
||||
self.parent = parent
|
||||
self.interrupting = interrupting
|
||||
|
||||
self.btns = {
|
||||
'cancel': other_btn(
|
||||
_("Cancel upload"), on_press=self.cancel_upload),
|
||||
'close': close_btn(parent, _("Close report")),
|
||||
'continue': close_btn(parent, _("Continue")),
|
||||
'close': close_btn(self, _("Close report")),
|
||||
'continue': close_btn(self, _("Continue")),
|
||||
'debug_shell': other_btn(
|
||||
_("Switch to a shell"), on_press=self.debug_shell),
|
||||
'restart': other_btn(
|
||||
|
@ -247,7 +248,7 @@ class ErrorReportStretchy(Stretchy):
|
|||
self.pile.focus_position += 1
|
||||
|
||||
def debug_shell(self, sender):
|
||||
self.parent.remove_overlay()
|
||||
self.app.debug_shell()
|
||||
|
||||
def restart(self, sender):
|
||||
self.app.restart()
|
||||
|
@ -273,9 +274,8 @@ class ErrorReportStretchy(Stretchy):
|
|||
|
||||
class ErrorReportListStretchy(Stretchy):
|
||||
|
||||
def __init__(self, app, parent):
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.parent = parent
|
||||
rows = [
|
||||
TableRow([
|
||||
Text(""),
|
||||
|
@ -295,13 +295,13 @@ class ErrorReportListStretchy(Stretchy):
|
|||
Text(""),
|
||||
self.table,
|
||||
Text(""),
|
||||
button_pile([close_btn(parent)]),
|
||||
button_pile([close_btn(self)]),
|
||||
]
|
||||
super().__init__("", widgets, 2, 2)
|
||||
|
||||
def open_report(self, sender, report):
|
||||
self.parent.show_stretchy_overlay(
|
||||
ErrorReportStretchy(self.app, self.parent, report, False))
|
||||
self.app.add_global_overlay(
|
||||
ErrorReportStretchy(self.app, report, False))
|
||||
|
||||
def state_for_report(self, report):
|
||||
if report.seen:
|
||||
|
|
|
@ -61,9 +61,10 @@ from subiquity.ui.views.error import ErrorReportListStretchy
|
|||
log = logging.getLogger('subiquity.ui.help')
|
||||
|
||||
|
||||
def close_btn(parent):
|
||||
def close_btn(app, stretchy):
|
||||
return other_btn(
|
||||
_("Close"), on_press=lambda sender: parent.remove_overlay())
|
||||
_("Close"),
|
||||
on_press=lambda sender: app.remove_global_overlay(stretchy))
|
||||
|
||||
|
||||
ABOUT_INSTALLER = _("""
|
||||
|
@ -154,7 +155,7 @@ def ssh_help_texts(ips, password):
|
|||
|
||||
class SimpleTextStretchy(Stretchy):
|
||||
|
||||
def __init__(self, parent, title, *texts):
|
||||
def __init__(self, app, title, *texts):
|
||||
widgets = []
|
||||
|
||||
for text in texts:
|
||||
|
@ -164,7 +165,7 @@ class SimpleTextStretchy(Stretchy):
|
|||
|
||||
widgets.extend([
|
||||
Text(""),
|
||||
button_pile([close_btn(parent)]),
|
||||
button_pile([close_btn(app, self)]),
|
||||
])
|
||||
super().__init__(title, widgets, 0, len(widgets)-1)
|
||||
|
||||
|
@ -191,7 +192,7 @@ DRY_RUN_KEYS = (
|
|||
|
||||
class GlobalKeyStretchy(Stretchy):
|
||||
|
||||
def __init__(self, app, parent):
|
||||
def __init__(self, app):
|
||||
rows = []
|
||||
for key, text in GLOBAL_KEYS:
|
||||
rows.append(TableRow([Text(_(key)), Text(_(text))]))
|
||||
|
@ -210,7 +211,7 @@ class GlobalKeyStretchy(Stretchy):
|
|||
('pack', table),
|
||||
]),
|
||||
Text(""),
|
||||
button_pile([close_btn(parent)]),
|
||||
button_pile([close_btn(app, self)]),
|
||||
]
|
||||
super().__init__(_("Shortcut Keys"), widgets, 0, 2)
|
||||
|
||||
|
@ -339,18 +340,18 @@ class HelpMenu(WidgetWrap):
|
|||
|
||||
# We don't let help dialogs pile up: if one is already
|
||||
# showing, remove it before showing the new one.
|
||||
if self.parent.showing_something:
|
||||
ui.body.remove_overlay()
|
||||
self.parent.showing_something = True
|
||||
if self.parent.current_help:
|
||||
self.parent.app.remove_global_overlay(self.parent.current_help)
|
||||
self.parent.current_help = stretchy
|
||||
fp, ui.pile.focus_position = ui.pile.focus_position, 1
|
||||
|
||||
def on_close():
|
||||
self.parent.showing_something = False
|
||||
self.parent.current_help = None
|
||||
ui.pile.focus_position = fp
|
||||
|
||||
connect_signal(stretchy, 'closed', on_close)
|
||||
|
||||
ui.body.show_stretchy_overlay(stretchy)
|
||||
self.parent.app.add_global_overlay(stretchy)
|
||||
|
||||
def _about(self, sender=None):
|
||||
info = lsb_release()
|
||||
|
@ -364,7 +365,7 @@ class HelpMenu(WidgetWrap):
|
|||
})
|
||||
self._show_overlay(
|
||||
SimpleTextStretchy(
|
||||
self.parent.app.ui.body,
|
||||
self.parent.app,
|
||||
_("About the installer"),
|
||||
template.format(**info)))
|
||||
|
||||
|
@ -382,7 +383,7 @@ class HelpMenu(WidgetWrap):
|
|||
|
||||
self._show_overlay(
|
||||
SimpleTextStretchy(
|
||||
self.parent.app.ui.body,
|
||||
self.parent.app,
|
||||
_("Help on SSH access"),
|
||||
*texts,
|
||||
))
|
||||
|
@ -392,16 +393,13 @@ class HelpMenu(WidgetWrap):
|
|||
def cb(sender=None):
|
||||
self._show_overlay(
|
||||
SimpleTextStretchy(
|
||||
self.parent.app.ui.body,
|
||||
self.parent.app,
|
||||
local_title,
|
||||
local_doc))
|
||||
return cb
|
||||
|
||||
def _shortcuts(self, sender):
|
||||
self._show_overlay(
|
||||
GlobalKeyStretchy(
|
||||
self.parent.app,
|
||||
self.parent.app.ui.body))
|
||||
self._show_overlay(GlobalKeyStretchy(self.parent.app))
|
||||
|
||||
def _debug_shell(self, sender):
|
||||
self.parent.app.debug_shell()
|
||||
|
@ -410,10 +408,7 @@ class HelpMenu(WidgetWrap):
|
|||
self.parent.app.toggle_color()
|
||||
|
||||
def _show_errors(self, sender):
|
||||
self._show_overlay(
|
||||
ErrorReportListStretchy(
|
||||
self.parent.app,
|
||||
self.parent.app.ui.body))
|
||||
self._show_overlay(ErrorReportListStretchy(self.parent.app))
|
||||
|
||||
|
||||
def get_installer_password(dry_run=False):
|
||||
|
@ -439,7 +434,7 @@ class HelpButton(PopUpLauncher):
|
|||
self.app = app
|
||||
self.btn = header_btn(_("Help"), on_press=self._open)
|
||||
self.ssh_password = None
|
||||
self.showing_something = False
|
||||
self.current_help = None
|
||||
super().__init__(self.btn)
|
||||
|
||||
def _open(self, sender):
|
||||
|
|
Loading…
Reference in New Issue