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): async def get_step(self, index):
return await self.endpoint.steps.GET(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): def done(self, setting, apply):
log.debug("KeyboardController.done %s next_screen", setting) log.debug("KeyboardController.done %s next_screen", setting)
if apply: if apply:

View File

@ -18,95 +18,9 @@ import os
from subiquity.common.serialize import Serializer from subiquity.common.serialize import Serializer
from subiquity.common.types import ( from subiquity.common.types import (
KeyboardLayout, 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: class KeyboardList:
def __init__(self): def __init__(self):

View File

@ -94,6 +94,9 @@ class API:
def GET() -> KeyboardSetting: ... def GET() -> KeyboardSetting: ...
def POST(data: Payload[KeyboardSetting]): ... def POST(data: Payload[KeyboardSetting]): ...
class needs_toggle:
def GET(layout_code: str, variant_code: str) -> bool: ...
class steps: class steps:
def GET(index: Optional[str]) -> AnyStep: ... 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') 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): class KeyboardController(SubiquityController):
endpoint = API.keyboard endpoint = API.keyboard
@ -74,12 +153,19 @@ class KeyboardController(SubiquityController):
return attr.asdict(self.model.setting) return attr.asdict(self.model.setting)
async def GET(self) -> KeyboardSetting: async def GET(self) -> KeyboardSetting:
return self.model.setting return for_ui(self.model.setting)
async def POST(self, data: KeyboardSetting): 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.model.setting = data
self.configured() 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: async def steps_GET(self, index: Optional[str]) -> AnyStep:
if self.pc105_steps is None: if self.pc105_steps is None:
path = os.path.join(self._kbds_dir, 'pc105.json') 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.ui.utils import button_pile, Color, Padding, screen
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
from subiquity.client.keyboard import for_ui, latinizable
from subiquity.common.types import ( from subiquity.common.types import (
KeyboardSetting, KeyboardSetting,
StepKeyPresent, StepKeyPresent,
@ -378,10 +377,10 @@ class KeyboardView(BaseView):
title = _("Keyboard configuration") title = _("Keyboard configuration")
def __init__(self, controller, initial_setting): def __init__(self, controller, setting):
self.controller = controller self.controller = controller
self.keyboard_list = controller.keyboard_list self.keyboard_list = controller.keyboard_list
self.initial_setting = initial_setting self.initial_setting = setting
self.form = KeyboardForm() self.form = KeyboardForm()
opts = [] opts = []
@ -392,7 +391,6 @@ class KeyboardView(BaseView):
connect_signal(self.form, 'cancel', self.cancel) connect_signal(self.form, 'cancel', self.cancel)
connect_signal(self.form.layout.widget, "select", self.select_layout) connect_signal(self.form.layout.widget, "select", self.select_layout)
self.form.layout.widget.options = opts self.form.layout.widget.options = opts
setting = for_ui(initial_setting)
layout, variant = self.lookup(setting.layout, setting.variant) layout, variant = self.lookup(setting.layout, setting.variant)
self.set_values(layout, variant) self.set_values(layout, variant)
@ -427,16 +425,20 @@ class KeyboardView(BaseView):
self.set_values(layout, variant) self.set_values(layout, variant)
self._w.base_widget.focus_position = 4 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): def done(self, result):
data = result.as_data() data = result.as_data()
layout = data['layout'] layout = data['layout']
variant = data.get('variant', layout.variants[0]) variant = data.get('variant', layout.variants[0])
setting = KeyboardSetting(layout=layout.code, variant=variant.code) setting = KeyboardSetting(layout=layout.code, variant=variant.code)
other = latinizable(setting) self.controller.app.aio_loop.create_task(self._check_toggle(setting))
if setting != other:
self.show_stretchy_overlay(ToggleQuestion(self, other))
else:
self.really_done(setting)
def really_done(self, setting): def really_done(self, setting):
apply = False apply = False