move checking if a layout needs a toggle to server side

subiquity inherits this behavior from d-i where if a the user selects a
layout that does not allow typing latin characters, the user is prompted
to choose a key to toggle between the one they selected and a related
one that does allow latin characters. This change moves the handling of
this to the server side, so the client just sees the keyboard layout the
user selects, and calls an API method to know if to ask the user about a
toggle key.
This commit is contained in:
Michael Hudson-Doyle 2021-03-16 12:30:18 +13:00
parent 7d98a77434
commit 744e53b76b
5 changed files with 105 additions and 96 deletions

View File

@ -68,6 +68,10 @@ class KeyboardController(SubiquityTuiController):
async def get_step(self, index):
return await self.endpoint.steps.GET(index)
async def needs_toggle(self, setting):
return await self.endpoint.needs_toggle.GET(
layout_code=setting.layout, variant_code=setting.variant)
def done(self, setting, apply):
log.debug("KeyboardController.done %s next_screen", setting)
if apply:

View File

@ -18,95 +18,9 @@ import os
from subiquity.common.serialize import Serializer
from subiquity.common.types import (
KeyboardLayout,
KeyboardSetting,
)
# Non-latin keyboard layouts that are handled in a uniform way
standard_non_latin_layouts = set(
('af', 'am', 'ara', 'ben', 'bd', 'bg', 'bt', 'by', 'et', 'ge',
'gh', 'gr', 'guj', 'guru', 'il', 'in', 'iq', 'ir', 'iku', 'kan',
'kh', 'kz', 'la', 'lao', 'lk', 'kg', 'ma', 'mk', 'mm', 'mn', 'mv',
'mal', 'np', 'ori', 'pk', 'ru', 'scc', 'sy', 'syr', 'tel', 'th',
'tj', 'tam', 'tib', 'ua', 'ug', 'uz')
)
def latinizable(setting):
"""
If this setting does not allow the typing of latin characters,
return a setting that can be switched to one that can.
"""
if setting.layout == 'rs':
if setting.variant.startswith('latin'):
return setting
else:
if setting.variant == 'yz':
new_variant = 'latinyz'
elif setting.variant == 'alternatequotes':
new_variant = 'latinalternatequotes'
else:
new_variant = 'latin'
return KeyboardSetting(layout='rs,rs',
variant=(new_variant +
',' + setting.variant))
elif setting.layout == 'jp':
if setting.variant in ('106', 'common', 'OADG109A',
'nicola_f_bs', ''):
return setting
else:
return KeyboardSetting(layout='jp,jp',
variant=',' + setting.variant)
elif setting.layout == 'lt':
if setting.variant == 'us':
return KeyboardSetting(layout='lt,lt', variant='us,')
else:
return KeyboardSetting(layout='lt,lt',
variant=setting.variant + ',us')
elif setting.layout == 'me':
if setting.variant == 'basic' or setting.variant.startswith('latin'):
return setting
else:
return KeyboardSetting(layout='me,me',
variant=setting.variant + ',us')
elif setting.layout in standard_non_latin_layouts:
return KeyboardSetting(layout='us,' + setting.layout,
variant=',' + setting.variant)
else:
return setting
def for_ui(setting):
"""
Attempt to guess a setting the user chose which resulted in the
current config. Basically the inverse of latinizable().
"""
if ',' in setting.layout:
layout1, layout2 = setting.layout.split(',', 1)
else:
layout1, layout2 = setting.layout, ''
if ',' in setting.variant:
variant1, variant2 = setting.variant.split(',', 1)
else:
variant1, variant2 = setting.variant, ''
if setting.layout == 'lt,lt':
layout = layout1
variant = variant1
elif setting.layout in ('rs,rs', 'us,rs', 'jp,jp', 'us,jp'):
layout = layout2
variant = variant2
elif layout1 == 'us' and layout2 in standard_non_latin_layouts:
layout = layout2
variant = variant2
elif ',' in setting.layout:
# Something unrecognized
layout = 'us'
variant = ''
else:
return setting
return KeyboardSetting(layout=layout, variant=variant)
class KeyboardList:
def __init__(self):

View File

@ -94,6 +94,9 @@ class API:
def GET() -> KeyboardSetting: ...
def POST(data: Payload[KeyboardSetting]): ...
class needs_toggle:
def GET(layout_code: str, variant_code: str) -> bool: ...
class steps:
def GET(index: Optional[str]) -> AnyStep: ...

View File

