From f77a861c38647efcfdb5843b2d0b8faf2daf107c Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 13 Mar 2018 20:56:13 +1300 Subject: [PATCH 1/3] pop up a little dialog while the keyboard config is applying --- subiquity/controllers/keyboard.py | 6 ++- subiquity/models/keyboard.py | 2 + subiquity/ui/spinner.py | 54 +++++++++++++++++++++++++++ subiquity/ui/views/installprogress.py | 25 +------------ subiquity/ui/views/keyboard.py | 18 +++++++++ subiquitycore/view.py | 9 ++++- 6 files changed, 88 insertions(+), 26 deletions(-) create mode 100644 subiquity/ui/spinner.py diff --git a/subiquity/controllers/keyboard.py b/subiquity/controllers/keyboard.py index cc02be80..c8e8d95e 100644 --- a/subiquity/controllers/keyboard.py +++ b/subiquity/controllers/keyboard.py @@ -60,7 +60,11 @@ class KeyboardController(BaseController): self.done(layout, variant) def done(self, layout, variant): - self.model.set_keyboard(layout, variant) + self.run_in_bg( + lambda: self.model.set_keyboard(layout, variant), + self._done) + + def _done(self, fut): self.signal.emit_signal('next-screen') def cancel(self): diff --git a/subiquity/models/keyboard.py b/subiquity/models/keyboard.py index c4e8397e..ab5b974e 100644 --- a/subiquity/models/keyboard.py +++ b/subiquity/models/keyboard.py @@ -101,3 +101,5 @@ class KeyboardModel: fp.write(self.config_content) if self.root == '/': run_command(['setupcon', '--save', '--force']) + else: + run_command(['sleep', '1']) diff --git a/subiquity/ui/spinner.py b/subiquity/ui/spinner.py new file mode 100644 index 00000000..4ec747fb --- /dev/null +++ b/subiquity/ui/spinner.py @@ -0,0 +1,54 @@ +# Copyright 2017 Canonical, Ltd. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from urwid import ( + Text, + ) + +styles = { + 'dots': { + 'texts': [t.replace('*', '\N{bullet}') for t in ['|*----|', '|-*---|', '|--*--|', '|---*-|', '|----*|', '|---*-|', '|--*--|', '|-*---|']], + 'rate': 0.2, + }, + 'spin': { + 'texts': ['-', '\\', '|', '/'], + 'rate': 0.1, + }, + } + +class Spinner(Text): + def __init__(self, loop, style='spin', align='center'): + self.loop = loop + self.spin_index = 0 + self.spin_text = styles[style]['texts'] + self.rate = styles[style]['rate'] + super().__init__('', align=align) + self.handle = None + + def _advance(self, sender=None, user_data=None): + self.spin_index = (self.spin_index + 1)%len(self.spin_text) + self.set_text(self.spin_text[self.spin_index]) + self.handle = self.loop.set_alarm_in(self.rate, self._advance) + + def start(self): + self.stop() + self._advance() + + def stop(self): + self.set_text('') + if self.handle is not None: + self.loop.remove_alarm(self.handle) + self.handle = None + diff --git a/subiquity/ui/views/installprogress.py b/subiquity/ui/views/installprogress.py index eb7bf642..61b2ae1b 100644 --- a/subiquity/ui/views/installprogress.py +++ b/subiquity/ui/views/installprogress.py @@ -25,6 +25,8 @@ from subiquitycore.ui.buttons import cancel_btn, ok_btn, other_btn from subiquitycore.ui.container import Columns, ListBox, Pile from subiquitycore.ui.utils import button_pile, Padding +from subiquity.ui.spinner import Spinner + log = logging.getLogger("subiquity.views.installprogress") class MyLineBox(LineBox): @@ -34,29 +36,6 @@ class MyLineBox(LineBox): else: return "" -class Spinner(Text): - def __init__(self, loop): - self.loop = loop - self.spin_index = 0 - self.spin_text = r'-\|/' - super().__init__('') - self.handle = None - - def _advance(self, sender=None, user_data=None): - self.spin_index = (self.spin_index + 1)%len(self.spin_text) - self.set_text(self.spin_text[self.spin_index]) - self.handle = self.loop.set_alarm_in(0.1, self._advance) - - def start(self): - self.stop() - self._advance() - - def stop(self): - self.set_text('') - if self.handle is not None: - self.loop.remove_alarm(self.handle) - self.handle = None - class ProgressView(BaseView): def __init__(self, controller): diff --git a/subiquity/ui/views/keyboard.py b/subiquity/ui/views/keyboard.py index f27819b1..94bde1c4 100644 --- a/subiquity/ui/views/keyboard.py +++ b/subiquity/ui/views/keyboard.py @@ -36,6 +36,7 @@ from subiquitycore.ui.selector import Option, Selector from subiquitycore.ui.utils import button_pile, Color, Padding from subiquitycore.view import BaseView +from subiquity.ui.spinner import Spinner from subiquity.ui.views import pc105 log = logging.getLogger("subiquity.ui.views.keyboard") @@ -249,6 +250,21 @@ class Detector: self.overlay.start() self.keyboard_view.show_overlay(self.overlay) +class ApplyingConfig(WidgetWrap): + def __init__(self, loop): + spinner = Spinner(loop, style='dots') + spinner.start() + text = _("Applying config") + # | text | + # 12 34 + self.width = len(text) + 4 + super().__init__( + LineBox( + Pile([ + ('pack', Text(' ' + text)), + ('pack', spinner), + ]))) + class ChoiceField(FormField): @@ -333,6 +349,8 @@ class KeyboardView(BaseView): variant = '' if self.form.variant.widget.value is not None: variant = self.form.variant.widget.value + ac = ApplyingConfig(self.controller.loop) + self.show_overlay(ac, width=ac.width, min_width=None) self.controller.done(layout, variant) def cancel(self, result=None): diff --git a/subiquitycore/view.py b/subiquitycore/view.py index 949643ec..c8b4f11a 100644 --- a/subiquitycore/view.py +++ b/subiquitycore/view.py @@ -36,13 +36,18 @@ class BaseView(WidgetWrap): valign='middle', height='pack' ) + PADDING = 3 + # Don't expect callers to account for the padding if they pass a fixed width. + if 'width' in kw: + if isinstance(kw['width'], int): + kw['width'] += 2*PADDING args.update(kw) top = Pile([ ('pack', Text("")), Columns([ - (3, Text("")), + (PADDING, Text("")), overlay_widget, - (3, Text("")) + (PADDING, Text("")) ]), ('pack', Text("")), ]) From 067b63b79d50607cb6d88e1945ee3c6467a4a89c Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 13 Mar 2018 20:56:41 +1300 Subject: [PATCH 2/3] run subiquity-loadkeys after setupcon to restore shift tab behaviour --- subiquity/models/keyboard.py | 1 + 1 file changed, 1 insertion(+) diff --git a/subiquity/models/keyboard.py b/subiquity/models/keyboard.py index ab5b974e..854b671a 100644 --- a/subiquity/models/keyboard.py +++ b/subiquity/models/keyboard.py @@ -101,5 +101,6 @@ class KeyboardModel: fp.write(self.config_content) if self.root == '/': run_command(['setupcon', '--save', '--force']) + run_command(['subiquity.subiquity-loadkeys']) else: run_command(['sleep', '1']) From bafef447506b836ae1cfc4366cb96c7b72b149cb Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 13 Mar 2018 21:28:58 +1300 Subject: [PATCH 3/3] /snap/bin is apparently not on PATH for subiquity... --- subiquity/models/keyboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subiquity/models/keyboard.py b/subiquity/models/keyboard.py index 854b671a..46ae3e0a 100644 --- a/subiquity/models/keyboard.py +++ b/subiquity/models/keyboard.py @@ -101,6 +101,6 @@ class KeyboardModel: fp.write(self.config_content) if self.root == '/': run_command(['setupcon', '--save', '--force']) - run_command(['subiquity.subiquity-loadkeys']) + run_command(['/snap/bin/subiquity.subiquity-loadkeys']) else: run_command(['sleep', '1'])