ui: redraw screens after moving from one screen to another
Wieh urwid > 2.1.2, the screen is only redrawn after urwid handles an event (e.g., keypress, resize, ...) or an urwid alarm (it is like a timer). All other changes made to the UI do not trigger a screen redraw. We now redraw the screen properly after moving from one screen to another. Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
parent
eca86c58da
commit
020dcc0b88
|
@ -270,10 +270,10 @@ class ExampleController(SubiquityTuiController):
|
|||
return ExampleView(self, thing)
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self, thing):
|
||||
self.app.next_screen(self.endpoint.POST(thing))
|
||||
self.app.request_next_screen(self.endpoint.POST(thing))
|
||||
```
|
||||
|
||||
Setting `endpoint_name` means that self.client gets set to an implementation of
|
||||
|
|
|
@ -70,7 +70,7 @@ class RecoveryChooserController(RecoveryChooserBaseController):
|
|||
|
||||
def select(self, system, action):
|
||||
self.model.select(system, action)
|
||||
self.app.next_screen()
|
||||
self.app.request_next_screen()
|
||||
|
||||
def more_options(self):
|
||||
self._current_view = self._all_view
|
||||
|
@ -96,4 +96,4 @@ class RecoveryChooserConfirmController(RecoveryChooserBaseController):
|
|||
|
||||
def back(self):
|
||||
self.model.unselect()
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
|
|
@ -74,7 +74,7 @@ class TestChooserConfirmController(unittest.TestCase):
|
|||
c.back()
|
||||
app.respond.assert_not_called()
|
||||
app.exit.assert_not_called()
|
||||
app.prev_screen.assert_called()
|
||||
app.request_prev_screen.assert_called()
|
||||
c.model.unselect.assert_called()
|
||||
|
||||
def test_confirm(self):
|
||||
|
@ -106,7 +106,7 @@ class TestChooserController(unittest.TestCase):
|
|||
)
|
||||
self.assertEqual(c.model.selection, exp)
|
||||
|
||||
app.next_screen.assert_called()
|
||||
app.request_next_screen.assert_called()
|
||||
app.respond.assert_not_called()
|
||||
app.exit.assert_not_called()
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class WelcomeController(TuiController):
|
|||
return self.welcome_view(self)
|
||||
|
||||
def done(self):
|
||||
self.app.next_screen()
|
||||
self.app.request_next_screen()
|
||||
|
||||
def cancel(self):
|
||||
# Can't go back from here!
|
||||
|
|
|
@ -483,7 +483,7 @@ class SubiquityClient(TuiApplication):
|
|||
self._remove_last_screen()
|
||||
super().exit()
|
||||
|
||||
def select_initial_screen(self):
|
||||
async def select_initial_screen(self):
|
||||
last_screen = None
|
||||
if self.updated:
|
||||
state_path = self.state_path("last-screen")
|
||||
|
@ -495,7 +495,7 @@ class SubiquityClient(TuiApplication):
|
|||
for i, controller in enumerate(self.controllers.instances):
|
||||
if controller.name == last_screen:
|
||||
index = i
|
||||
run_bg_task(self._select_initial_screen(index))
|
||||
await self._select_initial_screen(index)
|
||||
|
||||
async def _select_initial_screen(self, index):
|
||||
endpoint_names = []
|
||||
|
@ -507,7 +507,7 @@ class SubiquityClient(TuiApplication):
|
|||
if self.variant:
|
||||
await self.client.meta.client_variant.POST(self.variant)
|
||||
self.controllers.index = index - 1
|
||||
self.next_screen()
|
||||
await self.next_screen()
|
||||
|
||||
async def move_screen(self, increment, coro):
|
||||
try:
|
||||
|
|
|
@ -62,8 +62,10 @@ class DriversController(SubiquityTuiController):
|
|||
click(view.form.done_btn.base_widget)
|
||||
|
||||
def cancel(self) -> None:
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self, install: bool) -> None:
|
||||
log.debug("DriversController.done next_screen install=%s", install)
|
||||
self.app.next_screen(self.endpoint.POST(DriversPayload(install=install)))
|
||||
self.app.request_next_screen(
|
||||
self.endpoint.POST(DriversPayload(install=install))
|
||||
)
|
||||
|
|
|
@ -260,7 +260,7 @@ class FilesystemController(SubiquityTuiController, FilesystemManipulator):
|
|||
async def _guided_choice(self, choice: GuidedChoiceV2):
|
||||
coro = self.endpoint.guided.POST(choice)
|
||||
if not choice.capability.supports_manual_customization():
|
||||
self.app.next_screen(coro)
|
||||
await self.app.next_screen(coro)
|
||||
return
|
||||
status = await self.app.wait_with_progress(coro)
|
||||
self.model = FilesystemModel(status.bootloader, root="/")
|
||||
|
@ -294,11 +294,11 @@ class FilesystemController(SubiquityTuiController, FilesystemManipulator):
|
|||
self.ui.set_body(FilesystemView(self.model, self))
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def finish(self):
|
||||
log.debug("FilesystemController.finish next_screen")
|
||||
self.app.next_screen(
|
||||
self.app.request_next_screen(
|
||||
self.endpoint.POST(
|
||||
self.model._render_actions(mode=ActionRenderMode.FOR_API_CLIENT)
|
||||
)
|
||||
|
|
|
@ -43,11 +43,11 @@ class IdentityController(SubiquityTuiController):
|
|||
self.done(identity)
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self, identity_data):
|
||||
log.debug("IdentityController.done next_screen user_spec=%s", identity_data)
|
||||
self.app.next_screen(self.endpoint.POST(identity_data))
|
||||
self.app.request_next_screen(self.endpoint.POST(identity_data))
|
||||
|
||||
async def validate_username(self, username):
|
||||
return await self.endpoint.validate_username.GET(username)
|
||||
|
|
|
@ -49,7 +49,7 @@ class KeyboardController(SubiquityTuiController):
|
|||
await self.endpoint.POST(setting)
|
||||
|
||||
def done(self):
|
||||
self.app.next_screen()
|
||||
self.app.request_next_screen()
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
|
|
@ -67,8 +67,8 @@ class MirrorController(SubiquityTuiController):
|
|||
self.app.ui.body.form._click_done(None)
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self, mirror):
|
||||
log.debug("MirrorController.done next_screen mirror=%s", mirror)
|
||||
self.app.next_screen(self.endpoint.POST(MirrorPost(elected=mirror)))
|
||||
self.app.request_next_screen(self.endpoint.POST(MirrorPost(elected=mirror)))
|
||||
|
|
|
@ -118,10 +118,10 @@ class NetworkController(SubiquityTuiController, NetworkAnswersMixin):
|
|||
run_bg_task(self.unsubscribe())
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self):
|
||||
self.app.next_screen(self.endpoint.POST())
|
||||
self.app.request_next_screen(self.endpoint.POST())
|
||||
|
||||
def set_static_config(
|
||||
self, dev_name: str, ip_version: int, static_config: StaticConfig
|
||||
|
|
|
@ -33,8 +33,8 @@ class ProxyController(SubiquityTuiController):
|
|||
self.done(self.answers["proxy"])
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self, proxy):
|
||||
log.debug("ProxyController.done next_screen proxy=%s", proxy)
|
||||
self.app.next_screen(self.endpoint.POST(proxy))
|
||||
self.app.request_next_screen(self.endpoint.POST(proxy))
|
||||
|
|
|
@ -77,7 +77,7 @@ class RefreshController(SubiquityTuiController):
|
|||
|
||||
def done(self, sender=None):
|
||||
log.debug("RefreshController.done next_screen")
|
||||
self.app.next_screen()
|
||||
self.app.request_next_screen()
|
||||
|
||||
def cancel(self, sender=None):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
|
|
@ -39,7 +39,7 @@ class SerialController(SubiquityTuiController):
|
|||
def done(self, rich):
|
||||
log.debug("SerialController.done rich %s next_screen", rich)
|
||||
self.app.set_rich(rich)
|
||||
self.app.next_screen()
|
||||
self.app.request_next_screen()
|
||||
|
||||
def cancel(self):
|
||||
# Can't go back from here!
|
||||
|
|
|
@ -47,10 +47,10 @@ class SnapListController(SubiquityTuiController):
|
|||
|
||||
def done(self, selections: List[SnapSelection]):
|
||||
log.debug("SnapListController.done next_screen snaps_to_install=%s", selections)
|
||||
self.app.next_screen(self.endpoint.POST(selections))
|
||||
self.app.request_next_screen(self.endpoint.POST(selections))
|
||||
|
||||
def cancel(self, sender=None):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
async def get_list_wait(self):
|
||||
return await self.endpoint.GET(wait=True)
|
||||
|
|
|
@ -43,7 +43,7 @@ class SourceController(SubiquityTuiController):
|
|||
form._click_done(None)
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self, source_id, search_drivers: bool):
|
||||
log.debug(
|
||||
|
@ -51,4 +51,4 @@ class SourceController(SubiquityTuiController):
|
|||
source_id,
|
||||
search_drivers,
|
||||
)
|
||||
self.app.next_screen(self.endpoint.POST(source_id, search_drivers))
|
||||
self.app.request_next_screen(self.endpoint.POST(source_id, search_drivers))
|
||||
|
|
|
@ -84,7 +84,7 @@ class SSHController(SubiquityTuiController):
|
|||
form._click_done(None)
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def _fetch_cancel(self):
|
||||
if self._fetch_task is None:
|
||||
|
@ -123,4 +123,4 @@ class SSHController(SubiquityTuiController):
|
|||
|
||||
def done(self, result):
|
||||
log.debug("SSHController.done next_screen result=%s", result)
|
||||
self.app.next_screen(self.endpoint.POST(result))
|
||||
self.app.request_next_screen(self.endpoint.POST(result))
|
||||
|
|
|
@ -216,13 +216,13 @@ class UbuntuProController(SubiquityTuiController):
|
|||
schedule_task(inner())
|
||||
|
||||
def cancel(self) -> None:
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self, token: str) -> None:
|
||||
"""Submit the token and move on to the next screen."""
|
||||
self.app.next_screen(self.endpoint.POST(UbuntuProInfo(token=token)))
|
||||
self.app.request_next_screen(self.endpoint.POST(UbuntuProInfo(token=token)))
|
||||
|
||||
def next_screen(self) -> None:
|
||||
"""Move on to the next screen. Assume the token should not be
|
||||
submitted (or has already been submitted)."""
|
||||
self.app.next_screen()
|
||||
self.app.request_next_screen()
|
||||
|
|
|
@ -48,10 +48,10 @@ class WelcomeController(SubiquityTuiController):
|
|||
log.debug("WelcomeController.done %s next_screen", code)
|
||||
i18n.switch_language(code)
|
||||
self.app.native_language = display_name
|
||||
self.app.next_screen(self.endpoint.POST(code))
|
||||
self.app.request_next_screen(self.endpoint.POST(code))
|
||||
|
||||
def cancel(self, sender=None):
|
||||
if not self.serial:
|
||||
# Can't go back from here unless we're on serial!
|
||||
pass
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
|
|
@ -33,11 +33,11 @@ class ZdevController(SubiquityTuiController):
|
|||
self.done()
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
||||
def done(self):
|
||||
# switch to next screen
|
||||
self.app.next_screen()
|
||||
self.app.request_next_screen()
|
||||
|
||||
async def chzdev(self, action, zdevinfo):
|
||||
return await self.endpoint.chzdev.POST(action, zdevinfo)
|
||||
|
|
|
@ -296,7 +296,7 @@ class InstallConfirmation(Stretchy):
|
|||
if self.app.controllers.Progress.showing:
|
||||
run_bg_task(self.app.confirm_install())
|
||||
else:
|
||||
self.app.next_screen(self.app.confirm_install())
|
||||
self.app.request_next_screen(self.app.confirm_install())
|
||||
|
||||
def cancel(self, sender):
|
||||
self.app.remove_global_overlay(self)
|
||||
|
|
|
@ -663,7 +663,7 @@ class NetworkController(BaseNetworkController, TuiController, NetworkAnswersMixi
|
|||
def done(self):
|
||||
log.debug("NetworkController.done next_screen")
|
||||
self.model.has_network = self.network_event_receiver.has_default_route
|
||||
self.app.next_screen()
|
||||
self.app.request_next_screen()
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
|
|
|
@ -41,8 +41,8 @@ def make_app(model=None):
|
|||
app.context = Context.new(app)
|
||||
app.exit = mock.Mock()
|
||||
app.respond = mock.Mock()
|
||||
app.next_screen = mock.Mock()
|
||||
app.prev_screen = mock.Mock()
|
||||
app.request_next_screen = mock.Mock()
|
||||
app.request_prev_screen = mock.Mock()
|
||||
app.hub = MessageHub()
|
||||
app.opts = mock.Mock()
|
||||
app.opts.dry_run = True
|
||||
|
|
|
@ -156,7 +156,7 @@ class TuiApplication(Application):
|
|||
self.ui.block_input = False
|
||||
nonlocal min_show_task
|
||||
min_show_task = asyncio.create_task(asyncio.sleep(MIN_SHOW_PROGRESS_TIME))
|
||||
show()
|
||||
await show()
|
||||
|
||||
self.ui.block_input = True
|
||||
show_task = asyncio.create_task(_show())
|
||||
|
@ -166,7 +166,7 @@ class TuiApplication(Application):
|
|||
if min_show_task:
|
||||
await min_show_task
|
||||
if hide is not None:
|
||||
hide()
|
||||
await hide()
|
||||
else:
|
||||
self.ui.block_input = False
|
||||
show_task.cancel()
|
||||
|
@ -191,18 +191,24 @@ class TuiApplication(Application):
|
|||
else:
|
||||
task_to_cancel = None
|
||||
|
||||
def show_load():
|
||||
async def show_load():
|
||||
nonlocal ld
|
||||
ld = LoadingDialog(self.ui.body, message, task_to_cancel)
|
||||
self.ui.body.show_overlay(ld, width=ld.width)
|
||||
await self.redraw_screen()
|
||||
|
||||
def hide_load():
|
||||
async def hide_load():
|
||||
ld.close()
|
||||
await self.redraw_screen()
|
||||
|
||||
return await self._wait_with_indication(awaitable, show_load, hide_load)
|
||||
|
||||
async def wait_with_progress(self, awaitable):
|
||||
return await self._wait_with_indication(awaitable, self.show_progress)
|
||||
async def show_progress():
|
||||
self.show_progress()
|
||||
await self.redraw_screen()
|
||||
|
||||
return await self._wait_with_indication(awaitable, show_progress)
|
||||
|
||||
async def _move_screen(
|
||||
self, increment, coro
|
||||
|
@ -243,14 +249,36 @@ class TuiApplication(Application):
|
|||
view = view_or_callable
|
||||
self.ui.set_body(view)
|
||||
|
||||
def next_screen(self, coro=None):
|
||||
run_bg_task(self.move_screen(1, coro))
|
||||
async def redraw_screen(self):
|
||||
self.urwid_loop.draw_screen()
|
||||
|
||||
def prev_screen(self):
|
||||
run_bg_task(self.move_screen(-1, None))
|
||||
async def next_screen(self, coro=None):
|
||||
await self.move_screen(1, coro)
|
||||
|
||||
def select_initial_screen(self):
|
||||
self.next_screen()
|
||||
async def prev_screen(self):
|
||||
await self.move_screen(-1, None)
|
||||
|
||||
async def select_initial_screen(self):
|
||||
await self.next_screen()
|
||||
|
||||
def request_next_screen(self, coro=None, *, redraw=True):
|
||||
async def next_screen():
|
||||
await self.next_screen(coro)
|
||||
if redraw:
|
||||
await self.redraw_screen()
|
||||
|
||||
run_bg_task(next_screen())
|
||||
|
||||
def request_prev_screen(self, *, redraw=True):
|
||||
async def prev_screen():
|
||||
await self.prev_screen()
|
||||
if redraw:
|
||||
await self.redraw_screen()
|
||||
|
||||
run_bg_task(prev_screen())
|
||||
|
||||
def request_screen_redraw(self):
|
||||
run_bg_task(self.redraw_screen())
|
||||
|
||||
def set_rich(self, rich):
|
||||
if rich == self.rich_mode:
|
||||
|
@ -321,7 +349,7 @@ class TuiApplication(Application):
|
|||
# By default, basic on serial - rich otherwise.
|
||||
return not self.opts.run_on_serial
|
||||
|
||||
def start_urwid(self, input=None, output=None):
|
||||
async def start_urwid(self, input=None, output=None):
|
||||
# This stops the tcsetpgrp call in run_command_in_foreground from
|
||||
# suspending us. See the rant there for more details.
|
||||
signal.signal(signal.SIGTTOU, signal.SIG_IGN)
|
||||
|
@ -339,12 +367,13 @@ class TuiApplication(Application):
|
|||
extend_dec_special_charmap()
|
||||
self.set_rich(self.get_initial_rich_mode())
|
||||
self.urwid_loop.start()
|
||||
self.select_initial_screen()
|
||||
await self.select_initial_screen()
|
||||
await self.redraw_screen()
|
||||
|
||||
async def start(self, start_urwid=True):
|
||||
await super().start()
|
||||
if start_urwid:
|
||||
self.start_urwid()
|
||||
await self.start_urwid()
|
||||
|
||||
async def run(self):
|
||||
try:
|
||||
|
|
|
@ -47,7 +47,7 @@ class WSLConfigurationAdvancedController(SubiquityTuiController):
|
|||
"WSLConfigurationAdvancedController.done next_screen user_spec=%s",
|
||||
reconf_data,
|
||||
)
|
||||
self.app.next_screen(self.endpoint.POST(reconf_data))
|
||||
self.app.request_next_screen(self.endpoint.POST(reconf_data))
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
|
|
@ -32,7 +32,7 @@ class WSLConfigurationBaseController(SubiquityTuiController):
|
|||
"WSLConfigurationBaseController.done next_screen user_spec=%s",
|
||||
configuration_data,
|
||||
)
|
||||
self.app.next_screen(self.endpoint.POST(configuration_data))
|
||||
self.app.request_next_screen(self.endpoint.POST(configuration_data))
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
|
|
@ -41,7 +41,7 @@ class WSLSetupOptionsController(SubiquityTuiController):
|
|||
"WSLSetupOptionsController.done next_screen user_spec=%s",
|
||||
configuration_data,
|
||||
)
|
||||
self.app.next_screen(self.endpoint.POST(configuration_data))
|
||||
self.app.request_next_screen(self.endpoint.POST(configuration_data))
|
||||
|
||||
def cancel(self):
|
||||
self.app.prev_screen()
|
||||
self.app.request_prev_screen()
|
||||
|
|
Loading…
Reference in New Issue