@ -33,6 +33,85 @@ from subiquity.server.controller import SubiquityController
log = logging.getLogger('subiquity.server.controllers.keyboard')
# Non-latin keyboard layouts that are handled in a uniform way
standard_non_latin_layouts = set(
('af', 'am', 'ara', 'ben', 'bd', 'bg', 'bt', 'by', 'et', 'ge',
'gh', 'gr', 'guj', 'guru', 'il', 'in', 'iq', 'ir', 'iku', 'kan',
'kh', 'kz', 'la', 'lao', 'lk', 'kg', 'ma', 'mk', 'mm', 'mn', 'mv',
'mal', 'np', 'ori', 'pk', 'ru', 'scc', 'sy', 'syr', 'tel', 'th',
'tj', 'tam', 'tib', 'ua', 'ug', 'uz')
)
def latinizable(layout_code, variant_code):
"""
If this setting does not allow the typing of latin characters,
return a setting that can be switched to one that can.
"""
if layout_code == 'rs':
if variant_code.startswith('latin'):
return None
else:
if variant_code == 'yz':
new_variant_code = 'latinyz'
elif variant_code == 'alternatequotes':
new_variant_code = 'latinalternatequotes'
else:
new_variant_code = 'latin'
return 'rs,rs', new_variant_code + ',' + variant_code
elif layout_code == 'jp':
if variant_code in ('106', 'common', 'OADG109A', 'nicola_f_bs', ''):
return None
else:
return 'jp,jp', ',' + variant_code
elif layout_code == 'lt':
if variant_code == 'us':
return 'lt,lt', 'us,'
else:
return 'lt,lt', variant_code + ',us'
elif layout_code == 'me':
if variant_code == 'basic' or variant_code.startswith('latin'):
return None
else:
return 'me,me', variant_code + ',us'
elif layout_code in standard_non_latin_layouts:
return 'us,' + layout_code, ',' + variant_code
else:
return None
def for_ui(setting):
"""
Attempt to guess a setting the user chose which resulted in the
current config. Basically the inverse of latinizable().
"""
if ',' in setting.layout:
layout1, layout2 = setting.layout.split(',', 1)
else:
layout1, layout2 = setting.layout, ''
if ',' in setting.variant:
variant1, variant2 = setting.variant.split(',', 1)
else:
variant1, variant2 = setting.variant, ''
if setting.layout == 'lt,lt':
layout = layout1
variant = variant1
elif setting.layout in ('rs,rs', 'us,rs', 'jp,jp', 'us,jp'):
layout = layout2
variant = variant2
elif layout1 == 'us' and layout2 in standard_non_latin_layouts:
layout = layout2
variant = variant2
elif ',' in setting.layout:
# Something unrecognized
layout = 'us'
variant = ''
else:
return setting
return KeyboardSetting(
layout=layout, variant=variant, toggle=setting.toggle)
class KeyboardController(SubiquityController):
endpoint = API.keyboard
@ -74,12 +153,19 @@ class KeyboardController(SubiquityController):
return attr.asdict(self.model.setting)
async def GET(self) -> KeyboardSetting:
return self.model.setting
return for_ui(self.model.setting)
async def POST(self, data: KeyboardSetting):
new = latinizable(data.layout, data.variant)
if new is not None:
data = KeyboardSetting(new[0], new[1], data.toggle)
self.model.setting = data
self.configured()
async def needs_toggle_GET(self, layout_code: str,
variant_code: str) -> bool:
return latinizable(layout_code, variant_code) is not None
async def steps_GET(self, index: Optional[str]) -> AnyStep:
if self.pc105_steps is None:
path = os.path.join(self._kbds_dir, 'pc105.json')

View File

@ -45,7 +45,6 @@ from subiquitycore.ui.stretchy import (
from subiquitycore.ui.utils import button_pile, Color, Padding, screen
from subiquitycore.view import BaseView
from subiquity.client.keyboard import for_ui, latinizable
from subiquity.common.types import (
KeyboardSetting,
StepKeyPresent,
@ -378,10 +377,10 @@ class KeyboardView(BaseView):
title = _("Keyboard configuration")
def __init__(self, controller, initial_setting):
def __init__(self, controller, setting):
self.controller = controller
self.keyboard_list = controller.keyboard_list
self.initial_setting = initial_setting
self.initial_setting = setting
self.form = KeyboardForm()
opts = []
@ -392,7 +391,6 @@ class KeyboardView(BaseView):
connect_signal(self.form, 'cancel', self.cancel)
connect_signal(self.form.layout.widget, "select", self.select_layout)
self.form.layout.widget.options = opts
setting = for_ui(initial_setting)
layout, variant = self.lookup(setting.layout, setting.variant)
self.set_values(layout, variant)
@ -427,16 +425,20 @@ class KeyboardView(BaseView):
self.set_values(layout, variant)
self._w.base_widget.focus_position = 4
async def _check_toggle(self, setting):
needs_toggle = await self.controller.app.wait_with_text_dialog(
self.controller.needs_toggle(setting), "...")
if needs_toggle:
self.show_stretchy_overlay(ToggleQuestion(self, setting))
else:
self.really_done(setting)
def done(self, result):
data = result.as_data()
layout = data['layout']
variant = data.get('variant', layout.variants[0])
setting = KeyboardSetting(layout=layout.code, variant=variant.code)
other = latinizable(setting)
if setting != other:
self.show_stretchy_overlay(ToggleQuestion(self, other))
else:
self.really_done(setting)
self.controller.app.aio_loop.create_task(self._check_toggle(setting))
def really_done(self, setting):
apply = False